# LeoCRM — AGENTS.md

**Projekt:** leocrm
**Erstellt:** 2026-06-28
**Status:** Draft — ready for implementation

---

## 1. Build & Test Commands

### Backend (Python / FastAPI)

#### Setup
```bash
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```

#### Run Dev Server
```bash
cd backend
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```

#### Database Migrations (Alembic)
```bash
cd backend
# Generate migration after model changes
alembic revision --autogenerate -m "description"
# Apply migrations
alembic upgrade head
# Rollback one migration
alembic downgrade -1
```

#### Run All Backend Tests
```bash
cd backend
python -m pytest -v --tb=short
```

#### Run Specific Test File
```bash
cd backend
python -m pytest tests/test_auth.py -v --tb=short
```

#### Run Tests with Coverage
```bash
cd backend
python -m pytest --cov=app --cov-report=term-missing --cov-report=html
```

#### Run Tests with Grep Filter
```bash
cd backend
python -m pytest -k 'tenant or auth' -v
```

#### Type Checking
```bash
cd backend
mypy app/ --ignore-missing-imports
```

#### Linting
```bash
cd backend
ruff check app/
ruff format app/
```

### Frontend (React / Vite / TypeScript)

#### Setup
```bash
cd frontend
npm install
```

#### Run Dev Server
```bash
cd frontend
npm run dev
```

#### Build Production
```bash
cd frontend
npm run build
```

#### Run All Frontend Tests
```bash
cd frontend
npx vitest run --reporter=verbose
```

#### Run Tests with Coverage
```bash
cd frontend
npx vitest run --coverage
```

#### Run Tests in Watch Mode (dev)
```bash
cd frontend
npx vitest watch
```

#### Type Checking
```bash
cd frontend
npx tsc --noEmit
```

#### Linting
```bash
cd frontend
npx eslint src/ --ext .ts,.tsx
```

### Docker Compose (Full Stack)

#### Build All Services
```bash
docker compose build
```

#### Start All Services
```bash
docker compose up -d
```

#### View Logs
```bash
docker compose logs -f backend
```

#### Stop All Services
```bash
docker compose down
```

#### Validate Compose Config
```bash
docker compose config --quiet
```

### E2E Tests (Playwright)

```bash
cd e2e
npx playwright install
npx playwright test
```

---

## 2. Test Rules

### TDD (Test-Driven Development)

- **Red-Green-Refactor:** Write failing test first → implement minimum code to pass → refactor.
- **Every new endpoint gets a test BEFORE implementation.**
- **Every bug fix starts with a reproduction test.**

### Coverage Targets

| Layer | Coverage Target | Measured By |
|-------|----------------|-------------|
| Backend Core (app/core/) | 85% | pytest-cov |
| Backend Models+Services | 85% | pytest-cov |
| Backend Routes | 85% | pytest-cov |
| Backend Plugins | 80% | pytest-cov |
| Frontend Components | 75% | vitest coverage |
| Frontend Plugin UI | 70% | vitest coverage |
| E2E (critical paths) | 100% of defined specs | Playwright |

### Test File Structure

#### Backend
```
backend/tests/
├── conftest.py              — Fixtures: test client, test DB, auth helpers, seed data
├── test_auth.py             — Auth endpoints, RBAC, password reset
├── test_tenant.py           — Tenant isolation, cross-tenant access
├── test_companies.py        — Company CRUD, search, filter, pagination, soft-delete
├── test_contacts.py         — Contact CRUD, N:M links, GDPR delete
├── test_import_export.py   — CSV import/export, XLSX export, dry-run preview
├── test_plugins.py          — Plugin lifecycle, event bus, migrations
├── test_dms.py             — DMS folders, files, upload, shares, permissions
├── test_calendar.py        — Entries, recurrence, kanban, ICS, resources
├── test_mail.py            — Accounts, IMAP sync, send, threading, rules, PGP
├── test_tags.py            — Tag CRUD, assignment, bulk
├── test_notifications.py   — Notification CRUD, unread count
├── test_health.py          — Health endpoint
├── test_ai_copilot.py      — KI-Copilot API, RBAC enforcement, history
├── test_workflows.py       — Workflow CRUD, instances, approval/rejection, event triggers
├── test_monitoring.py     — Extended health, Prometheus metrics, alerting
└── test_performance.py    — 200k seed, list <500ms, FTS <500ms, streaming export
```

