Appearance
Agent Setup — CLAUDE.md, MCP & Debug Config
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Bootstrap all agent-context files so Claude (and future engineers) have zero-ambiguity guidance when working in any sub-project of Avelia.
Architecture: Root CLAUDE.md gives project-wide context; each sub-project has its own CLAUDE.md with precise tech-stack, commands, conventions, and testing rules. MCP servers are declared at the project root. VS Code launch/settings files enable one-click debugging.
Tech Stack: NestJS 10, TypeScript 5, PostgreSQL 16, Prisma 5, Flutter 3, Dart 3, Riverpod 2 (code-gen), go_router, Freezed, Dio, Jest, MCP (Puppeteer, Dart).
Task 1: Root CLAUDE.md
Files:
- Create:
CLAUDE.md
Step 1: Write the file
markdown
# Avelia — Project Root
Avelia is a **privacy-first mobile companion app** for couples navigating the journey from pre-conception through early childhood (7 life stages). Each partner has their own account; every data entry is explicitly private or shared — nothing crosses that line without intent.
## Repository Structure
| Path | What lives here |
|------|----------------|
| `avelia-flutter-app/` | Flutter mobile app (iOS + Android) |
| `avelia-backend/` | NestJS REST API (auth, sync, partner linking) |
| `docs/` | Product spec, design docs, implementation plans |
| `design/` | UI/UX assets |
## Sub-project Guides
- **Backend:** `avelia-backend/CLAUDE.md`
- **Flutter app:** `avelia-flutter-app/CLAUDE.md`
## Key Reference
- `docs/avelia-product-spec.md` — Complete product specification (read this first)
- `docs/plans/` — Implementation plans (named `YYYY-MM-DD-<feature>.md`)
## MCP Servers
Configured in `.claude/settings.json`:
| Server | Purpose |
|--------|---------|
| `puppeteer` | Browser automation for integration testing |
| `dart` | Flutter/Dart tooling (pub, analysis, test runner) |
## Core Principles (from spec)
1. **Private by default** — backend enforces privacy at the service layer; partner cannot read private entries, not even their existence
2. **Stage-aware** — 7 life stages; UI adapts but no features are locked
3. **E2E encrypted sync** — backend stores opaque ciphertext; it cannot read synced data
4. **No analytics, no ads, no third-party SDKs**
## Cross-cutting Conventions
- All secrets in `.env` (never committed); see `.env.example` in each sub-project
- Prefer explicit over implicit — no magic strings, no undocumented side effects
- Every feature starts with a failing test (TDD)
- Commit messages: `type(scope): description` — e.g. `feat(auth): add refresh token rotation`Step 2: Verify it exists
Run: ls CLAUDE.md Expected: CLAUDE.md
Step 3: Commit
bash
git add CLAUDE.md
git commit -m "docs: add root CLAUDE.md with project context"Note: Project root has no git repo yet — skip commit step if git is not yet initialised. Init with
git initfirst if desired.
Task 2: MCP Server Config
Files:
- Create:
.claude/settings.json
Step 1: Create the .claude directory and settings file
json
{
"mcpServers": {
"puppeteer": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"],
"env": {
"PUPPETEER_LAUNCH_OPTIONS": "{\"headless\": true}"
}
},
"dart": {
"command": "dart",
"args": ["pub", "global", "run", "mcp_server"],
"env": {}
}
}
}Note on Dart MCP: The
mcp_serverpackage is a community Dart MCP server. Install it with:dart pub global activate mcp_serverIf the package name differs in your environment, updateargsaccordingly. Alternatively, useflutter_mcpif available on pub.dev at time of setup.
Step 2: Verify
Run: cat .claude/settings.json Expected: valid JSON with two server entries.
Step 3: Commit
bash
git add .claude/settings.json
git commit -m "chore: add MCP server config (puppeteer, dart)"Task 3: Backend CLAUDE.md
Files:
- Create:
avelia-backend/CLAUDE.md
Step 1: Write the file
markdown
# Avelia Backend — NestJS API
REST API serving the Avelia mobile app. Responsibilities: JWT authentication (access + refresh), partner account linking via invite codes, privacy-enforced entry sync (E2E encrypted), and push notification delivery.
## Tech Stack
| Layer | Technology |
|-------|-----------|
| Runtime | Node.js 20 LTS |
| Language | TypeScript 5 (strict mode) |
| Framework | NestJS 10 |
| Database | PostgreSQL 16 |
| ORM | Prisma 5 |
| Auth | JWT (access 15 min / refresh 7 days) + bcrypt |
| Validation | class-validator + class-transformer |
| Testing | Jest + Supertest + jest-mock-extended |
| Linting | ESLint (typescript-eslint/recommended-requiring-type-checking) + Prettier |
## Commands
```bash
# Development
npm run start:dev # Dev server with hot reload (port 3000)
npm run start:debug # Debug mode — Node inspector on port 9229
# Testing
npm run test # Unit tests (watch off)
npm run test:watch # Unit tests in watch mode
npm run test:e2e # E2E tests (requires running DB)
npm run test:cov # Coverage report (target: ≥80% statements)
# Database
npm run prisma:migrate # Apply pending migrations (dev)
npm run prisma:migrate:deploy # Apply migrations (production/CI)
npm run prisma:studio # Open Prisma Studio GUI (port 5555)
npm run prisma:generate # Regenerate Prisma client after schema change
# Build
npm run build # Compile to dist/
npm run start:prod # Run compiled build
npm run lint # Lint + auto-fix
npm run format # Prettier formatModule Architecture
src/
auth/ # JWT strategy, guards, login/register/refresh endpoints
auth.module.ts
auth.service.ts
auth.controller.ts
strategies/
jwt.strategy.ts
jwt-refresh.strategy.ts
guards/
jwt-auth.guard.ts
users/ # User CRUD, profile management
users.module.ts
users.service.ts
users.controller.ts
partners/ # Invite code generation, partner linking/unlinking
partners.module.ts
partners.service.ts
partners.controller.ts
entries/ # Log entries with private/shared toggle
entries.module.ts
entries.service.ts
entries.controller.ts
sync/ # Receive and serve E2E encrypted sync payloads
sync.module.ts
sync.service.ts
sync.controller.ts
common/
decorators/ # @CurrentUser(), @Public()
filters/ # GlobalExceptionFilter
interceptors/ # ResponseTransformInterceptor
pipes/ # ValidationPipe (global)
dto/ # Shared DTOs
prisma/
prisma.module.ts
prisma.service.ts # PrismaService extends PrismaClient
app.module.ts
main.ts
prisma/
schema.prisma # Source of truth for DB schema
migrations/ # Generated — never edit manuallyKey Conventions
Privacy enforcement
entries.service.tsMUST filter byuserIdon every query — never return another user's private entries- Partner visibility:
entry.visibility === 'SHARED' && entry.userId === partner.idonly - Never expose
userIdor internal IDs in API responses — usecuid-based public IDs
DTOs and validation
- Every controller method must have a typed DTO (
CreateEntryDto,UpdateEntryDto, etc.) - Use
@IsEnum(),@IsNotEmpty(),@IsOptional()— no rawany - Global
ValidationPipe({ whitelist: true, forbidNonWhitelisted: true })inmain.ts
Error handling
- Throw
HttpExceptionsubclasses only:NotFoundException,UnauthorizedException,ConflictException, etc. - Never throw raw
Errorin services — callers won't know what status code to return GlobalExceptionFiltercatches unknown errors and returns 500 without leaking stack traces
Auth
- Access token: 15-minute lifespan, carried in
Authorization: Bearer <token>header - Refresh token: 7-day lifespan, stored hashed in DB, rotated on every use
@Public()decorator opts a route out of the globalJwtAuthGuard
Prisma
- Always inject
PrismaService(not the raw client) so the connection pool is shared - Use
prisma.$transaction([...])for any operation touching ≥2 tables - After editing
schema.prisma, runprisma:generatebefore building
Testing Approach
- Unit tests (
*.spec.ts): mockPrismaServicewithjest-mock-extended; test service logic in isolation - E2E tests (
test/*.e2e-spec.ts): spin up a real NestJS app against a test DB; reset withprisma migrate reset --forcebefore suite - Coverage gate: CI fails below 80% statement coverage on
src/ - Test file mirrors source:
src/auth/auth.service.ts→src/auth/auth.service.spec.ts
Environment Variables
Copy .env.example to .env. Never commit .env.
| Variable | Example | Description |
|---|---|---|
DATABASE_URL | postgresql://avelia:pw@localhost:5432/avelia_dev | Prisma connection string |
JWT_SECRET | <random 64-char hex> | Access token signing secret |
JWT_REFRESH_SECRET | <random 64-char hex> | Refresh token signing secret |
JWT_EXPIRES_IN | 15m | Access token TTL |
JWT_REFRESH_EXPIRES_IN | 7d | Refresh token TTL |
PORT | 3000 | HTTP server port |
NODE_ENV | development | development / production / test |
Debugging
VS Code: open avelia-backend/ as workspace root, then use the "Debug NestJS" launch config. It starts the server in --inspect mode and attaches automatically. Breakpoints in .ts files work via source maps.
Alternatively, run npm run start:debug then use the "Attach to NestJS" config to connect to port 9229 from a running instance.
**Step 2: Verify**
Run: `ls avelia-backend/CLAUDE.md`
Expected: file exists.
**Step 3: Commit**
```bash
git add avelia-backend/CLAUDE.md
git commit -m "docs: add avelia-backend CLAUDE.md (NestJS + Prisma conventions)"Task 4: Backend .env.example
Files:
- Create:
avelia-backend/.env.example
Step 1: Write the file
bash
# Avelia Backend — Environment Variables
# Copy to .env and fill in values. Never commit .env.
# Database
DATABASE_URL="postgresql://avelia:changeme@localhost:5432/avelia_dev"
# JWT
JWT_SECRET="replace-with-64-char-random-hex"
JWT_REFRESH_SECRET="replace-with-different-64-char-random-hex"
JWT_EXPIRES_IN="15m"
JWT_REFRESH_EXPIRES_IN="7d"
# Server
PORT=3000
NODE_ENV=developmentStep 2: Commit
bash
git add avelia-backend/.env.example
git commit -m "chore(backend): add .env.example with all required variables"Task 5: Backend VS Code Debug Config
Files:
- Create:
avelia-backend/.vscode/launch.json - Create:
avelia-backend/.vscode/settings.json
Step 1: Write launch.json
json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug NestJS",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start:debug"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"sourceMaps": true,
"envFile": "${workspaceFolder}/.env"
},
{
"name": "Attach to NestJS",
"type": "node",
"request": "attach",
"port": 9229,
"restart": true,
"sourceMaps": true,
"localRoot": "${workspaceFolder}",
"remoteRoot": "${workspaceFolder}"
},
{
"name": "Run Unit Tests (Debug)",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "test", "--", "--runInBand", "--no-coverage"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"envFile": "${workspaceFolder}/.env"
}
]
}Step 2: Write settings.json
json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"jest.jestCommandLine": "npm run test --",
"jest.autoRun": "off"
}Step 3: Commit
bash
git add avelia-backend/.vscode/
git commit -m "chore(backend): add VS Code debug and workspace settings"Task 6: Flutter CLAUDE.md
Files:
- Create:
avelia-flutter-app/CLAUDE.md
Step 1: Write the file
markdown
# Avelia Flutter App
Cross-platform mobile app (iOS + Android) for Avelia. Privacy-first, offline-first: all data is stored on-device first; cloud sync is optional and E2E encrypted. The UI adapts to the user's current life stage (7 stages) without locking any feature.
## Tech Stack
| Layer | Package / Tool |
|-------|---------------|
| Language | Dart 3 (sound null safety) |
| Framework | Flutter 3.x |
| State management | Riverpod 2 (`flutter_riverpod`, `riverpod_annotation`) |
| Code generation | `build_runner` + `riverpod_generator` + `freezed` + `json_serializable` |
| Navigation | `go_router` |
| HTTP client | `dio` + `retrofit` |
| Local storage | `drift` (SQLite ORM) — mirrors Room on Android / CoreData on iOS |
| Secure storage | `flutter_secure_storage` (tokens, encryption key) |
| Biometrics | `local_auth` |
| Testing | `flutter_test`, `mocktail`, `patrol` (E2E) |
| Linting | `flutter_lints` + custom `analysis_options.yaml` |
## Commands
```bash
# Development
flutter run # Run on connected device/emulator (debug)
flutter run --flavor staging # Run staging flavor
flutter run -d chrome # Run in Chrome (web, dev only)
# Code generation (run after editing annotated files)
dart run build_runner build --delete-conflicting-outputs
dart run build_runner watch # Continuous watch mode
# Testing
flutter test # All unit + widget tests
flutter test --coverage # With coverage (output: coverage/lcov.info)
flutter test test/features/auth/ # Single feature
dart run patrol test # E2E/integration tests (requires device)
# Build
flutter build apk --release # Android APK
flutter build ios --release # iOS (requires macOS + Xcode)
flutter build appbundle --release # Android App Bundle (Play Store)
# Analysis
flutter analyze # Static analysis
dart fix --apply # Auto-fix lint issues
dart format . # Format all Dart filesArchitecture
Feature-first folder structure. Each feature is self-contained.
lib/
features/
auth/
data/
auth_repository.dart # implements AuthRepository (abstract)
auth_api.dart # Retrofit API interface
dtos/
login_request.dto.dart
auth_response.dto.dart
domain/
auth_repository.dart # Abstract interface
models/
user.dart # @freezed data class
presentation/
screens/
login_screen.dart
widgets/
auth_form.dart
providers/
auth_provider.dart # @riverpod providers
entries/
... # Same structure
home/
journal/
guide/
us/ # Partner shared view
settings/
core/
router/
app_router.dart # go_router configuration
network/
dio_client.dart # Dio setup (interceptors, base URL)
api_client.dart # Retrofit client
storage/
database.dart # Drift database
secure_storage.dart # flutter_secure_storage wrapper
auth/
auth_interceptor.dart # Attaches JWT, handles 401 refresh
theme/
app_theme.dart
app_colors.dart
app_text_styles.dart
shared/
widgets/ # Reusable widgets (buttons, inputs, etc.)
extensions/ # Dart extension methods
utils/
main.dart
bootstrap.dart # ProviderScope + runApp
test/
features/ # Mirrors lib/features/
helpers/
test_providers.dart # Override providers in tests
integration_test/
app_test.dart # Patrol E2E testsKey Conventions
Riverpod
- Use
@riverpodannotation (code-gen) — no manualProvider()declarations - Keep providers in
presentation/providers/for screen-level state;domain/for business logic - Use
ref.watchin build methods;ref.readin callbacks/event handlers only - Override providers in tests via
ProviderContainerwithoverrides: [...]
Models
- All domain models use
@freezed— gives copyWith, equality, pattern matching for free - DTOs (API in/out) use
@JsonSerializable— kept separate from domain models - Conversion: DTO → domain model in the repository layer; never pass DTOs to the UI
Navigation
- All routes defined in
core/router/app_router.dart - Use
context.go('/path')(notNavigator.push) - Guards (
redirect) check auth state viaref.read(authStateProvider)
Privacy
- Every
Entrymodel has avisibilityfield (Visibility.private|Visibility.shared) - UI shows private entries only to the owner; shared entries visible to linked partner
- The private/shared toggle must be present on every log entry UI — no implicit defaults in UI
Error handling
- Repositories return
AsyncValue<T>orEither<Failure, T>— never throw from repositories - UI uses
.when(data:, loading:, error:)on AsyncValue providers - Show user-facing error messages via
ScaffoldMessenger— no raw exception messages exposed
Theming
- All colours from
AppColors— no hardcoded hex values in widgets - All text styles from
AppTextStyles— no hardcodedTextStyle(...)in widgets - Support light and dark mode from day 1
Testing Approach
- Unit tests (
test/): test services, repositories, providers in isolation usingmocktailmocks - Widget tests (
test/): useProviderScopewith overridden providers; never hit real network - E2E tests (
integration_test/):patrolagainst a real device/emulator with a test backend - Test file mirrors source:
lib/features/auth/domain/auth_repository.dart→test/features/auth/domain/auth_repository_test.dart
Debugging
VS Code: use the "Avelia (Debug)" launch config. Ensure a device/emulator is running first (flutter devices).
For hot reload: press r in the terminal; hot restart: R.
Flutter DevTools (performance, widget inspector, network):
bash
dart devtoolsThen open the printed URL in Chrome.
**Step 2: Verify**
Run: `ls avelia-flutter-app/CLAUDE.md`
Expected: file exists.
**Step 3: Commit**
```bash
git add avelia-flutter-app/CLAUDE.md
git commit -m "docs: add avelia-flutter-app CLAUDE.md (Riverpod, Drift, go_router conventions)"Task 7: Flutter VS Code Debug Config
Files:
- Create:
avelia-flutter-app/.vscode/launch.json - Create:
avelia-flutter-app/.vscode/settings.json
Step 1: Write launch.json
json
{
"version": "0.2.0",
"configurations": [
{
"name": "Avelia (Debug)",
"request": "launch",
"type": "dart",
"flutterMode": "debug",
"program": "lib/main.dart",
"args": ["--dart-define=ENV=development"]
},
{
"name": "Avelia (Profile)",
"request": "launch",
"type": "dart",
"flutterMode": "profile",
"program": "lib/main.dart"
},
{
"name": "Avelia (Release)",
"request": "launch",
"type": "dart",
"flutterMode": "release",
"program": "lib/main.dart"
},
{
"name": "Flutter Tests (Debug)",
"request": "launch",
"type": "dart",
"program": "test/",
"flutterMode": "debug"
}
]
}Step 2: Write settings.json
json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "Dart-Code.dart-code",
"editor.rulers": [100],
"dart.lineLength": 100,
"dart.flutterSdkPath": null,
"dart.runPubGetOnPubspecChanges": "always",
"[dart]": {
"editor.formatOnSave": true,
"editor.selectionHighlight": false,
"editor.suggest.snippetsPreventQuickSuggestions": false,
"editor.suggestSelection": "first",
"editor.tabCompletion": "onlySnippets",
"editor.wordBasedSuggestions": "off"
}
}Step 3: Commit
bash
git add avelia-flutter-app/.vscode/
git commit -m "chore(flutter): add VS Code debug and Dart workspace settings"Task 8: Save Memory
Files:
- Create:
/Users/antonanders/.claude/projects/-Volumes-exSSD-dev-baby-parents-app/memory/MEMORY.md
Step 1: Write MEMORY.md
markdown
# Avelia — Project Memory
## Project Overview
Privacy-first mobile app for couples (fertility → early childhood, 7 life stages).
Product spec: `docs/avelia-product-spec.md`
## Sub-projects
- `avelia-backend/` — NestJS 10 + PostgreSQL + Prisma 5 + JWT auth
- `avelia-flutter-app/` — Flutter 3 + Riverpod 2 (code-gen) + Drift + go_router
## Key Conventions
- Privacy enforced at service layer: partner never sees private entries
- E2E encrypted sync: backend stores ciphertext only
- Backend: DTOs + class-validator, HttpException hierarchy, Prisma.$transaction for multi-table ops
- Flutter: @freezed models, @riverpod code-gen, repositories return AsyncValue/Either (no throws)
- Commit style: `type(scope): description`
## MCP Servers
`.claude/settings.json` — Puppeteer + Dart MCP (dart pub global run mcp_server)
## Important Paths
- Product spec: `docs/avelia-product-spec.md`
- Plans: `docs/plans/`
- Backend env: `avelia-backend/.env.example`
- Backend debug: `avelia-backend/.vscode/launch.json`
- Flutter debug: `avelia-flutter-app/.vscode/launch.json`Step 2: Verify
Run: ls /Users/antonanders/.claude/projects/-Volumes-exSSD-dev-baby-parents-app/memory/MEMORY.md
Execution Summary
8 tasks total. All are file creation with no dependencies between tasks — can be run sequentially or in parallel.
No tests required for this plan (it is configuration/documentation only — no runnable code).
If a git repo doesn't yet exist in the project root, initialise with git init && git add -A && git commit -m "chore: initial project scaffold" before the per-task commits.