# Platform Admin Dashboard

Product-agnostic admin console for the ByteLyst platform. Connects **directly** to Azure Cosmos DB via the `@azure/cosmos` SDK — no intermediate API server. Set `PRODUCT_ID` in `.env.local` to deploy for any product (e.g. `lysnrai`, `chronomind`, `nomgap`, `mindlyst`).

---

## Tech Stack

| Layer         | Technology                                       |
| ------------- | ------------------------------------------------ |
| **Framework** | Next.js 16 (App Router, React 19)                |
| **Styling**   | TailwindCSS v4 + shadcn/ui (New York style)      |
| **Database**  | Azure Cosmos DB (NoSQL, Serverless) — direct SDK |
| **Auth**      | JWT (jose) + bcrypt (bcryptjs), server-side only |
| **Charts**    | Recharts                                         |
| **Icons**     | Lucide React                                     |
| **Language**  | TypeScript 5                                     |

## Getting Started

```bash
npm install
cp .env.local.example .env.local    # Fill in real Azure credentials

npm run dev                         # http://localhost:3001
npm run check                       # TypeScript + ESLint
npm run build                       # Production build
```

### Seed the Database

Creates all Cosmos containers + default admin/viewer users:

```bash
curl -X POST "http://localhost:3001/api/seed?secret=<SEED_SECRET>"
```

### Default Logins

| Email              | Password    | Role        |
| ------------------ | ----------- | ----------- |
| `admin@example.com`  | `Admin123!`  | Super Admin |
| `viewer@example.com` | `viewer123`  | Viewer      |

## Environment Variables

Copy `.env.local.example` → `.env.local`:

| Variable                  | Required | Description                              |
| ------------------------- | -------- | ---------------------------------------- |
| `COSMOS_ENDPOINT`         | Yes      | Cosmos DB endpoint URL                   |
| `COSMOS_KEY`              | Yes      | Cosmos DB primary key                    |
| `COSMOS_DATABASE`         | No       | Database name (set per product)          |
| `COSMOS_REGION`           | No       | Region (default: `westus2`)              |
| `JWT_SECRET`              | Yes      | Shared JWT signing secret                |
| `SEED_SECRET`             | Yes      | Secret for POST /api/seed                |
| `AZURE_KEYVAULT_URL`      | No       | Azure Key Vault URL                      |
| `AZURE_SPEECH_KEY`        | No       | Speech service key (for future features) |
| `AZURE_SPEECH_REGION`     | No       | Speech region                            |
| `AZURE_OPENAI_ENDPOINT`   | No       | OpenAI endpoint                          |
| `AZURE_OPENAI_KEY`        | No       | OpenAI key                               |
| `AZURE_OPENAI_DEPLOYMENT` | No       | Model deployment name                    |

## Pages

| Route            | Description                                                      |
| ---------------- | ---------------------------------------------------------------- |
| `/`              | Dashboard overview — KPIs, charts, recent activity               |
| `/users`         | User management — search, filter, detail dialogs                 |
| `/subscriptions` | Plan management — pricing, features, create plans                |
| `/tokens`        | API token management — create, revoke, scopes                    |
| `/usage`         | Usage analytics — token/request charts, model costs              |
| `/audit`         | Audit log — admin actions, security events                       |
| `/settings`      | Platform config — kill switch, Azure, rate limits, notifications |
| `/login`         | Authentication page                                              |

## API Routes

All routes are in `src/app/api/`:

| Endpoint                    | Method         | Description                                |
| --------------------------- | -------------- | ------------------------------------------ |
| `/api/auth/login`           | POST           | Authenticate user (email + password → JWT) |
| `/api/auth/me`              | GET            | Get current user from Bearer token         |
| `/api/users`                | GET/POST       | List/create users                          |
| `/api/users/[id]`           | GET/PUT/DELETE | User CRUD by ID                            |
| `/api/tokens`               | GET/POST       | List/create API tokens                     |
| `/api/usage`                | GET            | Usage analytics                            |
| `/api/audit`                | GET            | Audit log entries                          |
| `/api/dashboard/stats`      | GET            | Dashboard KPI statistics                   |
| `/api/settings/kill-switch` | GET/PUT        | Platform kill switch (read/toggle)         |
| `/api/seed`                 | POST           | Initialize containers + seed default users |

## Architecture