#### Frontend
```
frontend/src/__tests__/
├── components/             — UI component unit tests (Button, Input, Modal, Table, etc.)
├── features/               — Feature integration tests (CompanyList, ContactForm, etc.)
├── hooks/                 — Custom hook tests (useDebounce, usePagination, etc.)
├── plugins/               — Plugin UI tests (DMS, Calendar, Mail, Tags)
└── search/                — Global search tests
```

#### E2E
```
e2e/
├── auth.spec.ts            — Login → logout flow
├── company-crud.spec.ts    — Create → edit → delete company
├── contact-crud.spec.ts    — Create → link to company → delete
├── search.spec.ts          — Global search
└── plugin-toggle.spec.ts   — Activate/deactivate plugin
```

### Test Conventions

- **Test names:** `test_<action>_<condition>_<expected_result>` (e.g., `test_login_with_invalid_credentials_returns_401`)
- **Test structure:** Arrange → Act → Assert (AAA pattern)
- **Fixtures:** Use `conftest.py` for shared fixtures. No fixture duplication across files.
- **Test DB:** Use in-memory or ephemeral PostgreSQL (via testcontainers or pytest-postgresql). NEVER test against production DB.
- **Mocking:** Mock external services (SMTP, IMAP, OnlyOffice) in tests. Use `unittest.mock.AsyncMock` for async mocks.
- **Assertions:** Use pytest's native `assert` for backend, `expect()` from `@testing-library/jest-dom` for frontend.
- **No flaky tests:** Tests must be deterministic. Use explicit waits, not sleeps.
- **Test isolation:** Each test must be independent. No test depends on another test's side effects.

### Don't Modify Tests Rule

- **NEVER modify existing tests to make them pass.** If a test fails, fix the code, not the test.
- **Exception:** If the test itself is wrong (testing incorrect behavior), document why and get approval before changing.
- **Test files are owned by the QA process, not the implementer.**

---

## 3. Conventions

### Backend Structure

```
backend/app/
├── main.py                 — FastAPI app entry point, lifespan, middleware registration
├── config.py               — Pydantic Settings (reads from env vars)
├── deps.py                 — FastAPI dependency injection (auth, db, tenant, permissions)
├── core/                   — Core infrastructure (cross-cutting concerns)
│   ├── db/                 — SQLAlchemy engine, session factory, base model
│   ├── tenant.py           — TenantMixin, ORM auto-filter, tenant context
│   ├── auth.py             — Session auth, password hashing (bcrypt), RBAC
│   ├── event_bus.py        — Async in-process event bus
│   ├── service_container.py — DI container
│   ├── storage.py          — File storage (local/S3)
│   ├── cache.py            — Redis cache wrapper
│   ├── jobs.py             — ARQ job queue integration
│   ├── notifications.py    — Notification service
│   └── audit.py            — Audit log middleware
├── models/                 — SQLAlchemy ORM models (one file per domain)
├── schemas/                — Pydantic schemas (request/response, one file per domain)
├── services/               — Business logic (one file per domain)
├── routes/                  — FastAPI routers (one file per domain)
├── plugins/                — Plugin system
│   ├── registry.py         — Plugin discovery, registration
│   ├── manifest.py         — Plugin manifest Pydantic schema
│   ├── lifecycle.py        — Install/activate/deactivate/uninstall
│   ├── migrations.py       — Plugin DB migration runner
│   ├── ui_registry.py      — Plugin UI component registration
│   └── builtins/           — Built-in plugins
│       ├── dms/            — DMS plugin
│       ├── calendar/       — Calendar plugin
│       ├── mail/           — Mail plugin
│       └── tags/           — Tags plugin
└── utils/                  — Shared utilities (validation, export, import)
```

### Backend Naming Conventions

