# backend ## Overview Backend for the video upload prototype providing: - Better Auth email/password authentication - Presigned MinIO uploads/downloads - An authenticated video administration surface at `/admin` ## Requirements - [Bun](https://bun.sh) (tooling used for running scripts & dependency management) - Postgres reachable via `DATABASE_URL` - MinIO-compatible storage reachable via `MINIO_*` env vars - `.env` file populated with secrets and credentials ## Install ```bash bun install ``` ## Configuration Copy the example environment file and adjust the values: ```bash cp .env.example .env ``` Required env vars: | Name | Purpose | | --- | --- | | `DATABASE_URL` | Postgres connection string | | `BETTER_AUTH_SECRET` | Secret used to sign sessions | | `BETTER_AUTH_URL` | Public base URL for the backend (e.g., `http://localhost:3000`) | | `BETTER_AUTH_TRUSTED_ORIGINS` | Comma-separated list of allowed frontend origins | | `PORT` | HTTP port (default `3000`) | | `MINIO_*` | Connection settings for the MinIO/S3 endpoint | | `ADMIN_USERNAME` / `ADMIN_PASSWORD` | Basic auth for `/admin` dashboard | ## Running - Start the server in development: ```bash bun run dev ``` - Server boots after ensuring the configured MinIO bucket exists. ## Database (Drizzle ORM) - Generate a migration: ```bash bun run db:generate ``` - Apply migrations: ```bash bun run db:migrate ``` - Backfill Better Auth credential accounts for existing users: ```bash bun run auth:migrate ``` - Open Drizzle Studio: ```bash bun run db:studio ``` ## API All `/videos` and `/admin` routes require a valid Better Auth session except for the admin dashboard access, which uses HTTP Basic auth with `ADMIN_USERNAME`/`ADMIN_PASSWORD`. ### Authentication Authentication is handled by Better Auth under `/api/auth/*` (for example `/api/auth/sign-in` and `/api/auth/sign-up`). ### Authorization All authenticated endpoints expect a Better Auth session cookie sent by the client. ### Video Management | Endpoint | Purpose | | --- | --- | | `POST /videos/upload-url` | Request a presigned PUT URL for a new video | | `GET /videos/download-url` | Generate a signed GET URL to download a video | | `GET /videos` | List objects in the configured bucket | | `DELETE /videos` | Delete an object by `objectKey` | `POST /videos/upload-url` request body requires `fileName` and `deviceId` (UUID belonging to the authenticated user), with optional `prefix`. ### Device Management (Phase 1) | Endpoint | Purpose | | --- | --- | | `POST /devices/register` | Register a user-owned device as `camera` or `client` and issue bearer device token | | `GET /devices` | List all devices for the authenticated user | | `PATCH /devices/:deviceId` | Update device role/metadata/status | | `POST /devices/:deviceId/heartbeat` | Device-token authenticated presence heartbeat | ### Camera-Client Linking (Phase 1) | Endpoint | Purpose | | --- | --- | | `POST /device-links` | Link one client device to one camera device | | `GET /device-links` | List links for the authenticated user | | `DELETE /device-links/:linkId` | Remove a camera-client link | ### Realtime Commands (Phase 2) | Endpoint | Purpose | | --- | --- | | `POST /commands` | Queue and dispatch command from a linked client device to camera | | `GET /commands` | Inspect command status/history | | `POST /commands/:commandId/ack` | Device-token ack/reject command fallback | Socket.IO channel: - Devices connect with bearer device token (`auth.token` or `Authorization: Bearer ...`). - Camera receives `command:received`. - Camera sends `command:ack` with `acknowledged` or `rejected`. - 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 OpenAPI docs are generated from Zod/OpenAPI definitions: | Endpoint | Purpose | | --- | --- | | `GET /openapi.json` | OpenAPI 3 spec (JSON) | | `GET /docs` | Swagger UI | ### Admin Dashboard Access `/admin` with Basic auth to: - Request presigned upload URLs - Upload files directly via the generated URL - List and delete objects within the MinIO bucket The dashboard UI submits to `/admin/upload-url`, `/admin/objects`, and `/admin/object`. ## Schema - `users` – email/username/password and timestamps - `events` – user-created events with a unique `videoUrl` - `videos` – upload metadata including `objectKey`, bucket, URLs, status, and timestamps ## Notes - MinIO bucket creation happens during startup, so the service must be able to reach the endpoint. - Keep Better Auth and MinIO secrets out of source control.