# Web Internal Adoption Checklist (Stage 2 Cutover)

## Purpose

This document is the step-by-step runbook for switching internal operators from the
legacy `bytelyst-trading-dashboard-web` to the new monorepo web dashboard (`web/`).

It covers the pre-flight gate, deployment, validation, rollback triggers, and
post-adoption monitoring. Complete every step in order.

---

## Pre-Flight Gate

Do not begin cutover until all of the following are true.

### Go / No-Go Checks

Run from the monorepo root:

```bash
pnpm verify          # typecheck + test + build — must be green
pnpm lint            # backend contract + security guards + web/mobile lint — must be green
pnpm smoke:release   # auth + kill-switch smoke tests — must pass
```

Backend-specific:

```bash
cd backend
npm run check:api-contract          # feature-flag shapes, audit events, namespace constants
npm run check:websocket-contract    # BotState lifecycle consistency
npm run check:security-guards       # tenant isolation — must be green
npm run check:tenant-isolation      # row-level access — must be green
```

### Environment Checks

- [ ] Backend is deployed and reachable (`GET /health/live` returns 200)
- [ ] Cosmos DB containers readable and writable (`dynamic_config`, `trading-profiles`, `trading-control`, `snapshots`, `capital-ledger`)
- [ ] Platform-service is reachable from the deployment environment
- [ ] `PLATFORM_AUTH_ENABLED=true` is set on the backend deployment
- [ ] `VITE_TRADING_API_URL` points to the deployed backend (not localhost)
- [ ] `VITE_PLATFORM_URL` points to the live platform-service
- [ ] `CORS_ALLOWED_ORIGINS` on the backend includes the new web dashboard origin
- [ ] Feature flags set correctly for the rollout population:
  - `TAB_MARKETPLACE_ENABLED` — set per rollout plan
  - `TAB_MEMBERSHIP_ENABLED` — set per rollout plan
  - `ENABLE_BACKTEST` — set per rollout plan

### Rollback Readiness

- [ ] The legacy web dashboard URL is still live and working
- [ ] You know who owns the rollback decision and how to reach them
- [ ] Backend trade-halt control is reachable (`POST /internal/trading/pause`)

---

## Step 1 — Deploy the Web Dashboard

```bash
# From monorepo root — production build
pnpm build

# Or using Docker
pnpm docker:up
```

Verify the deployment:

- [ ] Web dashboard loads at the new URL without a blank screen
- [ ] Browser console shows no errors on load
- [ ] Network tab shows no 4xx/5xx on initial API calls

---

## Step 2 — Internal Operator Sign-In

Have each internal operator complete the sign-in sequence:

- [ ] Navigate to the new web dashboard URL
- [ ] Sign in using platform credentials (same as the legacy dashboard)
- [ ] Session restores correctly after browser refresh (no re-login required)
- [ ] Auth token is a platform JWT (check via browser devtools: `Authorization: Bearer ...` on API calls)
- [ ] `GET /api/me/profile` returns the correct user profile and role

---

## Step 3 — Core Feature Validation

Each operator validates their own user scope:

### Trading State
- [ ] Overview tab loads with live bot state (not stale/empty)
- [ ] WebSocket connection shows "Connected" in the header
- [ ] Socket connects to `/trading` namespace (check backend logs: `[API][/trading] Client connected`)
- [ ] Positions tab shows current open positions
- [ ] Trade History tab shows closed trade history
- [ ] My Strategies tab lists the operator's trading profiles

### Real-Time Updates
- [ ] Leave the dashboard open for 60 seconds; confirm symbol prices update live
- [ ] Trigger a manual order or profile toggle; confirm the state updates without refresh

### Admin Operators (role = admin only)
- [ ] Signals tab is visible and loads correctly
- [ ] Entries tab is visible and loads correctly
- [ ] Admin Panel tab is visible
- [ ] Strategy Clusters tab is visible
- [ ] Admin Panel → Trading Control: pause and resume work correctly
- [ ] Backend logs show `[AUDIT]` entries for pause/resume actions
- [ ] "Preview as Customer" toggle hides admin-only tabs correctly

### Kill-Switch Behaviour
- [ ] If platform-service maintenance mode is toggled on, web blocks access with correct UI
- [ ] After maintenance mode is lifted, web recovers without a page reload

---

