> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blindcast.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Server Overview

> Drop-in Docker server for BlindCast — content registry, API keys, key derivation, presigned uploads, and an admin dashboard in a single container.

The BlindCast Server is a complete backend for encrypted video — register content, manage API keys, derive content keys, generate presigned upload URLs, and administer everything from a built-in dashboard.

## What it includes

| Feature               | Description                                                             |
| --------------------- | ----------------------------------------------------------------------- |
| **Content registry**  | Postgres-backed content CRUD with status management                     |
| **API key auth**      | SHA-256 hashed keys with scopes (`admin`, `full`, `upload`, `playback`) |
| **Key derivation**    | HKDF-SHA-256 content keys — only for registered, active content         |
| **Presigned uploads** | S3-compatible presigned PUT URLs scoped to content                      |
| **Viewer auth**       | HS256 or JWKS JWT verification for key endpoints                        |
| **Leases**            | Time-limited, revocable access tokens                                   |
| **Admin dashboard**   | React SPA at `/admin` with first-launch setup wizard                    |

## Quick start

```bash theme={null}
# 1. Generate keys
openssl rand -hex 32  # → MASTER_KEY_HEX
openssl rand -hex 32  # → SALT_HEX

# 2. Start everything
cd packages/server
MASTER_KEY_HEX=<your-key> SALT_HEX=<your-salt> docker compose up -d

# 3. Open the dashboard
open http://localhost:4100/admin
```

The first visit to the dashboard triggers a setup wizard that creates your first admin API key.

## Architecture

```mermaid theme={null}
graph TB
  subgraph "BlindCast Server (Docker)"
    API["REST API<br/>/api/v1/*"]
    Keys["Key Server<br/>/keys/:contentId"]
    Presign["Presign<br/>/api/v1/content/:id/presign"]
    Admin["Admin Dashboard<br/>/admin"]
    Health["Health Check<br/>/health"]
  end

  PG["Postgres"]
  S3["S3 / MinIO"]

  API --> PG
  Keys --> PG
  Presign --> S3
  Admin --> API
```

The server composes existing BlindCast packages:

* **`@blindcast/keys/express`** — key derivation router mounted at `/keys`
* **`@blindcast/storage/presign-server`** — presigned URL generation
* **Content registry** — Postgres-backed content + API key stores
* **Admin SPA** — static React + Tailwind files served at `/admin`

## Endpoints

| Method   | Path                          | Auth                  | Description               |
| -------- | ----------------------------- | --------------------- | ------------------------- |
| `GET`    | `/health`                     | None                  | Health check              |
| `GET`    | `/keys/:contentId`            | JWT (optional)        | Derive content key        |
| `POST`   | `/api/v1/content`             | API key               | Register content          |
| `GET`    | `/api/v1/content`             | API key               | List content              |
| `GET`    | `/api/v1/content/:id`         | API key               | Get content details       |
| `PATCH`  | `/api/v1/content/:id`         | API key               | Update content            |
| `DELETE` | `/api/v1/content/:id`         | API key               | Soft-delete content       |
| `POST`   | `/api/v1/content/:id/presign` | API key               | Get presigned upload URLs |
| `POST`   | `/api/v1/api-keys`            | API key (admin)       | Create API key            |
| `GET`    | `/api/v1/api-keys`            | API key (admin)       | List API keys             |
| `DELETE` | `/api/v1/api-keys/:id`        | API key (admin)       | Revoke API key            |
| `POST`   | `/api/v1/setup`               | None (first run only) | Create initial admin key  |

## Key validation

The server only derives keys for **registered, active** content. If a viewer requests a key for an unregistered or disabled content ID, the key server returns 404. This prevents key derivation for arbitrary content IDs.

## Next steps

* [Docker Setup](/server/docker) — environment variables, bring-your-own Postgres/S3
* [Content API](/server/content-api) — REST API reference
* [API Keys](/server/api-keys) — scopes, bootstrap, management
* [Admin Dashboard](/server/admin-dashboard) — setup wizard, content management UI