```
src/
├── app/
│   ├── (dashboard)/              # Protected routes (sidebar + auth guard)
│   │   ├── layout.tsx            # Dashboard shell (sidebar, error boundary)
│   │   ├── loading.tsx           # Skeleton loading state
│   │   ├── page.tsx              # Dashboard overview
│   │   ├── users/page.tsx
│   │   ├── subscriptions/page.tsx
│   │   ├── tokens/page.tsx
│   │   ├── usage/page.tsx
│   │   ├── audit/page.tsx
│   │   └── settings/page.tsx     # Includes kill switch toggle
│   ├── api/                      # Next.js API routes → direct Cosmos DB
│   │   ├── auth/login/route.ts
│   │   ├── auth/me/route.ts
│   │   ├── users/route.ts
│   │   ├── users/[id]/route.ts
│   │   ├── tokens/route.ts
│   │   ├── usage/route.ts
│   │   ├── audit/route.ts
│   │   ├── dashboard/stats/route.ts
│   │   ├── settings/kill-switch/route.ts
│   │   └── seed/route.ts
│   ├── login/page.tsx            # Public login page
│   ├── layout.tsx                # Root layout (providers)
│   └── providers.tsx             # Auth + Theme providers
├── components/
│   ├── ui/                       # 16 shadcn/ui primitives (avatar, badge, button, card, etc.)
│   ├── sidebar-nav.tsx           # Responsive sidebar (mobile hamburger)
│   ├── auth-guard.tsx            # Route protection → redirect to /login
│   └── error-boundary.tsx        # Catch page crashes gracefully
└── lib/
    ├── cosmos.ts                 # Cosmos DB client singleton + container registry
    ├── auth-server.ts            # JWT create/verify + bcrypt (server-side only)
    ├── auth-context.tsx          # Client auth provider (localStorage tokens)
    ├── theme-context.tsx         # Dark/light/system mode
    ├── api.ts                    # Client-side API helper functions
    ├── mock-data.ts              # Mock data + types (fallback when Cosmos unavailable)
    ├── utils.ts                  # cn() tailwind merge helper
    └── repositories/             # Direct Cosmos DB CRUD
        ├── users.ts              # getUserById, getUserByEmail, createUser, updateUser
        ├── tokens.ts             # API token CRUD
        ├── audit.ts              # Audit log read/write
        └── usage.ts              # Usage statistics
```

## Cosmos DB Integration

The dashboard connects **directly** to Cosmos DB — no intermediate backend server.

**Pattern:**

```
Page Component → fetch("/api/...") → API Route → Repository → Cosmos SDK → Azure
```

**Key files:**

- `lib/cosmos.ts` — singleton `CosmosClient`, `getContainer(name)`, `initializeAllContainers()`
- `lib/repositories/*.ts` — CRUD functions per container
- `lib/auth-server.ts` — `authenticateUser()`, `createAccessToken()`, `verifyToken()`

**Container definitions** (in `cosmos.ts`):

| Container     | Partition Key | TTL     |
| ------------- | ------------- | ------- |
| `users`       | `/id`         | —       |
| `licenses`    | `/userId`     | —       |
| `transcripts` | `/userId`     | —       |
| `usage_daily` | `/userId`     | 1 year  |
| `settings`    | `/userId`     | —       |
| `audit_log`   | `/category`   | 90 days |
| `api_tokens`  | `/userId`     | —       |
| `devices`     | `/userId`     | —       |

## Kill Switch

The Settings page has a prominent kill switch card at the top:

- **Green** = platform active, **Red** = platform disabled
- Toggle writes to `settings` container: `{ id: "kill_switch", userId: "system", enabled: bool }`
- All apps (desktop, mobile, web) read this document to check platform status

## Features

- **Direct Cosmos DB** — no middleware, API routes call SDK directly
- **JWT auth** — bcrypt password hashing, HS256 JWT tokens
- **Auth guard** — redirects to `/login` if not authenticated
- **Mock fallback** — pages fall back to mock data if Cosmos is unavailable
- **Responsive** — sidebar collapses to hamburger on mobile
- **Dark mode** — toggle in sidebar footer, persisted to localStorage
- **Error boundary** — catches page crashes gracefully
- **Kill switch** — global platform toggle on Settings page

## Docker

```bash
docker build -t platform-admin .
docker run -p 3001:3000 --env-file .env.local platform-admin

# Or with docker-compose
docker compose up -d
```

## Development Notes

- **Port**: runs on 3001 in dev (3000 may conflict with Docker)
- **shadcn/ui**: components are in `src/components/ui/`, added via `npx shadcn@latest add <component>`
- **Adding a new API route**: create `src/app/api/<name>/route.ts`, import from `@/lib/repositories/*`
- **Adding a new page**: create `src/app/(dashboard)/<name>/page.tsx` — auto-protected by auth guard
