From de13a08a98a6e2c8ff5cf54e44777e02a08330c2 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Tue, 31 Mar 2026 01:42:31 -0700 Subject: [PATCH] chore: update chat history archive + design-tokens tarball --- .../WINDSURF/.last-refresh.log | 12 +- .../learning_ai_efforise/README.md | 9 + .../refresh-chat-history.md | 17 ++ .../w1-scaffold-and-cleanup.md | 125 ++++++++ .../w2-backend-scaffold.md | 255 ++++++++++++++++ .../learning_ai_efforise/w3-web-and-devops.md | 278 ++++++++++++++++++ .../bytelyst-design-tokens-0.1.0.tgz | Bin 0 -> 29482 bytes 7 files changed, 690 insertions(+), 6 deletions(-) create mode 100644 __LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/README.md create mode 100644 __LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/refresh-chat-history.md create mode 100644 __LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w1-scaffold-and-cleanup.md create mode 100644 __LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w2-backend-scaffold.md create mode 100644 __LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w3-web-and-devops.md create mode 100644 packages/design-tokens/bytelyst-design-tokens-0.1.0.tgz diff --git a/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/.last-refresh.log b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/.last-refresh.log index 0cd72170..259ede4e 100644 --- a/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/.last-refresh.log +++ b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/.last-refresh.log @@ -1,9 +1,9 @@ -Last refresh: 2026-03-29T06:00:06Z (2026-03-28 23:00:06 PDT) -Cascade conversations: 50 (424M) -Memories: 104 +Last refresh: 2026-03-31T06:00:05Z (2026-03-30 23:00:05 PDT) +Cascade conversations: 50 (366M) +Memories: 106 Implicit context: 20 -Code tracker dirs: 77 -File edit history: 3881 entries +Code tracker dirs: 43 +File edit history: 4014 entries Workspace storage: 34 workspaces Repo docs: 7 files across 2 repos -Repo workflows: 49 files across 11 repos +Repo workflows: 54 files across 12 repos diff --git a/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/README.md b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/README.md new file mode 100644 index 00000000..7379f7f9 --- /dev/null +++ b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/README.md @@ -0,0 +1,9 @@ +# Effo Rise AI — Windsurf Workflows + +This directory contains Windsurf workflow definitions for the Effo Rise AI project. + +## Available Workflows + +| Workflow | Description | +| ----------------------- | ----------------------------------------- | +| `/refresh-chat-history` | Refresh the Windsurf chat history archive | diff --git a/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/refresh-chat-history.md b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/refresh-chat-history.md new file mode 100644 index 00000000..82d67cb0 --- /dev/null +++ b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/refresh-chat-history.md @@ -0,0 +1,17 @@ +--- +description: Refresh the Windsurf chat history archive +--- + +# Refresh Chat History + +This workflow is a placeholder for the Effo Rise AI project. Since this repo does not currently have a chat-history archive directory, this workflow is minimal. + +## Steps + +1. Confirm the repo is clean or commit pending changes first. + +```bash +cd /Users/sd9235/code/mygh/learning_ai_efforise && git status --short +``` + +2. No chat-history symlinks or archives to refresh for this repo at this time. diff --git a/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w1-scaffold-and-cleanup.md b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w1-scaffold-and-cleanup.md new file mode 100644 index 00000000..f99ee312 --- /dev/null +++ b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w1-scaffold-and-cleanup.md @@ -0,0 +1,125 @@ +--- +description: 'Window 1: Phase 0 scaffolding + Manus cleanup (RUN FIRST — other windows depend on this)' +--- + +# Window 1: Phase 0 Scaffolding + Manus Cleanup + +> **MUST complete before starting Window 2 or Window 3.** +> **Scope:** Root files, `shared/`, `vite.config.ts`, config files. Do NOT create `backend/` or `mobile/`. +> **Reference:** `docs/ECOSYSTEM_ADAPTATION_ROADMAP.md` Sections 4 (Phase 0), 5, and 6. + +## Context + +This repo (`learning_ai_efforise`) is a Vite + React 19 SPA built by Manus.computer. It needs ecosystem scaffolding before any feature work. The product is **EffoRise** — an identity-based habit tracker. Product ID: `efforise`, backend port: 4020, web port: 3080. + +## Step 1: Create Product Identity + +Create `shared/product.json` following the ecosystem pattern. Use NoteLett (`../learning_ai_notes/shared/product.json`) or ActionTrail (`../learning_ai_trails/shared/product.json`) as reference. Key fields: + +```json +{ + "productId": "efforise", + "productName": "EffoRise", + "displayName": "EffoRise", + "description": "Identity-based habit tracker — rise with efforts", + "domain": "efforise.app", + "version": "0.1.0", + "ports": { + "backend": 4020, + "web": 3080 + }, + "bundleIds": { + "ios": "com.saravana.efforise", + "android": "com.saravana.efforise" + }, + "platforms": ["web", "mobile"], + "tokenPrefix": "--er-", + "ecosystem": "bytelyst" +} +``` + +## Step 2: Create Agent Config Files (8 files) + +Create all 8 agent config files matching ecosystem standard. Copy structure from `../learning_ai_notes/` or `../learning_ai_trails/`: + +1. `AGENTS.md` — AI agent onboarding guide (customize for efforise: Vite SPA + Fastify backend, productId efforise, port 4020, --er-\* tokens) +2. `CLAUDE.md` — Claude Code instructions (short version pointing to AGENTS.md) +3. `.windsurfrules` — Windsurf rules (short version pointing to AGENTS.md) +4. `.cursorrules` — Cursor rules (short version pointing to AGENTS.md) +5. `.clinerules` — Cline rules (short version pointing to AGENTS.md) +6. `.aider.conf.yml` — Aider config +7. `.editorconfig` — Copy from any ecosystem repo +8. `.github/copilot-instructions.md` — GitHub Copilot rules + +## Step 3: Create Root Config Files + +1. Add `.nvmrc` with content `22` +2. Update `packageManager` in `package.json` to `"pnpm@10.6.5"` +3. Add `.npmrc` — copy from `../learning_ai_notes/.npmrc` (Gitea registry config) +4. Add `.npmrc.docker` — copy from `../learning_ai_notes/.npmrc.docker` +5. Add `pnpm-workspace.yaml`: + ```yaml + packages: + - backend + ``` +6. Add `.husky/pre-commit` and `.husky/pre-push` — copy from `../learning_ai_notes/.husky/` +7. Add `scripts/secret-scan-repo.sh` and `scripts/secret-scan-staged.sh` — copy from `../learning_ai_notes/scripts/` +8. Add `.dockerignore` — copy from `../learning_ai_notes/.dockerignore` +9. Add `eslint.config.js` at root — ESLint 9 flat config + +## Step 4: Manus Artifact Cleanup + +### 4a. Clean `vite.config.ts` + +- Remove `vite-plugin-manus-runtime` plugin +- Remove `vite-plugin-manus-debug-collector` plugin + all LOG_DIR code +- Remove `@builder.io/vite-plugin-jsx-loc` plugin +- Replace `allowedHosts: [".manuspre.computer", ...]` with `allowedHosts: ["localhost"]` + +### 4b. Delete Manus Files + +- Delete `client/src/components/ManusDialog.tsx` +- Delete `client/src/components/Map.tsx` (Google Maps boilerplate, 156 lines) +- Delete `client/public/__manus__/` directory (contains `debug-collector.js`) +- Delete `client/public/images/` (empty dir, referenced `identity-tree.png` never existed) +- Delete `report.txt` (root — Manus project report) +- Delete `server/` directory entirely (Express static server — replaced by backend/ in Phase 1) +- Delete `shared/const.ts` (Manus OAuth constants — `COOKIE_NAME`, `ONE_YEAR_MS`) +- Delete `patches/wouter@3.7.1.patch` (evaluate first — remove if not critical) + +### 4c. Clean `client/index.html` + +- Remove `VITE_ANALYTICS_ENDPOINT` / `VITE_ANALYTICS_WEBSITE_ID` script references + +### 4d. Dependency Cleanup in `package.json` + +- **Downgrade** `zod` from `^4.1.12` → `^3.24.2` (CRITICAL — Zod 4 breaks @bytelyst/\* integration) +- **Upgrade** `typescript` from `5.6.3` → `^5.7.3` +- **Remove:** `streamdown`, `cmdk`, `add` (devDep), `@types/google.maps` (devDep), `next-themes` +- **Remove:** `express`, `@types/express` (server/ is deleted) +- **Remove** Manus vite plugins from devDeps: `vite-plugin-manus-runtime`, `@builder.io/vite-plugin-jsx-loc` + +### 4e. Move Files + +- Move `ideas.md` → `docs/ideas.md` + +## Step 5: Create README.md + +Write a proper README.md with: + +- Product name + description +- Tech stack (Vite + React 19 SPA, Fastify 5 backend planned) +- Setup instructions (`pnpm install`, `pnpm dev`) +- Port assignments (backend: 4020, web: 3080) +- Link to `docs/ECOSYSTEM_ADAPTATION_ROADMAP.md` + +## Step 6: Verify + +- Run `pnpm install` to verify lock file generates cleanly +- Run `pnpm dev` to verify the Vite SPA still works after cleanup +- Commit: `chore(scaffold): Phase 0 product identity + ecosystem scaffolding` +- Commit: `chore(cleanup): remove Manus artifacts and fix dependencies` + +## Done Signal + +When complete, tell the user: **"Window 1 complete. You can now start Window 2 (backend) and Window 3 (web) in parallel."** diff --git a/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w2-backend-scaffold.md b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w2-backend-scaffold.md new file mode 100644 index 00000000..4af2827c --- /dev/null +++ b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w2-backend-scaffold.md @@ -0,0 +1,255 @@ +--- +description: 'Window 2: Backend scaffold + domain modules (Phase 1 + Phase 3 — start AFTER Window 1 completes)' +--- + +# Window 2: Backend Scaffold + Domain Modules + +> **Prerequisites:** Window 1 must be complete (product identity, pnpm-workspace, .npmrc exist). +> **Scope:** `backend/` directory ONLY. Do NOT modify `client/`, `mobile/`, root config files, or `shared/`. +> **Reference:** `docs/ECOSYSTEM_ADAPTATION_ROADMAP.md` Sections 4 (Phase 1, Phase 3). +> **Scaffold reference repos:** `../learning_ai_notes/backend/`, `../learning_ai_trails/backend/`, `../learning_ai_flowmonk/backend/` + +## Context + +EffoRise is an identity-based habit tracker. Product ID: `efforise`, backend port: 4020. The backend follows the standard ByteLyst product-backend pattern: Fastify 5 + TypeScript ESM + `@bytelyst/*` shared packages + Zod validation. + +All `@bytelyst/*` packages come from the Gitea npm registry (configured in root `.npmrc`). Use `@bytelyst/datastore` with `DB_PROVIDER=memory` for local dev (no Cosmos needed). + +--- + +## Phase 1: Backend Scaffold + +### Step 1: Create `backend/package.json` + +Copy structure from `../learning_ai_notes/backend/package.json`. Key deps: + +**dependencies:** + +- `@bytelyst/fastify-core`, `@bytelyst/config`, `@bytelyst/errors`, `@bytelyst/datastore` +- `@bytelyst/cosmos`, `@bytelyst/auth`, `@bytelyst/fastify-auth`, `@bytelyst/backend-config` +- `@bytelyst/backend-telemetry`, `@bytelyst/backend-flags`, `@bytelyst/field-encrypt` +- `@bytelyst/logger`, `fastify`, `zod` (^3.24.2), `jose` + +**devDependencies:** + +- `typescript` (^5.7.3), `tsx`, `vitest`, `eslint` (^9.0.0), `@bytelyst/testing` + +**scripts:** + +- `"dev": "tsx watch src/server.ts"` +- `"build": "tsc"` +- `"typecheck": "tsc --noEmit"` +- `"test": "vitest run"` +- `"start": "node dist/server.js"` + +### Step 2: Create `backend/tsconfig.json` + +Extend `../../tsconfig.base.json` if available, otherwise use ecosystem standard: + +```json +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "resolveJsonModule": true + }, + "include": ["src/**/*.ts"], + "exclude": ["src/**/*.test.ts", "dist"] +} +``` + +### Step 3: Create `backend/src/lib/` Files + +Create these standard lib files (copy patterns from `../learning_ai_notes/backend/src/lib/`): + +1. **`product-config.ts`** — Read `../../shared/product.json`, export `productConfig`, `PRODUCT_ID` +2. **`config.ts`** — Zod env schema (PORT=4020, HOST, NODE_ENV, DB_PROVIDER, JWT_SECRET, CORS_ORIGIN, COSMOS_ENDPOINT, COSMOS_KEY, COSMOS_DATABASE) +3. **`auth.ts`** — Re-export JWT extraction from `@bytelyst/auth` or `@bytelyst/fastify-auth` +4. **`request-context.ts`** — `getUserId(req)`, `getRequestProductId(req)` helpers +5. **`errors.ts`** — Re-export from `@bytelyst/errors` +6. **`datastore.ts`** — `@bytelyst/datastore` provider init (Cosmos or memory via `DB_PROVIDER`) +7. **`cosmos-init.ts`** — Register all Cosmos containers on startup (effo_identities, effo_efforts, effo_habits, effo_streaks, effo_insights) +8. **`field-encrypt.ts`** — Field encryption singleton from `@bytelyst/field-encrypt` +9. **`telemetry.ts`** — Telemetry event buffer stub from `@bytelyst/backend-telemetry` +10. **`feature-flags.ts`** — Feature flag registry stub from `@bytelyst/backend-flags` + +### Step 4: Create `backend/src/server.ts` + +Fastify entrypoint using `createServiceApp()` from `@bytelyst/fastify-core`: + +- Register CORS, auth, health endpoint +- Register cosmos-init on startup +- Register route modules (added in Phase 3) +- `startService()` on port 4020 + +### Step 5: Create `backend/src/diagnostics.test.ts` + +Standard diagnostic health-check test (copy from any ecosystem backend). + +### Step 6: Create Config Files + +- `backend/.env.example` — All env vars with defaults +- `backend/.gitignore` — `dist/`, `node_modules/`, `.env` +- `backend/eslint.config.js` — ESLint 9 flat config (copy from `../learning_ai_notes/backend/`) +- `backend/vitest.config.ts` — Vitest config +- `backend/Dockerfile` — Multi-stage Fastify build (copy from `../learning_ai_notes/backend/Dockerfile`) + +### Step 7: Add Vite Proxy + +Add to `vite.config.ts` (in the root, this is the ONE root file you may touch): + +```ts +server: { + proxy: { + '/api': 'http://localhost:4020' + } +} +``` + +### Step 8: Verify Phase 1 + +```bash +cd backend && pnpm install && pnpm run typecheck && pnpm run build && pnpm test +``` + +Commit: `feat(backend): Phase 1 backend scaffold with Fastify 5 + @bytelyst/* packages` + +--- + +## Phase 3: Domain Modules + +### Module Pattern + +Each module lives in `backend/src/modules//` with three files: + +- `types.ts` — Zod schemas + TypeScript types, Cosmos doc shape +- `repository.ts` — CRUD operations via `@bytelyst/datastore` `getCollection()` +- `routes.ts` — Fastify route handlers with Zod validation +- `routes.test.ts` — Vitest tests using `buildTestApp()` pattern + +Every Cosmos document MUST include `productId: "efforise"`. + +### Module 1: `identities` + +Container: `effo_identities`, partition: `/userId` + +| Field | Type | Description | +| ----------- | ---------- | ------------------------- | +| id | string | UUID | +| userId | string | Owner | +| productId | "efforise" | Required | +| name | string | "Writer", "Athlete", etc. | +| parentId | string? | For tree structure | +| description | string | What this identity means | +| color | string | Accent color | +| icon | string | Emoji or icon key | +| order | number | Sort order | +| createdAt | string | ISO timestamp | +| updatedAt | string | ISO timestamp | + +Routes: GET /api/identities, POST /api/identities, GET /api/identities/:id, PATCH /api/identities/:id, DELETE /api/identities/:id, PATCH /api/identities/:id/reorder + +### Module 2: `efforts` + +Container: `effo_efforts`, partition: `/userId` + +| Field | Type | Description | +| --------------- | ----------------------------- | ----------------------------------- | +| id | string | UUID | +| userId | string | Owner | +| productId | "efforise" | Required | +| identityId | string | Which identity this effort supports | +| habitId | string? | Optional link to habit | +| type | "micro" \| "medium" \| "deep" | Effort depth | +| description | string | What was done | +| durationMinutes | number? | Optional duration | +| loggedAt | string | When the effort happened | +| createdAt | string | ISO timestamp | + +Routes: GET /api/efforts, POST /api/efforts, GET /api/efforts/:id, PATCH /api/efforts/:id, DELETE /api/efforts/:id, GET /api/efforts/stats (aggregation) + +### Module 3: `habits` + +Container: `effo_habits`, partition: `/userId` + +| Field | Type | Description | +| ------------ | ------------------------------- | ------------------------------------- | +| id | string | UUID | +| userId | string | Owner | +| productId | "efforise" | Required | +| identityId | string | Which identity this habit supports | +| name | string | "Write 500 words", "Run 3 miles" | +| frequency | "daily" \| "weekly" \| "custom" | How often | +| customDays | number[]? | If frequency=custom, which days (0-6) | +| targetCount | number | Times per period | +| reminderTime | string? | HH:MM for push notification | +| isActive | boolean | Can be paused | +| createdAt | string | ISO timestamp | +| updatedAt | string | ISO timestamp | + +Routes: GET /api/habits, POST /api/habits, GET /api/habits/:id, PATCH /api/habits/:id, DELETE /api/habits/:id + +### Module 4: `streaks` + +Container: `effo_streaks`, partition: `/userId` + +| Field | Type | Description | +| ---------------- | ---------- | ------------------------ | +| id | string | UUID | +| userId | string | Owner | +| productId | "efforise" | Required | +| habitId | string | Which habit | +| currentStreak | number | Current consecutive days | +| longestStreak | number | All-time record | +| lastLogDate | string | YYYY-MM-DD | +| totalCompletions | number | All-time count | +| updatedAt | string | ISO timestamp | + +Routes: GET /api/streaks, GET /api/streaks/:habitId, POST /api/streaks/:habitId/log (increment) + +### Module 5: `insights` + +Container: `effo_insights`, partition: `/userId` + +| Field | Type | Description | +| ------------------ | --------------------------------------------- | -------------------------- | +| id | string | UUID | +| userId | string | Owner | +| productId | "efforise" | Required | +| type | "weekly_summary" \| "coaching" \| "milestone" | Insight type | +| title | string | Display title | +| body | string | Insight content (markdown) | +| relatedIdentityIds | string[] | Referenced identities | +| generatedAt | string | ISO timestamp | +| dismissedAt | string? | If user dismissed | + +Routes: GET /api/insights, GET /api/insights/:id, POST /api/insights/:id/dismiss + +### Step: Register All Modules + +Update `server.ts` to register all 5 route modules. Update `cosmos-init.ts` to register all 5 containers. + +### Step: Create `backend/src/test-helpers.ts` + +Standard `buildTestApp()` helper for Vitest (copy pattern from `../learning_ai_notes/backend/src/test-helpers.ts`). + +### Verify Phase 3 + +```bash +cd backend && pnpm run typecheck && pnpm test && pnpm run build +``` + +Commit: `feat(backend): Phase 3 domain modules — identities, efforts, habits, streaks, insights` + +--- + +## Done Signal + +When complete, tell the user: **"Window 2 complete. Backend with 5 domain modules is ready. Window 3 can now build web screens against these APIs. Window 5 (mobile) can also start."** diff --git a/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w3-web-and-devops.md b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w3-web-and-devops.md new file mode 100644 index 00000000..bf7c09a8 --- /dev/null +++ b/__LOCAL_LLMs/AI_IDE_CHAT_HISTORY/WINDSURF/repo_workflows/learning_ai_efforise/w3-web-and-devops.md @@ -0,0 +1,278 @@ +--- +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(path: string, options?: RequestInit): Promise { + 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 `` 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."** diff --git a/packages/design-tokens/bytelyst-design-tokens-0.1.0.tgz b/packages/design-tokens/bytelyst-design-tokens-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c526e95f8a84bd8f57484804c479f34ca0536e7f GIT binary patch literal 29482 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 H0DuDk4NovM literal 0 HcmV?d00001