- **Files:** `snake_case.py` (e.g., `company_service.py`)
- **Classes:** `PascalCase` (e.g., `CompanyService`, `CompanyModel`)
- **Functions/Methods:** `snake_case` (e.g., `get_company_by_id`)
- **Constants:** `UPPER_SNAKE_CASE` (e.g., `SESSION_TIMEOUT_HOURS`)
- **Models:** `<Entity>Model` suffix or just `<Entity>` (e.g., `Company`, `Contact`)
- **Schemas:** `<Entity>Create`, `<Entity>Update`, `<Entity>Read`, `<Entity>List` (Pydantic)
- **Services:** `<Entity>Service` (e.g., `CompanyService`)
- **Routers:** `<entity>_router` variable, file name `<entity>_router.py`
- **Tests:** `test_<domain>.py` (e.g., `test_companies.py`)

### Backend Code Conventions

- **Async first:** All route handlers and service methods are `async def`.
- **Type hints:** All function signatures have type hints (Python 3.12+ syntax).
- **Docstrings:** All public functions/classes have docstrings (Google style).
- **Error handling:** Use FastAPI `HTTPException` with proper status codes. Never raise generic `Exception`.
- **Validation:** Pydantic schemas validate input. Never validate in routes directly.
- **Tenant scoping:** Never query without tenant filter (ORM auto-filter handles this, but be aware).
- **UUID:** All IDs are UUID. Never use integer auto-increment.
- **Timestamps:** All datetime fields are `TIMESTAMPTZ`. Never use naive datetime.
- **Soft-delete:** Use `deleted_at IS NULL` filter. Never hard-delete without explicit `gdpr=true` flag.
- **Audit:** All mutations must create audit log entries. Use the audit middleware/decorator.

### Frontend Structure

```
frontend/src/
├── main.tsx               — React entry point
├── App.tsx                — Root component, router, providers
├── api/                   — API client (axios), interceptors, endpoint definitions
├── components/            — Shared UI components
│   ├── layout/            — Shell, Sidebar, TopBar, ContentArea
│   ├── ui/               — Button, Input, Select, Modal, Toast, Table, Card, Badge, Avatar
│   └── shared/           — EmptyState, LoadingState, ConfirmDialog, Pagination, Skeleton
├── features/              — Feature modules (one folder per feature)
│   ├── auth/             — Login, PasswordReset
│   ├── companies/        — CompanyList, CompanyDetail, CompanyForm
│   ├── contacts/         — ContactList, ContactDetail, ContactForm
│   ├── settings/         — SettingsTree, ProfileSettings, RoleEditor
│   ├── audit/            — AuditLog
│   ├── dashboard/        — Dashboard
│   └── search/           — GlobalSearch
├── plugins/              — Plugin UI loading framework
│   ├── PluginRegistry.tsx — Fetch manifests, register components
│   └── PluginLoader.tsx   — Dynamic lazy-loading of plugin components
├── hooks/                 — Custom React hooks (useDebounce, usePagination, useAuth, etc.)
├── store/                 — Zustand stores (useAuthStore, useUIStore, useTenantStore)
├── i18n/                  — react-i18next setup + locale files (de.json, en.json)
├── styles/                — Global CSS, design tokens (Tailwind config), accessibility
└── utils/                 — Utilities (format, validation, export, constants)
```

### Frontend Naming Conventions

- **Files:** `PascalCase.tsx` for components (e.g., `CompanyList.tsx`), `camelCase.ts` for utilities (e.g., `apiClient.ts`)
- **Components:** `PascalCase` (e.g., `CompanyList`, `ContactForm`)
- **Hooks:** `use<Feature>` (e.g., `useDebounce`, `useAuth`)
- **Stores:** `use<Domain>Store` (e.g., `useAuthStore`, `useUIStore`)
- **Types/Interfaces:** `PascalCase` (e.g., `CompanyData`, `ContactFormValues`)
- **API functions:** `camelCase` (e.g., `getCompanies`, `createContact`)
- **Test files:** `<Component>.test.tsx` next to component or in `__tests__/` mirror

### Frontend Code Conventions

- **TypeScript strict:** `strict: true` in tsconfig.json. No `any` types.
- **Functional components:** Only function components, no class components.
- **Hooks:** Custom hooks for reusable logic. No inline hooks in JSX.
- **TanStack Query:** Server state via `useQuery` / `useMutation`. No manual fetch in components.
- **Zustand:** Client state only (UI toggles, theme, active tenant). No server data in Zustand.
- **React Hook Form + Zod:** All forms use `react-hook-form` with `zodResolver`.
- **Tailwind CSS:** No custom CSS files (except global + accessibility). Use Tailwind utility classes.
- **i18n:** All user-visible strings go through `t()` from `react-i18next`. No hardcoded strings.
- **Accessibility:** ARIA attributes on all interactive elements. 44px touch targets. Keyboard navigation.
- **Lazy loading:** Plugin components use `React.lazy()` with `Suspense` boundaries.