## Step 4 — Config and Feature Flag Validation

- [ ] `GET /api/feature-flags` returns the correct `backtest`, `tabs.marketplace`, and `tabs.membership` values
- [ ] Backtesting tab visibility matches `ENABLE_BACKTEST` and `BACKTEST_CUSTOMER_ENABLED` config
- [ ] Marketplace tab visibility matches `TAB_MARKETPLACE_ENABLED` config
- [ ] Membership tab visibility matches `TAB_MEMBERSHIP_ENABLED` config
- [ ] Dynamic config changes via Admin Panel → Config are persisted to Cosmos and visible after a page refresh

---

## Step 5 — Request Tracing Spot Check

Pick any operator action (e.g., load trade history):

- [ ] Browser devtools shows `x-request-id` header on the request
- [ ] Backend response echoes the same `x-request-id`
- [ ] Search backend logs for that `x-request-id` — the full request trace appears

---

## Step 6 — Parallel Run Period (Recommended: 1–3 days)

Run the new and legacy dashboards in parallel before switching traffic fully:

- [ ] Operators use the new dashboard as primary
- [ ] Legacy dashboard remains accessible as a fallback
- [ ] No trading state mutations go through the legacy dashboard during this period
- [ ] Monitor for discrepancies between what new and legacy dashboards show

---

## Step 7 — Traffic Cutover

Once parallel run is complete with no issues:

- [ ] Update any bookmarks, internal links, or runbooks to point to the new URL
- [ ] Communicate to all internal users that the new dashboard is now primary
- [ ] Disable or redirect the legacy dashboard URL (do not delete it yet)

---

## Rollback Triggers

Stop cutover and revert to the legacy dashboard immediately if any of the following occur:

| Condition | Action |
|---|---|
| Sign-in or session restore fails for any operator | Rollback |
| Tenant data leak — operator sees another user's positions or history | Rollback immediately + page oncall |
| Trading control (pause/resume) does not apply correctly | Rollback |
| Dynamic config writes fail silently | Rollback |
| WebSocket disconnects repeatedly with no recovery | Rollback |
| Missing data in positions or trade history vs. legacy dashboard | Investigate before proceeding |

### Rollback Steps

1. Restore the legacy dashboard URL as primary (flip DNS or update internal links)
2. Notify all operators to switch back immediately
3. Do **not** rewrite or delete Cosmos state during first-response rollback
4. File an incident report referencing the `x-request-id` values from affected requests
5. Resolve the root cause before re-attempting cutover

---

## Post-Adoption Monitoring (First 24 Hours)

Watch the following immediately after cutting over:

### Immediate (first 30 minutes)
- [ ] Platform auth failure rate is zero
- [ ] Token refresh failures are zero
- [ ] Backend `401` / `403` error rate is baseline (no spike)
- [ ] WebSocket connection error rate is baseline

### First Hour
- [ ] Cosmos reads and writes are completing successfully (check backend logs for Cosmos errors)
- [ ] Dynamic config refresh cycle completes without error (every `DYNAMIC_CONFIG_REFRESH_MS`)
- [ ] No tenant isolation anomalies in security guard logs

### First 24 Hours
- [ ] Runtime control drift: Cosmos control-plane state matches in-memory trading control mode
- [ ] Kill-switch state matches platform-service state
- [ ] No stale session events (operators are not re-prompted to log in unexpectedly)
- [ ] No build or chunk-size regressions affecting web load time (check browser waterfall)

---

## Post-Cutover Sign-Off

Complete after the first 24 hours with no rollback triggers:

- [ ] All operators confirm the new dashboard is working correctly
- [ ] Monitoring checks above are all green
- [ ] Incident response runbooks updated to reference the new dashboard URL
- [ ] Legacy web repo marked as archived (not deleted — kept as reference)
- [ ] ROADMAP.md: mark "Web internal adoption" as `[x]` Done
- [ ] OPERATIONS.md: update Staged Cutover section to reflect Stage 2 complete

---

## Next Stage

After web internal adoption is confirmed:

**Stage 3 — Mobile Internal Beta** (see planned `docs/CUTOVER_MOBILE.md`)
- Release mobile app to internal testers
- Validate sign-in, session restore, live state, degraded-state handling
- Gate: backend/web contracts must be stable through at least one full backend deploy cycle
