feat(attendance): add notification delivery and NFC security foundation
This commit is contained in:
@@ -17,6 +17,8 @@ const preferredLocationSchema = z.object({
|
||||
const hhmmSchema = z.string().regex(/^\d{2}:\d{2}$/, 'Time must use HH:MM format');
|
||||
const isoDateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must use YYYY-MM-DD format');
|
||||
const clockInModeSchema = z.enum(['NFC_REQUIRED', 'GEO_REQUIRED', 'EITHER']);
|
||||
const pushProviderSchema = z.enum(['FCM', 'APNS', 'WEB_PUSH']);
|
||||
const pushPlatformSchema = z.enum(['IOS', 'ANDROID', 'WEB']);
|
||||
|
||||
const shiftPositionSchema = z.object({
|
||||
roleId: z.string().uuid().optional(),
|
||||
@@ -205,6 +207,11 @@ export const staffClockInSchema = z.object({
|
||||
longitude: z.number().min(-180).max(180).optional(),
|
||||
accuracyMeters: z.number().int().nonnegative().optional(),
|
||||
capturedAt: z.string().datetime().optional(),
|
||||
proofNonce: z.string().min(8).max(255).optional(),
|
||||
proofTimestamp: z.string().datetime().optional(),
|
||||
attestationProvider: z.enum(['PLAY_INTEGRITY', 'APP_ATTEST', 'DEVICE_CHECK']).optional(),
|
||||
attestationToken: z.string().min(16).max(20000).optional(),
|
||||
isMockLocation: z.boolean().optional(),
|
||||
notes: z.string().max(2000).optional(),
|
||||
overrideReason: z.string().max(2000).optional(),
|
||||
rawPayload: z.record(z.any()).optional(),
|
||||
@@ -224,6 +231,11 @@ export const staffClockOutSchema = z.object({
|
||||
longitude: z.number().min(-180).max(180).optional(),
|
||||
accuracyMeters: z.number().int().nonnegative().optional(),
|
||||
capturedAt: z.string().datetime().optional(),
|
||||
proofNonce: z.string().min(8).max(255).optional(),
|
||||
proofTimestamp: z.string().datetime().optional(),
|
||||
attestationProvider: z.enum(['PLAY_INTEGRITY', 'APP_ATTEST', 'DEVICE_CHECK']).optional(),
|
||||
attestationToken: z.string().min(16).max(20000).optional(),
|
||||
isMockLocation: z.boolean().optional(),
|
||||
notes: z.string().max(2000).optional(),
|
||||
overrideReason: z.string().max(2000).optional(),
|
||||
breakMinutes: z.number().int().nonnegative().optional(),
|
||||
@@ -253,6 +265,27 @@ export const staffLocationBatchSchema = z.object({
|
||||
message: 'assignmentId or shiftId is required',
|
||||
});
|
||||
|
||||
export const pushTokenRegisterSchema = z.object({
|
||||
provider: pushProviderSchema.default('FCM'),
|
||||
platform: pushPlatformSchema,
|
||||
pushToken: z.string().min(16).max(4096),
|
||||
deviceId: z.string().max(255).optional(),
|
||||
appVersion: z.string().max(80).optional(),
|
||||
appBuild: z.string().max(80).optional(),
|
||||
locale: z.string().max(32).optional(),
|
||||
timezone: z.string().max(64).optional(),
|
||||
notificationsEnabled: z.boolean().optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
});
|
||||
|
||||
export const pushTokenDeleteSchema = z.object({
|
||||
tokenId: z.string().uuid().optional(),
|
||||
pushToken: z.string().min(16).max(4096).optional(),
|
||||
reason: z.string().max(255).optional(),
|
||||
}).refine((value) => value.tokenId || value.pushToken, {
|
||||
message: 'tokenId or pushToken is required',
|
||||
});
|
||||
|
||||
export const staffProfileSetupSchema = z.object({
|
||||
fullName: z.string().min(2).max(160),
|
||||
bio: z.string().max(5000).optional(),
|
||||
|
||||
Reference in New Issue
Block a user