---
description: "Window 3: Web frontend + design tokens + platform integration + DevOps (Phase 2 + 4 + 5 + 6 — start AFTER Window 1 completes)"
---

# Window 3: Web Frontend + DevOps

> **Prerequisites:** Window 1 must be complete (Manus artifacts removed, deps cleaned, scaffolding in place).
> **Scope:** `client/` directory, root DevOps files (`Dockerfile`, `docker-compose.yml`, `.gitea/`, `scripts/docker-prep.sh`). Do NOT modify `backend/` or `mobile/`.
> **Reference:** `docs/ECOSYSTEM_ADAPTATION_ROADMAP.md` Sections 4 (Phase 2, 4, 5, 6).
> **Scaffold reference repos:** `../learning_ai_fastgap/web/` (NomGap), `../learning_ai_notes/web/` (NoteLett)

## Context

EffoRise is an identity-based habit tracker. The web frontend is a Vite + React 19 SPA in `client/`. Currently only a landing page exists (`client/src/pages/Home.tsx`). The backend (Window 2) exposes APIs on port 4020. Vite proxy is configured to forward `/api` → `http://localhost:4020`.

Product design direction: "Modern Gradient Minimalism" with emerald green branding and glassmorphic UI elements (see `docs/ideas.md`). CSS token prefix: `--er-*`.

---

## Phase 2: Design Token Alignment

### Step 1: Define `--er-*` CSS Custom Properties

Update `client/src/index.css` to use `--er-*` prefixed tokens. Map existing unprefixed vars to the new namespace:

```css
:root {
  /* EffoRise design tokens (--er-* namespace) */
  --er-bg-primary: #ffffff;
  --er-bg-secondary: #f8fafc;
  --er-bg-surface: #ffffff;
  --er-text-primary: #0f172a;
  --er-text-secondary: #475569;
  --er-text-muted: #94a3b8;
  --er-accent-primary: #059669;    /* emerald-600 */
  --er-accent-secondary: #0d9488;  /* teal-600 */
  --er-accent-gradient: linear-gradient(to right, #059669, #0d9488);
  --er-border-default: #e2e8f0;
  --er-border-subtle: #f1f5f9;
  --er-radius-sm: 0.375rem;
  --er-radius-md: 0.5rem;
  --er-radius-lg: 0.75rem;
  --er-radius-xl: 1rem;
  /* ... dark mode overrides in .dark {} */
}
```

Keep the existing shadcn/ui CSS variable layer (--background, --foreground, etc.) but wire them to reference `--er-*` tokens underneath so the app can gradually migrate.

### Step 2: Integrate `@bytelyst/design-tokens`

Add `@bytelyst/design-tokens` to root `package.json` (devDep). This provides the canonical token source. The `--er-*` tokens should align with the generated values where possible.

### Step 3: Wire `@bytelyst/ui` Components

Add `@bytelyst/ui` to root `package.json`. Audit existing `client/src/components/ui/` — replace local shadcn copies where `@bytelyst/ui` equivalents exist (Button, Card, Badge, Toast, etc.). Keep app-specific components local.

Commit: `feat(web): Phase 2 design tokens — --er-* namespace + @bytelyst/design-tokens`

---

## Phase 4: Web App Screens

### Step 1: Create App Layout

Create a sidebar-based app layout (matching ecosystem pattern). Reference `../learning_ai_fastgap/web/src/components/Sidebar.tsx`.

The app should have two modes:
- **Marketing:** Landing page at `/` (existing `Home.tsx`)
- **App:** Sidebar layout at `/app/*` routes (new)

For Vite SPA with wouter:
- `/` → Landing page (existing)
- `/app` → Dashboard
- `/app/identity` → Identity tree builder
- `/app/log` → Effort logging
- `/app/insights` → Progress charts
- `/app/settings` → Account settings

### Step 2: Create API Client

Create `client/src/lib/api-client.ts` — typed fetch wrapper for backend API:

```typescript
const API_BASE = '/api';  // Vite proxy handles forwarding to :4020

export async function fetchApi<T>(path: string, options?: RequestInit): Promise<T> {
  const res = await fetch(`${API_BASE}${path}`, {
    headers: { 'Content-Type': 'application/json', ...options?.headers },
    ...options,
  });
  if (!res.ok) throw new Error(`API error: ${res.status}`);
  return res.json();
}
```

Create typed clients: `identity-client.ts`, `effort-client.ts`, `habit-client.ts`, `streak-client.ts`, `insight-client.ts`.

### Step 3: Create Zustand Store

Create `client/src/lib/store.ts` — app state store:

```typescript
import { create } from 'zustand';
// Identity, effort, habit, streak state + actions
// Wire to API clients for fetch/create/update/delete
```

### Step 4: Build Screens