### Git Conventions

- **Branch naming:** `feature/T01-core-infrastructure`, `fix/auth-tenant-isolation`, `hotfix/critical-bug`
- **Commit messages:** Conventional Commits format:
  - `feat(core): implement auth system with session-based login`
  - `fix(dms): resolve folder permission bypass on move`
  - `test(mail): add IMAP sync integration tests`
  - `refactor(calendar): extract recurrence engine to separate module`
  - `docs(architecture): update ADR-03 with plugin lifecycle details`
- **PR titles:** `[T01] Core Infrastructure + Multi-Tenant + Auth System`
- **Branch from:** `main` (or feature branch for sub-features)
- **Merge strategy:** Squash merge to `main` after review + CI passes

---

## 4. Task-Zuweisung (Subagenten pro Task)

### Phasen-Plan

#### v1 Core Phases (Phase 3 — Implementation)

| Phase | Tasks | Parallel | Subagent Profile | Description |
|-------|-------|----------|-------------------|-------------|
| 1 | T01 | No | implementation_engineer | Foundation: Core, Auth, Multi-Tenant, RLS, Rate Limiting |
| 2 | T02, T03 | Yes (2 agents) | implementation_engineer ×2 | Core entities + Plugin framework parallel |
| 3 | T07a, T09 | Yes (2 agents) | implementation_engineer ×2 | Frontend Shell+Auth+UI Library + KI-Copilot/Workflow parallel |
| 4 | T07b | No | implementation_engineer | Frontend Feature Pages (Companies, Contacts, Settings, Dashboard, Search) |
| 5 | T10 | No | implementation_engineer | Monitoring, Performance, Doku, Environment Config |

#### v2 Plugin Phases (nach v1 Deployment)

| Phase | Tasks | Parallel | Subagent Profile | Description |
|-------|-------|----------|-------------------|-------------|
| 6 | T04, T05, T06, T11 | Yes (4 agents) | implementation_engineer ×4 | DMS, Calendar, Mail, Tags+Permissions backends parallel |
| 7 | T08a, T08b, T08c | Yes (3 agents) | implementation_engineer ×3 | Frontend DMS+Tags, Calendar, Mail+Search parallel |

### Task-to-Subagent Mapping

| Task ID | Title | Subagent | Dependencies | Phase | Scope |
|---------|-------|----------|--------------|-------|-------|
| T01 | Core Infrastructure + Multi-Tenant + Auth | implementation_engineer | — | 1 | v1 |
| T02 | Company + Contact + Import/Export | implementation_engineer | T01 | 2 | v1 |
| T03 | Plugin System Framework | implementation_engineer | T01 | 2 | v1 |
| T07a | Frontend SPA — Shell, Auth, Routing, i18n, UI Library | implementation_engineer | T01 | 3 | v1 |
| T07b | Frontend SPA — Companies, Contacts, Settings, Dashboard, Search | implementation_engineer | T01, T02, T07a | 4 | v1 |
| T09 | KI-Copilot + Workflow Engine | implementation_engineer | T01, T02 | 3 | v1 |
| T10 | Monitoring + Performance + Doku + Env Config | implementation_engineer | T01, T02 | 5 | v1 |
| T04 | DMS Plugin Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T05 | Calendar Plugin Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T06 | Mail Plugin Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T11 | Tags + Permissions + Entity Links Backend | implementation_engineer | T01, T03 | 6 | v2 |
| T08a | Frontend DMS + Tags + Permissions UI | implementation_engineer | T04, T07b | 7 | v2 |
| T08b | Frontend Calendar UI | implementation_engineer | T05, T07b | 7 | v2 |
| T08c | Frontend Mail + Global Search UI | implementation_engineer | T06, T07b | 7 | v2 |

### Parallelization Notes

