feat(backend): implement v2 domain slice and live smoke
This commit is contained in:
14
backend/command-api/src/contracts/commands/attendance.js
Normal file
14
backend/command-api/src/contracts/commands/attendance.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const attendanceCommandSchema = z.object({
|
||||
assignmentId: z.string().uuid(),
|
||||
sourceType: z.enum(['NFC', 'GEO', 'QR', 'MANUAL', 'SYSTEM']),
|
||||
sourceReference: z.string().max(255).optional(),
|
||||
nfcTagUid: z.string().max(255).optional(),
|
||||
deviceId: z.string().max(255).optional(),
|
||||
latitude: z.number().min(-90).max(90).optional(),
|
||||
longitude: z.number().min(-180).max(180).optional(),
|
||||
accuracyMeters: z.number().int().nonnegative().optional(),
|
||||
capturedAt: z.string().datetime().optional(),
|
||||
rawPayload: z.record(z.any()).optional(),
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const favoriteStaffSchema = z.object({
|
||||
tenantId: z.string().uuid(),
|
||||
businessId: z.string().uuid(),
|
||||
staffId: z.string().uuid(),
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const orderCancelSchema = z.object({
|
||||
orderId: z.string().uuid(),
|
||||
tenantId: z.string().uuid(),
|
||||
reason: z.string().max(1000).optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
});
|
||||
57
backend/command-api/src/contracts/commands/order-create.js
Normal file
57
backend/command-api/src/contracts/commands/order-create.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const roleSchema = z.object({
|
||||
roleCode: z.string().min(1).max(100),
|
||||
roleName: z.string().min(1).max(120),
|
||||
workersNeeded: z.number().int().positive(),
|
||||
payRateCents: z.number().int().nonnegative().optional(),
|
||||
billRateCents: z.number().int().nonnegative().optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
});
|
||||
|
||||
const shiftSchema = z.object({
|
||||
shiftCode: z.string().min(1).max(80),
|
||||
title: z.string().min(1).max(160),
|
||||
status: z.enum([
|
||||
'DRAFT',
|
||||
'OPEN',
|
||||
'PENDING_CONFIRMATION',
|
||||
'ASSIGNED',
|
||||
'ACTIVE',
|
||||
'COMPLETED',
|
||||
'CANCELLED',
|
||||
]).optional(),
|
||||
startsAt: z.string().datetime(),
|
||||
endsAt: z.string().datetime(),
|
||||
timezone: z.string().min(1).max(80).optional(),
|
||||
clockPointId: z.string().uuid().optional(),
|
||||
locationName: z.string().max(160).optional(),
|
||||
locationAddress: z.string().max(300).optional(),
|
||||
latitude: z.number().min(-90).max(90).optional(),
|
||||
longitude: z.number().min(-180).max(180).optional(),
|
||||
geofenceRadiusMeters: z.number().int().positive().optional(),
|
||||
requiredWorkers: z.number().int().positive(),
|
||||
notes: z.string().max(5000).optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
roles: z.array(roleSchema).min(1),
|
||||
});
|
||||
|
||||
export const orderCreateSchema = z.object({
|
||||
tenantId: z.string().uuid(),
|
||||
businessId: z.string().uuid(),
|
||||
vendorId: z.string().uuid().optional(),
|
||||
orderNumber: z.string().min(1).max(80),
|
||||
title: z.string().min(1).max(160),
|
||||
description: z.string().max(5000).optional(),
|
||||
status: z.enum(['DRAFT', 'OPEN', 'FILLED', 'ACTIVE', 'COMPLETED', 'CANCELLED']).optional(),
|
||||
serviceType: z.enum(['EVENT', 'CATERING', 'HOTEL', 'RESTAURANT', 'OTHER']).optional(),
|
||||
startsAt: z.string().datetime().optional(),
|
||||
endsAt: z.string().datetime().optional(),
|
||||
locationName: z.string().max(160).optional(),
|
||||
locationAddress: z.string().max(300).optional(),
|
||||
latitude: z.number().min(-90).max(90).optional(),
|
||||
longitude: z.number().min(-180).max(180).optional(),
|
||||
notes: z.string().max(5000).optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
shifts: z.array(shiftSchema).min(1),
|
||||
});
|
||||
35
backend/command-api/src/contracts/commands/order-update.js
Normal file
35
backend/command-api/src/contracts/commands/order-update.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const nullableString = (max) => z.union([z.string().max(max), z.null()]);
|
||||
const nullableDateTime = z.union([z.string().datetime(), z.null()]);
|
||||
const nullableUuid = z.union([z.string().uuid(), z.null()]);
|
||||
|
||||
const orderUpdateShape = {
|
||||
orderId: z.string().uuid(),
|
||||
tenantId: z.string().uuid(),
|
||||
vendorId: nullableUuid.optional(),
|
||||
title: nullableString(160).optional(),
|
||||
description: nullableString(5000).optional(),
|
||||
status: z.enum(['DRAFT', 'OPEN', 'FILLED', 'ACTIVE', 'COMPLETED']).optional(),
|
||||
serviceType: z.enum(['EVENT', 'CATERING', 'HOTEL', 'RESTAURANT', 'OTHER']).optional(),
|
||||
startsAt: nullableDateTime.optional(),
|
||||
endsAt: nullableDateTime.optional(),
|
||||
locationName: nullableString(160).optional(),
|
||||
locationAddress: nullableString(300).optional(),
|
||||
latitude: z.union([z.number().min(-90).max(90), z.null()]).optional(),
|
||||
longitude: z.union([z.number().min(-180).max(180), z.null()]).optional(),
|
||||
notes: nullableString(5000).optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
};
|
||||
|
||||
export const orderUpdateSchema = z.object(orderUpdateShape).superRefine((value, ctx) => {
|
||||
const mutableKeys = Object.keys(orderUpdateShape).filter((key) => !['orderId', 'tenantId'].includes(key));
|
||||
const hasMutableField = mutableKeys.some((key) => Object.prototype.hasOwnProperty.call(value, key));
|
||||
if (!hasMutableField) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'At least one mutable order field must be provided',
|
||||
path: [],
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const shiftAcceptSchema = z.object({
|
||||
shiftId: z.string().uuid().optional(),
|
||||
shiftRoleId: z.string().uuid(),
|
||||
workforceId: z.string().uuid(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const shiftAssignStaffSchema = z.object({
|
||||
shiftId: z.string().uuid(),
|
||||
tenantId: z.string().uuid(),
|
||||
shiftRoleId: z.string().uuid(),
|
||||
workforceId: z.string().uuid(),
|
||||
applicationId: z.string().uuid().optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const shiftStatusChangeSchema = z.object({
|
||||
shiftId: z.string().uuid(),
|
||||
tenantId: z.string().uuid(),
|
||||
status: z.enum([
|
||||
'DRAFT',
|
||||
'OPEN',
|
||||
'PENDING_CONFIRMATION',
|
||||
'ASSIGNED',
|
||||
'ACTIVE',
|
||||
'COMPLETED',
|
||||
'CANCELLED',
|
||||
]),
|
||||
reason: z.string().max(1000).optional(),
|
||||
metadata: z.record(z.any()).optional(),
|
||||
});
|
||||
11
backend/command-api/src/contracts/commands/staff-review.js
Normal file
11
backend/command-api/src/contracts/commands/staff-review.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const staffReviewSchema = z.object({
|
||||
tenantId: z.string().uuid(),
|
||||
businessId: z.string().uuid(),
|
||||
staffId: z.string().uuid(),
|
||||
assignmentId: z.string().uuid(),
|
||||
rating: z.number().int().min(1).max(5),
|
||||
reviewText: z.string().max(5000).optional(),
|
||||
tags: z.array(z.string().min(1).max(80)).max(20).optional(),
|
||||
});
|
||||
Reference in New Issue
Block a user