Build each screen as a component in `client/src/pages/app/`:

1. **Dashboard** (`Dashboard.tsx`)
   - Identity tree summary cards
   - Today's habits checklist
   - Current streaks display
   - Quick-log effort button
   - Recent insights

2. **Identity Builder** (`Identity.tsx`)
   - Tree view of identities (parent/child)
   - Create/edit identity modal
   - Drag-and-drop reorder
   - Color + icon picker

3. **Effort Logger** (`Log.tsx`)
   - Quick-tap effort buttons (micro/medium/deep)
   - Select identity + optional habit
   - Description + duration
   - Recent efforts timeline

4. **Insights** (`Insights.tsx`)
   - Weekly effort chart (Recharts)
   - Streak leaderboard
   - AI coaching cards
   - Milestone celebrations

5. **Settings** (`Settings.tsx`)
   - Account info (placeholder until auth)
   - Theme toggle (already exists via ThemeContext)
   - Notification preferences (placeholder)
   - Data export

### Step 5: Verify Phase 4

- All screens render without errors
- API calls work through Vite proxy to backend (if Window 2 is running)
- Navigation works between all routes

Commit: `feat(web): Phase 4 app screens — dashboard, identity, log, insights, settings`

---

## Phase 5: Platform Integration

### Step 1: Add Platform Client Packages

Add to root `package.json`:
- `@bytelyst/react-auth` — Auth context + provider
- `@bytelyst/api-client` — Typed fetch wrapper (can replace manual api-client.ts)
- `@bytelyst/telemetry-client` — Browser telemetry
- `@bytelyst/diagnostics-client` — Diagnostic reporter
- `@bytelyst/feature-flag-client` — Feature flags
- `@bytelyst/kill-switch-client` — Kill switch
- `@bytelyst/platform-client` — Platform service client

### Step 2: Wire Auth

Create `client/src/lib/auth.ts`:
```typescript
import { createAuthContext } from '@bytelyst/react-auth';
export const { AuthProvider, useAuth } = createAuthContext({
  platformUrl: 'http://localhost:4003',
  productId: 'efforise',
});
```

Wrap app in `<AuthProvider>` in `App.tsx`.

### Step 3: Wire Telemetry + Diagnostics

Create `client/src/lib/telemetry.ts` and `client/src/lib/diagnostics.ts`. Initialize in app root.

### Step 4: Wire Feature Flags + Kill Switch

Create `client/src/lib/feature-flags.ts` and `client/src/lib/kill-switch.ts`. Use for gating unreleased features.

### Step 5: Create Product Config

Create `client/src/lib/product-config.ts`:
```typescript
import productJson from '../../../shared/product.json';
export const PRODUCT_ID = productJson.productId;
export const PRODUCT_NAME = productJson.productName;
// etc.
```

Commit: `feat(web): Phase 5 platform integration — auth, telemetry, flags, kill switch`

---

## Phase 6: DevOps

### Step 1: Docker

- Create `client/Dockerfile` — multi-stage Vite build (or copy from NomGap `../learning_ai_fastgap/web/Dockerfile` and adapt for Vite)
- Create `docker-compose.yml` at root:
  ```yaml
  services:
    backend:
      build: ./backend
      ports: ["4020:4020"]
      env_file: backend/.env
    web:
      build: ./client
      ports: ["3080:3080"]
  ```
- Create `scripts/docker-prep.sh` — Pack @bytelyst/* tarballs for Docker builds (copy from `../learning_ai_notes/scripts/docker-prep.sh`)

### Step 2: CI

Create `.gitea/workflows/ci.yml`:
```yaml
name: CI
on: [push, pull_request]
jobs:
  backend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: pnpm install --frozen-lockfile
      - run: cd backend && pnpm run typecheck
      - run: cd backend && pnpm test
      - run: cd backend && pnpm run build
  web:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: pnpm install --frozen-lockfile
      - run: cd client && npx tsc --noEmit
      - run: pnpm run build
```

### Step 3: Playwright E2E

Create `client/e2e/` directory with:
- `playwright.config.ts` — config targeting `http://localhost:3080`
- `accessibility.spec.ts` — axe-core accessibility checks on all pages
- `navigation.spec.ts` — verify all routes load

### Step 4: Register in Ecosystem

Tell user to add to `../learning_ai_common_plat/`:
- `docker-compose.ecosystem.yml`: efforise-backend :4020, efforise-web :3080
- `.env.ecosystem.example`: Effo Rise env vars
- `products/efforise/product.json`: Product registry entry

Commit: `chore(devops): Phase 6 — Docker, CI, Playwright E2E, docker-prep`

---

## Done Signal

When complete, tell the user: **"Window 3 complete. Web app with 5 screens, platform integration, Docker, CI, and Playwright E2E are ready."**