**v1 Phases:**
- **Phase 2:** T02 (Company/Contact) and T03 (Plugin Framework) are independent after T01 — safe to run in parallel.
- **Phase 3:** T07a (Frontend Shell+Auth+UI Library) depends only on T01. T09 (KI/Workflow) depends on T01+T02. Both can run in parallel if API contracts are frozen.
- **Phase 4:** T07b (Frontend Feature Pages) depends on T07a (UI library, routing, auth) + T02 (company/contact API). Must run after T07a.
- **Phase 5:** T10 (Monitoring+Doku) depends on T01+T02. Can run parallel with T07b.

**v2 Phases (after v1 deployment):**
- **Phase 6:** T04 (DMS), T05 (Calendar), T06 (Mail), T11 (Tags+Perm) all depend on T01+T03 — safe to run in parallel.
- **Phase 7:** T08a/T08b/T08c depend on T07b + respective backend (T04/T05/T06) — safe to run in parallel.

### Block Rules

- Block = max 3 Tasks per implementation block.
- After each block: quality_reviewer review → block_compactor → context_compactor → User checkpoint.
- quality_reviewer and release_auditor do NOT count toward the 3-task limit.
- After 3 blocks (9 tasks): release_auditor runs full audit.
- Token budget: ~3000 tokens per task. If tool result >5000 tokens: context_compactor.

---

## 5. Forbidden Patterns

### Backend Forbidden

- ❌ **SQLite:** No SQLite as database. PostgreSQL 16 only (ADR-01).
- ❌ **Jinja2:** No server-side HTML rendering. API-only backend (ADR-03).
- ❌ **Cross-Tenant Data Access:** No query without tenant_id filter. ORM auto-filter must not be bypassed.
- ❌ **Plaintext Passwords:** Passwords must be bcrypt-hashed (cost=12). Never store or log plaintext.
- ❌ **JWT Tokens:** No JWT auth in v1. Session-based auth with HttpOnly cookies only (ADR-05).
- ❌ **Naive Datetime:** All datetime fields must be timezone-aware (TIMESTAMPTZ). Never use `datetime.now()` without tz.
- ❌ **Integer IDs:** All primary keys are UUID. Never use auto-increment integer IDs.
- ❌ **Hard-Delete without GDPR flag:** Companies/Contacts use soft-delete. Hard-delete only with explicit `?gdpr=true`.
- ❌ **Manual Tenant Filter:** Never manually add `.filter(Tenant.id == x)` in services. The ORM auto-filter handles this.
- ❌ **Sync I/O in Routes:** All route handlers are `async def`. Never use blocking I/O (use `asyncpg`, `aiofiles`, etc.).
- ❌ **Raw SQL without Tenant Check:** Any raw SQL query must explicitly include `tenant_id` filter.
- ❌ **Secrets in Code:** No hardcoded secrets. All secrets via environment variables.
- ❌ **Unvalidated Input:** All request bodies validated by Pydantic schemas. Never trust raw request data.
- ❌ **Missing Audit Log:** All create/update/delete operations must create audit log entries.
- ❌ **Plugin Tables without tenant_id:** All plugin-created tables must include `tenant_id` column. The migration validator enforces this.

### Frontend Forbidden

- ❌ **Class Components:** No class components. Functional components with hooks only.
- ❌ **Inline Styles:** No `style={{}}` props. Use Tailwind utility classes.
- ❌ **Hardcoded Strings:** No user-visible hardcoded strings. Use `t()` from i18n.
- ❌ **Manual Fetch in Components:** No `fetch()` or `axios` calls in components. Use TanStack Query hooks.
- ❌ **Server Data in Zustand:** Zustand is for client state only. Server data goes in TanStack Query.
- ❌ **`any` Types:** No `any` type. Use proper TypeScript types.
- ❌ **Missing ARIA Attributes:** All interactive elements must have ARIA labels.
- ❌ **Touch Targets < 44px:** All buttons/links must have minimum 44px touch target.
- ❌ **Direct DOM Manipulation:** No `document.getElementById()` or `querySelector()` in components. Use React refs.
- ❌ **Unsafe HTML Rendering:** No `dangerouslySetInnerHTML` without sanitization. Mail bodies must be sanitized (DOMPurify equivalent).

### Deployment Forbidden

