docs(events): add phase3 motion API and realtime event docs
This commit is contained in:
@@ -111,6 +111,17 @@ Socket.IO channel:
|
|||||||
- Camera sends `command:ack` with `acknowledged` or `rejected`.
|
- Camera sends `command:ack` with `acknowledged` or `rejected`.
|
||||||
- Source client receives `command:status`.
|
- Source client receives `command:status`.
|
||||||
|
|
||||||
|
### Motion Events (Phase 3)
|
||||||
|
| Endpoint | Purpose |
|
||||||
|
| --- | --- |
|
||||||
|
| `POST /events/motion/start` | Camera device creates motion event and fan-outs notification to linked clients |
|
||||||
|
| `POST /events/:eventId/motion/end` | Camera device closes a motion event and broadcasts end state |
|
||||||
|
| `GET /events` | Authenticated user fetches event history |
|
||||||
|
|
||||||
|
Motion realtime events:
|
||||||
|
- Linked clients receive `motion:detected` as soon as camera starts event.
|
||||||
|
- Linked clients receive `motion:ended` when camera ends event.
|
||||||
|
|
||||||
### API Docs
|
### API Docs
|
||||||
OpenAPI docs are generated from Zod/OpenAPI definitions:
|
OpenAPI docs are generated from Zod/OpenAPI definitions:
|
||||||
|
|
||||||
|
|||||||
@@ -608,6 +608,132 @@ registry.registerPath({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: 'post',
|
||||||
|
path: '/events/motion/start',
|
||||||
|
summary: 'Camera device starts a motion event and notifies linked clients',
|
||||||
|
tags: ['Events'],
|
||||||
|
security: [{ bearerDeviceToken: [] }],
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: z.object({
|
||||||
|
title: z.string().optional(),
|
||||||
|
triggeredBy: z.string().optional(),
|
||||||
|
videoUrl: z.string().url().optional(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
201: {
|
||||||
|
description: 'Motion event started',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: z.object({
|
||||||
|
message: z.string(),
|
||||||
|
event: z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
userId: z.string().uuid(),
|
||||||
|
deviceId: z.string().uuid().nullable(),
|
||||||
|
title: z.string().nullable(),
|
||||||
|
triggeredBy: z.string().nullable(),
|
||||||
|
status: z.string(),
|
||||||
|
startedAt: z.string().datetime(),
|
||||||
|
endedAt: z.string().datetime().nullable(),
|
||||||
|
videoUrl: z.string().nullable(),
|
||||||
|
createdAt: z.string().datetime(),
|
||||||
|
updatedAt: z.string().datetime(),
|
||||||
|
notifiedAt: z.string().datetime().nullable(),
|
||||||
|
}),
|
||||||
|
notifiedClients: z.number().int(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: 'post',
|
||||||
|
path: '/events/{eventId}/motion/end',
|
||||||
|
summary: 'Camera device ends a motion event and notifies linked clients',
|
||||||
|
tags: ['Events'],
|
||||||
|
security: [{ bearerDeviceToken: [] }],
|
||||||
|
request: {
|
||||||
|
params: z.object({ eventId: z.string().uuid() }),
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: z.object({
|
||||||
|
status: z.enum(['completed', 'cancelled', 'failed']).optional(),
|
||||||
|
videoUrl: z.string().url().optional(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: 'Motion event ended',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: z.object({
|
||||||
|
message: z.string(),
|
||||||
|
event: z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
status: z.string(),
|
||||||
|
endedAt: z.string().datetime().nullable(),
|
||||||
|
updatedAt: z.string().datetime(),
|
||||||
|
}),
|
||||||
|
notifiedClients: z.number().int(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: 'get',
|
||||||
|
path: '/events',
|
||||||
|
summary: 'List events for authenticated user',
|
||||||
|
tags: ['Events'],
|
||||||
|
security: [{ cookieAuth: [] }],
|
||||||
|
request: {
|
||||||
|
query: z.object({
|
||||||
|
status: z.string().optional(),
|
||||||
|
limit: z.coerce.number().int().min(1).max(100).default(25),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: 'User event list',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: z.object({
|
||||||
|
count: z.number().int(),
|
||||||
|
events: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
status: z.string(),
|
||||||
|
startedAt: z.string().datetime(),
|
||||||
|
endedAt: z.string().datetime().nullable(),
|
||||||
|
deviceId: z.string().uuid().nullable(),
|
||||||
|
title: z.string().nullable(),
|
||||||
|
triggeredBy: z.string().nullable(),
|
||||||
|
videoUrl: z.string().nullable(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export function buildOpenApiDocument() {
|
export function buildOpenApiDocument() {
|
||||||
const generator = new OpenApiGeneratorV3(registry.definitions);
|
const generator = new OpenApiGeneratorV3(registry.definitions);
|
||||||
const document = generator.generateDocument({
|
const document = generator.generateDocument({
|
||||||
@@ -625,6 +751,7 @@ export function buildOpenApiDocument() {
|
|||||||
{ name: 'Devices', description: 'Device registration and heartbeat endpoints' },
|
{ name: 'Devices', description: 'Device registration and heartbeat endpoints' },
|
||||||
{ name: 'Device Links', description: 'Client-camera authorization links' },
|
{ name: 'Device Links', description: 'Client-camera authorization links' },
|
||||||
{ name: 'Commands', description: 'Realtime command dispatch and status' },
|
{ name: 'Commands', description: 'Realtime command dispatch and status' },
|
||||||
|
{ name: 'Events', description: 'Motion event lifecycle and user event history' },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user