# NVR Backend API Gateway

Production-oriented FastAPI gateway for an AI-powered NVR system. The gateway is responsible for authentication, camera metadata, MongoDB clip/event queries, and signed MinIO playback/thumbnail URLs. Frontend clients should never connect directly to MongoDB or MinIO.

## Features

- JWT login, refresh, and current-user endpoints with bcrypt password support.
- Protected REST APIs for cameras, live stream metadata, clips, clip playback, thumbnails, and event timelines.
- Automatic MongoDB indexes for the ingestion `events` collection search patterns.
- MinIO presigned URL generation with configurable expiration.
- Structured JSON request logging with request id, endpoint, method, latency, status, and user id.
- Configurable in-memory rate limiting.
- Unified JSON error responses.
- Dockerfile and Docker Compose stack for backend, MongoDB, MinIO, and bucket initialization.

## Configuration

Copy the example environment file and replace all `change-me` values before running in production:

```bash
cp .env.example .env
```

Required variables include:

- `MONGO_URI`, `MONGO_DB`, `MONGO_COLLECTION`
- `MINIO_ENDPOINT`, `MINIO_ACCESS_KEY`, `MINIO_SECRET_KEY`, `MINIO_BUCKET`
- `JWT_SECRET`, `JWT_EXPIRATION_MINUTES`, `REFRESH_TOKEN_EXPIRATION_DAYS`
- `ADMIN_USERNAME` plus either `ADMIN_PASSWORD` or `ADMIN_PASSWORD_HASH`

`INGESTION_CONFIG_PATH` defaults to `../Ingestion/config.json`; when that file is readable, camera IDs are derived from the ingestion `video_sources` order, matching `nvr_processor.py` stream IDs (`0`, `1`, ...). `CAMERAS_JSON` can be set to override camera and live stream metadata returned by `/api/cameras` and `/api/live-streams`.

## Run with Docker Compose

```bash
cd backend
docker compose up --build
```

The API listens on `http://localhost:8000`. Swagger UI is available at `http://localhost:8000/docs`.

## Run locally

```bash
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
uvicorn app.main:app --reload
```

## Authentication flow

1. Set `ADMIN_PASSWORD` or `ADMIN_PASSWORD_HASH` in `.env`.
2. Start the backend; it creates the admin user if it does not exist.
3. Log in:

```bash
curl -X POST http://localhost:8000/api/auth/login \
  -H 'content-type: application/json' \
  -d '{"username":"admin","password":"change-me-admin-password"}'
```

Use the returned access token as `Authorization: Bearer <token>` for all non-health endpoints.

## Endpoints

- `GET /health`
- `POST /api/auth/login`
- `POST /api/auth/refresh`
- `GET /api/auth/me`
- `GET /api/cameras`
- `GET /api/cameras/{camera_id}`
- `GET /api/live-streams`
- `GET /api/clips?camera_id=1&detected_object=person&page=1&limit=50`
- `GET /api/clips/{clip_id}`
- `GET /api/clips/{clip_id}/playback`
- `GET /api/clips/{clip_id}/thumbnail`
- `GET /api/events`

## MongoDB clip schema

The gateway reads uploader records like this and supports extended metadata fields:

```json
{
  "camera_id": 0,
  "filename": "clip.mp4",
  "s3_path": "cam_0/clip.mp4",
  "timestamp": "2026-06-11T00:00:00Z",
  "uploaded_at": "2026-06-11T00:00:10Z",
  "detected_object": "person",
  "duration_seconds": 10,
  "size_bytes": 4235112,
  "thumbnail_path": "cam_0/thumb.jpg"
}
```

The default `MONGO_COLLECTION` is `events` and the default `MINIO_BUCKET` is `nvr-footage` so the gateway reads the records written by `Ingestion/nvr_processor.py` without renaming collections or buckets. Indexes are created automatically on startup for `(camera_id, timestamp)`, `timestamp`, and `detected_object`.