- ❌ **Running as Root in Container:** Containers run as non-root user (app:app).
- ❌ **Exposed DB Port in Production:** PostgreSQL port (5432) must not be exposed externally in production.
- ❌ **No Health Check:** All services must have Docker health checks configured.
- ❌ **No Volume for Storage:** File storage must use a named volume, not ephemeral container storage.
- ❌ **Secrets in docker-compose.yml:** No secrets in compose file. Use `.env` file or Docker secrets.

---

## 6. Quality Gates

### Per-Task Quality Gate

Before a task is marked complete:
1. All test_spec commands must pass.
2. Coverage target must be met (measured by pytest-cov / vitest coverage).
3. TypeScript compiles without errors (`tsc --noEmit`).
4. Linting passes (ruff for backend, eslint for frontend).
5. Build succeeds (Vite build for frontend, no build step for backend).
6. No forbidden patterns detected.
7. All acceptance criteria verified as testable.

### Phase Gate (after each phase)

1. All tasks in the phase pass their quality gates.
2. quality_reviewer subagent reviews the phase output.
3. No critical issues from quality_reviewer.
4. Block compactor saves progress.
5. User checkpoint before next phase.

### Release Gate (before v1 deployment)

1. All 7 v1 tasks complete (T01, T02, T03, T07a, T07b, T09, T10).
2. release_auditor runs full audit.
3. Docker Compose builds and starts successfully.
4. Health endpoint returns 200.
5. E2E tests (Playwright) pass.
6. All forbidden patterns checked.

### v2 Release Gate (before v2 plugin deployment)

1. All 7 v2 tasks complete (T04, T05, T06, T11, T08a, T08b, T08c).
2. release_auditor runs full audit.
3. All plugin backends + frontends pass quality gates.
4. Plugin install/activate/deactivate lifecycle tested.
5. All forbidden patterns checked.

---

## 7. Environment Setup

### Development Environment

| Variable | Value | Purpose |
|----------|-------|---------|
| `POSTGRES_HOST` | `localhost` (dev) / `postgres` (docker) | Database host |
| `POSTGRES_PORT` | `5432` | Database port |
| `POSTGRES_DB` | `leocrm` | Database name |
| `POSTGRES_USER` | `leocrm` | Database user |
| `POSTGRES_PASSWORD` | (from .env) | Database password |
| `REDIS_URL` | `redis://localhost:6379/0` | Redis for cache + sessions + jobs |
| `LEOCRM_SECRET_KEY` | (min 32 chars) | Session signing secret |
| `SESSION_TIMEOUT_HOURS` | `8` | Session expiry |
| `MAIL_ENCRYPTION_KEY` | (32-byte hex) | AES-256 key for mail credentials |
| `STORAGE_BACKEND` | `local` (dev) / `s3` (prod) | File storage backend |
| `STORAGE_PATH` | `/data/leocrm/storage` | Local storage path |
| `ONLYOFFICE_URL` | `http://onlyoffice:80` | OnlyOffice document server |
| `LOG_LEVEL` | `INFO` | Logging level |

### Test Environment

- Test DB: Ephemeral PostgreSQL (pytest-postgresql or testcontainers).
- Test Redis: Ephemeral or fakeredis.
- External services (IMAP, SMTP, OnlyOffice): Mocked via `unittest.mock.AsyncMock`.
- Test fixtures in `conftest.py` provide: test client, authenticated client (per role), seeded data.

---

## 8. Architecture Reference

Full architecture details: `architecture.md`

Full task graph with test specs: `task_graph.json`

Key ADRs:
- ADR-01: PostgreSQL 16 (not SQLite)
- ADR-02: ARQ (not Celery)
- ADR-03: Built-in plugins with manifest (not dynamic pip-install)
- ADR-04: TanStack Query (not Redux)
- ADR-05: Session-based auth (not JWT)
- ADR-06: Soft-delete with `deleted_at` column

---

## Handoff

- **AGENTS.md status:** COMPLETE
- **task_graph.json status:** COMPLETE (14 tasks: 7 v1 + 7 v2, all with test_spec, 143 features covered, v1/v2 separated, v2.1.0)
- **architecture.md status:** COMPLETE (73/73 v1 features referenced, v2 sections marked)
- **Ready for v1 implementation:** YES (pending quality_reviewer review + plan_mode transition to implementation_allowed)
- **v2 implementation:** After v1 deployment, separate phase
