feat(camera): add camera management functionality and data flow documentation

- Implemented camera slice in Redux store for managing camera state.
- Added new tables in PostgreSQL for camera devices, lending, and audit logs.
- Created camera-related schemas in contracts for validation.
- Developed camera data flow documentation outlining ingest and read processes.
- Introduced async thunks for fetching, creating, lending, returning, and updating cameras.
This commit is contained in:
marco.chan committed 2026-09-04 12:05:52 +08:00
1 parent 7923ba1b8d
commit d3b6c5032f
11 files changed
+2524 -114

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
import { z } from 'zod';
export const cameraHealthSchema = z.enum(['online', 'offline', 'unknown']);
export const cameraDeviceSchema = z.object({
cameraId: z.string().min(1),
name: z.string().min(1),
location: z.string().min(1),
model: z.string().min(1).nullable(),
notes: z.string().min(1).nullable(),
isActive: z.boolean(),
});
export const cameraDeviceUpdateSchema = z
.object({
name: z.string().min(1).optional(),
location: z.string().min(1).optional(),
model: z.string().min(1).nullable().optional(),
notes: z.string().min(1).nullable().optional(),
isActive: z.boolean().optional(),
})
.refine((value) => Object.keys(value).length > 0, {
message: 'At least one field is required',
});
export const cameraAuditActionSchema = z.enum([
'camera_created',
'camera_lent',
'camera_returned',
'camera_updated',
'camera_activated',
'camera_deactivated',
'camera_soft_deleted',
]);
export const cameraAuditLogSchema = z.object({
id: z.number().int().positive(),
cameraId: z.string().min(1),
action: cameraAuditActionSchema,
actor: z.string().min(1),
metadata: z.record(z.unknown()),
createdAt: z.string().datetime(),
});
export const cameraAuditLogListSchema = z.object({
items: z.array(cameraAuditLogSchema),
});
export const cameraRuntimePayloadSchema = z.object({
fps: z.number().int().nonnegative(),
bitrateKbps: z.number().int().positive(),
recording: z.boolean(),
scene: z.string().min(1),
});
export const cameraLatestStatusSchema = z.object({
cameraId: z.string().min(1),
lastSeen: z.string().datetime().nullable(),
health: cameraHealthSchema,
payload: cameraRuntimePayloadSchema.nullable(),
});
export const cameraLendInfoSchema = z.object({
borrower: z.string().min(1),
dueDate: z.string().datetime(),
purpose: z.string().min(1).optional(),
lentAt: z.string().datetime(),
});
export const cameraListItemSchema = z.object({
cameraId: z.string().min(1),
name: z.string().min(1),
location: z.string().min(1),
model: z.string().min(1).nullable(),
notes: z.string().min(1).nullable(),
isActive: z.boolean(),
latest: cameraLatestStatusSchema,
lend: cameraLendInfoSchema.nullable(),
});
export const cameraListResponseSchema = z.object({
items: z.array(cameraListItemSchema),
});
export const cameraLendRequestSchema = z.object({
borrower: z.string().min(1),
dueDate: z.string().datetime(),
purpose: z.string().min(1).optional(),
});
export const cameraCreateRequestSchema = z.object({
cameraId: z.string().min(1),
name: z.string().min(1),
location: z.string().min(1),
model: z.string().min(1).nullable().optional(),
notes: z.string().min(1).nullable().optional(),
isActive: z.boolean().optional(),
});
export const cameraReturnResponseSchema = z.object({
cameraId: z.string().min(1),
returned: z.boolean(),
});
export const cameraSimulateIngestResponseSchema = z.object({
accepted: z.boolean(),
writes: z.object({
mongo: z.boolean(),
redis: z.boolean(),
postgres: z.boolean(),
}),
latest: cameraLatestStatusSchema,
});
export type CameraHealth = z.infer<typeof cameraHealthSchema>;
export type CameraDevice = z.infer<typeof cameraDeviceSchema>;
export type CameraDeviceUpdate = z.infer<typeof cameraDeviceUpdateSchema>;
export type CameraAuditAction = z.infer<typeof cameraAuditActionSchema>;
export type CameraAuditLog = z.infer<typeof cameraAuditLogSchema>;
export type CameraRuntimePayload = z.infer<typeof cameraRuntimePayloadSchema>;
export type CameraLatestStatus = z.infer<typeof cameraLatestStatusSchema>;
export type CameraLendInfo = z.infer<typeof cameraLendInfoSchema>;
export type CameraListItem = z.infer<typeof cameraListItemSchema>;
export type CameraListResponse = z.infer<typeof cameraListResponseSchema>;
export type CameraLendRequest = z.infer<typeof cameraLendRequestSchema>;
export type CameraCreateRequest = z.infer<typeof cameraCreateRequestSchema>;
export type CameraReturnResponse = z.infer<typeof cameraReturnResponseSchema>;
export type CameraSimulateIngestResponse = z.infer<typeof cameraSimulateIngestResponseSchema>;
+1
View File
@@ -1,4 +1,5 @@
export * from './device-status.js';
export * from './camera.js';
export * from './greeting.js';
export * from './presence.js';
export * from './telemetry.js';