- dashboards/admin-web: split product-constants.ts for client-safe imports - dashboards/admin-web: serverExternalPackages + webpack fallbacks for @bytelyst/config - dashboards/admin-web: instrumentation.ts uses @bytelyst/config/keyvault sub-path - packages/config: add ./keyvault and ./product-identity sub-path exports - packages/feedback-client: fix stale test expectation (TODO-1 → actual error message) - packages/sync: fix reprocessFailed test (flush already pushes items) |
||
|---|---|---|
| .. | ||
| e2e | ||
| public | ||
| src | ||
| .bundlesizerc.json | ||
| .dockerignore | ||
| .env.example | ||
| .env.local.example | ||
| .gitignore | ||
| .nvmrc | ||
| components.json | ||
| Dockerfile | ||
| eslint.config.mjs | ||
| next.config.ts | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| postcss.config.mjs | ||
| README.md | ||
| tsconfig.json | ||
| vercel.json | ||
| vitest.config.ts | ||
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
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:
curl -X POST "http://localhost:3001/api/seed?secret=<SEED_SECRET>"
Default Logins
| 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— singletonCosmosClient,getContainer(name),initializeAllContainers()lib/repositories/*.ts— CRUD functions per containerlib/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
settingscontainer:{ 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
/loginif 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
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 vianpx 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