From 9e070707c205c0699626afede2b2dcc0063b20fe Mon Sep 17 00:00:00 2001 From: Samuel Monroe Date: Tue, 28 Apr 2026 14:39:10 +0200 Subject: [PATCH 1/6] Agentic setup review with Codex --- .../skills}/wefa-tanstack-query/SKILL.md | 2 +- .../wefa-tanstack-query/agents/openai.yaml | 0 .../references/official-v5-patterns.md | 0 .../references/wefa-conventions.md | 0 .../skills}/wefa-vue-frontend/SKILL.md | 6 +- .../wefa-vue-frontend/agents/openai.yaml | 0 .gitignore | 1 + AGENTS.md | 106 +++-- PLANS.md | 38 ++ bff/AGENTS.md | 61 +++ code_review.md | 23 + django/AGENTS.md | 179 ++++++++ django/CONTRIBUTE.md | 2 + vue/.github/copilot-instructions.md | 275 +----------- vue/AGENTS.md | 67 +++ vue/package-lock.json | 67 +-- vue/scripts/files/copilot-instructions.md | 420 ------------------ 17 files changed, 492 insertions(+), 755 deletions(-) rename {skills => .agents/skills}/wefa-tanstack-query/SKILL.md (97%) rename {skills => .agents/skills}/wefa-tanstack-query/agents/openai.yaml (100%) rename {skills => .agents/skills}/wefa-tanstack-query/references/official-v5-patterns.md (100%) rename {skills => .agents/skills}/wefa-tanstack-query/references/wefa-conventions.md (100%) rename {skills => .agents/skills}/wefa-vue-frontend/SKILL.md (92%) rename {skills => .agents/skills}/wefa-vue-frontend/agents/openai.yaml (100%) create mode 100644 PLANS.md create mode 100644 bff/AGENTS.md create mode 100644 code_review.md create mode 100644 django/AGENTS.md create mode 100644 vue/AGENTS.md delete mode 100644 vue/scripts/files/copilot-instructions.md diff --git a/skills/wefa-tanstack-query/SKILL.md b/.agents/skills/wefa-tanstack-query/SKILL.md similarity index 97% rename from skills/wefa-tanstack-query/SKILL.md rename to .agents/skills/wefa-tanstack-query/SKILL.md index f4b393ae..6fabb0ba 100644 --- a/skills/wefa-tanstack-query/SKILL.md +++ b/.agents/skills/wefa-tanstack-query/SKILL.md @@ -68,4 +68,4 @@ Apply TanStack Query Vue v5 with official v5 patterns while preserving WeFa's pr 1. For wrapper tests in `vue/src/network/__tests__`, mock `@tanstack/vue-query` directly and assert the wrapper configuration. 2. For feature or component tests, mock `@/network` instead of TanStack internals unless the feature truly owns the hook configuration. 3. Use `vue/CONTRIBUTE.md` as the source of truth for the current Vue quality gates and validation commands. -4. If the task also changes frontend behavior outside the network layer, follow the matching validation expectations from `skills/wefa-vue-frontend/SKILL.md` instead of redefining them here. +4. If the task also changes frontend behavior outside the network layer, follow the matching validation expectations from `.agents/skills/wefa-vue-frontend/SKILL.md` instead of redefining them here. diff --git a/skills/wefa-tanstack-query/agents/openai.yaml b/.agents/skills/wefa-tanstack-query/agents/openai.yaml similarity index 100% rename from skills/wefa-tanstack-query/agents/openai.yaml rename to .agents/skills/wefa-tanstack-query/agents/openai.yaml diff --git a/skills/wefa-tanstack-query/references/official-v5-patterns.md b/.agents/skills/wefa-tanstack-query/references/official-v5-patterns.md similarity index 100% rename from skills/wefa-tanstack-query/references/official-v5-patterns.md rename to .agents/skills/wefa-tanstack-query/references/official-v5-patterns.md diff --git a/skills/wefa-tanstack-query/references/wefa-conventions.md b/.agents/skills/wefa-tanstack-query/references/wefa-conventions.md similarity index 100% rename from skills/wefa-tanstack-query/references/wefa-conventions.md rename to .agents/skills/wefa-tanstack-query/references/wefa-conventions.md diff --git a/skills/wefa-vue-frontend/SKILL.md b/.agents/skills/wefa-vue-frontend/SKILL.md similarity index 92% rename from skills/wefa-vue-frontend/SKILL.md rename to .agents/skills/wefa-vue-frontend/SKILL.md index ac5d5cf3..a2677b4e 100644 --- a/skills/wefa-vue-frontend/SKILL.md +++ b/.agents/skills/wefa-vue-frontend/SKILL.md @@ -10,7 +10,6 @@ Apply the WeFa Vue workspace standards with predictable discovery, implementatio ## First Reads 1. Read `vue/README.md` for package capabilities, exports, and workspace scripts. 2. Read `vue/CONTRIBUTE.md` for quality gates and contribution expectations. -3. Read `vue/scripts/files/copilot-instructions.md` when the task changes UI composition patterns or component selection. ## Workspace Map 1. Start public-surface discovery at `vue/src/lib.ts` and `vue/src/containers/index.ts`. @@ -27,8 +26,9 @@ Apply the WeFa Vue workspace standards with predictable discovery, implementatio 5. Prefer Tailwind utility classes for routine styling. Do not add new CSS imports. Use scoped styles or bound style objects only when the existing feature pattern needs layout math, chart sizing, or other cases Tailwind cannot express cleanly. 6. Prefer `const { prop = defaultValue } = defineProps()` for defaults and avoid `withDefaults()` unless the local file pattern already depends on it. 7. Keep user-facing literals translated through i18n keys (`useI18nLib`, `t`, `$t`), including `aria-label`, `title`, placeholders, validation copy, and button labels. -8. When a change creates or exposes new public surface, update the nearest `index.ts` and shared entrypoints such as `vue/src/lib.ts` or `vue/src/containers/index.ts` as needed. -9. Regenerate or reuse generated OpenAPI client artifacts through the existing script instead of hand-editing generated files. +8. New public components or containers should usually ship with source, stories, MDX docs, and unit tests, unless the adjacent feature pattern in this repo clearly differs. +9. When a change creates or exposes new public surface, update the nearest `index.ts` and shared entrypoints such as `vue/src/lib.ts` or `vue/src/containers/index.ts` as needed. +10. Regenerate or reuse generated OpenAPI client artifacts through the existing script instead of hand-editing generated files. ## Delivery Workflow 1. Inspect existing implementation first: diff --git a/skills/wefa-vue-frontend/agents/openai.yaml b/.agents/skills/wefa-vue-frontend/agents/openai.yaml similarity index 100% rename from skills/wefa-vue-frontend/agents/openai.yaml rename to .agents/skills/wefa-vue-frontend/agents/openai.yaml diff --git a/.gitignore b/.gitignore index 83e11e05..2047f509 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.code-workspace *.iml .claude/settings.local.json +.claude/launch.json django/docs/source/api/* django/docs/output/**/* .env diff --git a/AGENTS.md b/AGENTS.md index 583404ce..3a6d9958 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,56 +1,94 @@ # N-SIDE WeFa – Agent Guide +## Product + +**WeFa** (Web Factory) is N-SIDE's internal toolkit for assembling full-stack product experiences quickly. It gives product teams batteries-included building blocks — auth, legal consent, locale, audit, request-scoped helpers, and a Vue/PrimeVue component library — so a new app starts at "wired and tested", not at a blank repo. + ## Project Snapshot -- WeFa (Web Factory) ships two publishable packages: `django/` contains the `nside-wefa` Django toolkit, `vue/` contains the `@nside/wefa` Vue 3 component library. -- Goal: provide production-ready auth, legal-consent, other backend packages, and UI building blocks so product teams can assemble full-stack experiences quickly. -- Primary technologies: Python 3.12+, Django 5.2 + Django REST Framework, Vitest + Playwright, Vue 3 + PrimeVue + Tailwind 4. +- WeFa ships three artifacts on a shared version: `django/` (the `nside-wefa` Django toolkit, published to PyPI), `vue/` (the `@nside/wefa` Vue 3 component library, published to npm), and `bff/` (a Flask backend-for-frontend, published as a Docker image to GHCR). +- Primary technologies: Python 3.12+, Django 5.2 + Django REST Framework, Flask 3 (BFF), Vue 3 + PrimeVue + Tailwind 4, Vitest + Playwright. ## Repository Layout & Key Docs -- `README.md` – top-level overview; defer to `django/README.md` and `vue/README.md` for workspace specifics. -- `django/` – reusable apps (`nside_wefa.common`, `.authentication`, `.legal_consent`, etc) plus `demo/` project and pytest setup. -- `vue/` – component library, demo playground, Storybook, scripts (e.g. `wefa-install`), and AI guidance (`scripts/files/copilot-instructions.md`). -- Contribution guides: `django/CONTRIBUTE.md` & `vue/CONTRIBUTE.md` define environment setup, quality gates, and release discipline. +- `README.md` – top-level overview; defer to per-workspace `README.md` for specifics. +- `django/` – reusable apps (`nside_wefa.common`, `.utils`, `.authentication`, `.legal_consent`, `.locale`, `.audit`) plus `demo/` project and pytest setup. See `django/AGENTS.md`. +- `vue/` – component library, demo playground, Storybook, `wefa-install` script. See `vue/AGENTS.md` plus the repo-local skills under `.agents/skills/`. +- `bff/` – Flask BFF handling OAuth/session/cookie + Django proxy. See `bff/AGENTS.md`. +- `.agents/skills/` – repo-local Codex skills. Codex can auto-discover these; other agents should read the referenced `SKILL.md` files directly. +- `docs/agent-roadmap.md` – checked-in replacement for older machine-local roadmap references used for cross-cutting infrastructure planning. +- `code_review.md` – review checklist for agent-led PR and patch review. +- `PLANS.md` – template for multi-step or cross-workspace execution plans. +- Contribution guides: `django/CONTRIBUTE.md` & `vue/CONTRIBUTE.md` cover human onboarding; the agent guides cover conventions and the quality gate. ## Instruction Routing -- For frontend work inside `vue/` (components, containers, stories/docs, translations, tests), use the `$wefa-vue-frontend` skill defined at `skills/wefa-vue-frontend/SKILL.md`. -- For work inside `django/`, use the backend guidance in this file until a dedicated `django/AGENTS.md` is introduced. -- For cross-cutting work (API + UI), follow this file for shared expectations and apply the `wefa-vue-frontend` skill for the frontend part. +- For frontend work inside `vue/` (components, containers, stories/docs, translations, tests), use the repo-local skills `wefa-vue-frontend` and `wefa-tanstack-query` from `.agents/skills/`. Codex can auto-discover them; agents that do not auto-load skills should read `.agents/skills/wefa-vue-frontend/SKILL.md`, `.agents/skills/wefa-tanstack-query/SKILL.md`, and `vue/AGENTS.md`. +- For backend work inside `django/`, see `django/AGENTS.md` for app conventions, the quality gate, the new-app checklist, and known gotchas. +- For BFF work inside `bff/`, see `bff/AGENTS.md` for blueprint layout, OAuth/cookie conventions, OpenAPI flow, and the quality gate. +- For cross-cutting work (Django ↔ BFF ↔ Vue), follow this file for shared expectations plus the relevant workspace AGENTS / SKILL files. +- Before designing cross-cutting infrastructure (auth modes, observability, retention, RBAC, tenancy, …), check `docs/agent-roadmap.md` first. If the intended shape is not recorded there, surface the design question early instead of relying on machine-local notes. ## Core Engineering Principles - **Convention over configuration**: align with provided settings helpers (`NSIDE_WEFA` for Django and documented Vue defaults) before introducing bespoke wiring. - **Type safety & documentation**: keep Python and TypeScript hints accurate; add comments only for non-obvious logic; update relevant docs whenever behaviour changes. - **Tests as gatekeepers**: extend existing suites when behaviour changes; no feature lands without matching tests unless explicitly justified. - -## Backend Playbook (`django/`) -- **App structure**: extend existing apps (`nside_wefa.authentication`, `.legal_consent`, `.common`, etc) unless a new domain warrants a standalone package. Mirror current layout: `apps.py`, `checks.py`, `models/`, `serializers.py`, `urls.py`, `views/`, `tests/`, `README.md`. -- **Settings contract**: all configuration flows through the `NSIDE_WEFA` dict. When adding options, document in `django/README.md`, add system checks in `checks.py`, and ensure defaults keep migrations optional. -- **APIs & serializers**: follow DRF patterns already present; keep authentication utilities DRY by placing shared logic under `utils/`. Expose URLs through `include('nside_wefa..urls')` and cover them in tests. -- **Testing & quality**: use pytest with Django (`pytest` or `python manage.py test`) plus coverage when needed. Run `ruff format .`, `ruff check .`, and `mypy nside_wefa/` before submission. Demo project (`django/demo`) is available for manual validation. +- **Mirror an existing app/component**: when in doubt about layout, settings shape, signal pattern, or test structure, copy the closest analogue rather than inventing a new pattern. +- **Test under non-default settings too**: any feature gated by an opt-in flag (tamper-evidence, `INCLUDE_ALL_MODELS`, `RAISE_ON_FAILURE`, …) needs a test that exercises the flag turned on. Code paths that work only in the default config are how silent regressions ship. ## Shared Workflow Expectations -- Stay within the workspace toolchain: `uv`/pip + Hatchling builds for Django, npm scripts + Vite for Vue. +- Stay within the workspace toolchain: `uv` + Hatchling builds for Django and BFF, npm scripts + Vite for Vue. - Keep lockfiles consistent with the package manager in use (`uv.lock`, `package-lock.json`). -- Maintain documentation parity: adjust relevant READMEs, MDX docs, or changelog entries (once introduced) whenever behaviour changes. -- For cross-cutting features, coordinate backend API shape first, then wire the frontend through the generated clients/composables. +- Maintain documentation parity: adjust relevant READMEs, MDX docs, or changelog entries whenever behaviour changes. +- For cross-cutting features, coordinate backend API shape first, then wire the frontend through the generated clients/composables; the BFF sits at the boundary and should not absorb logic that belongs in Django or Vue. + +## Cross-Workspace Verification +- If only `django/` changes, run the Django quality gate from `django/AGENTS.md`. +- If only `bff/` changes, run the BFF quality gate from `bff/AGENTS.md`. +- If only `vue/` changes, run the Vue quality gate from `vue/AGENTS.md`. +- If Django API shape, BFF proxy/auth behavior, cookie names, redirect targets, or error-code contracts change, run the relevant backend gate and, in `vue/`, run `npm run type-check`, `npm run build`, and `npm run test:package-types`. If routed demo flows or browser-visible auth UX changed, also run `npm run test:e2e -- --reporter=dot`. + +### Quality Gate Cheat Sheet + +Minimum entry commands per workspace. See each workspace's `AGENTS.md` for the full gate. + +```bash +# django/ (cwd: django/) +uv sync --all-extras && uv run pytest && uv run ruff check nside_wefa demo \ + && uv run ruff format --check nside_wefa demo && uv run mypy nside_wefa/ \ + && uv run python manage.py check + +# bff/ (cwd: bff/) +uv sync --dev && uv run pytest \ + && uv run python -m bff_app.openapi.generate --check --output bff_app/openapi/openapi.yaml + +# vue/ (cwd: vue/) +npm install && npm run lint-check && npm run type-check && npm run format-check \ + && npm run test:unit -- --reporter=dot --silent && npm run build +# Add: npm run test:e2e -- --reporter=dot when routing/demo/browser flows changed +# Add: npm run test:package-types when exports or packaging changed +``` + +## Domain Invariants + +Cross-workspace contracts that don't live in any single file. Honor these when planning changes that span workspaces. + +- **Single shared version.** All three artifacts (`django/`, `vue/`, `bff/`) ship on one version, bumped from the repo root via `python3 scripts/wefa_version.py {bump|set} ...`. Do not edit `pyproject.toml` / `package.json` versions by hand. +- **BFF ↔ Vue auth contract.** The `bff/` cookie names (`_at|_rt|_it|_meta`, see `TOKEN_COOKIE_SUFFIXES` in `bff/bff_app/services/token_cookies.py`) and the `FRONTEND_REDIRECT?error=` failure codes (`auth_state_missing`, `auth_state_mismatch`, `auth_provider_error`, `auth_callback_incomplete`, `auth_token_exchange_failed`, `auth_invalid_token`, `auth_cookie_too_large`) are part of the public contract with `vue/`. Renames or additions are coordinated changes — update `bff/README.md`, `bff/AGENTS.md`, and the consuming Vue flows in the same PR. +- **Django app load order.** `nside_wefa.common` must be installed before any other `nside_wefa.*` app (it owns shared settings access and `get_section` / `get_value`). Beyond that, `audit/checks.py::wefa_apps_dependencies_check` enforces the rest of the dependency order at boot — failing `manage.py check` is the signal, not a runtime crash. +- **Generated artifacts stay in sync.** The BFF OpenAPI spec at `bff/bff_app/openapi/openapi.yaml` is regression-checked in CI (`--check` flag); the Vue typed OpenAPI client under `vue/src/demo/openapi/` is regenerated through the existing script, never hand-edited. If a route schema or Django API shape changes, regenerate before opening the PR. +- **Opt-in flags need their own tests.** Every feature gated by an opt-in (`tamper_evident`, `INCLUDE_ALL_MODELS`, `RAISE_ON_FAILURE`, future toggles) must ship with a regression test that exercises the flag turned on. "Worked in default config, broke under the opt-in" is the documented bug shape. + +## Review And Planning +- For review requests, follow `code_review.md` so findings stay ordered and consistent across workspaces. +- For ambiguous or multi-step cross-workspace work, start from `PLANS.md` or ask the agent to plan before editing. ## Decision Checklists -- **Before shipping backend change**: - - [ ] Update/extend system checks and settings docs. - - [ ] Provide migrations only when required and reversible. - - [ ] Add pytest coverage for new branches/edge cases. - **Before opening a PR**: - - [ ] Run required backend lint/format/test commands. - - [ ] Update backend docs/demo snippets as needed. - - [ ] Document breaking changes and version impacts. - -## Quick Command Reference -- Backend install: `cd django && pip install -e .[dev]` (or `uv sync --all-extras`) -- Backend tests: `cd django && pytest` -- Backend lint/type: `cd django && ruff check . && ruff format --check && mypy nside_wefa/` + - [ ] Tests added/updated for changed behaviour, edge cases, and any opt-in flags. + - [ ] Workspace-specific quality gate run green (see the workspace's `AGENTS.md`). + - [ ] Per-app / per-feature README + top-level workspace README updated alongside behaviour changes. + - [ ] Breaking changes and version impacts called out in the PR body. ## When in Doubt -- Re-read the relevant `README.md` and `CONTRIBUTE.md` before altering flows. -- Trace existing backend implementations (e.g., `nside_wefa/legal_consent`) to mirror patterns. -- Surface open questions early (e.g., new authentication modes) so design/system owners can confirm direction. +- Workspace AGENTS / SKILL files first, then `README.md` / `CONTRIBUTE.md`, then mirror the closest existing implementation. +- Surface open questions early (new auth modes, new top-level apps, schema-breaking changes, BFF surface expansion) so design/system owners can confirm direction. Following this guide keeps contributions aligned with the existing architecture, ensures compliance with the WeFa component hierarchy, and preserves release quality across both Django and Vue packages. diff --git a/PLANS.md b/PLANS.md new file mode 100644 index 00000000..c2bc3124 --- /dev/null +++ b/PLANS.md @@ -0,0 +1,38 @@ +# WeFa Cross-Workspace Plan Template + +Use this template for ambiguous, long-running, or cross-workspace work before implementation starts. + +## Goal + +State the user-visible outcome and the success condition. + +## Touched Workspaces + +- `django/` +- `bff/` +- `vue/` + +List only the workspaces that the change will touch and explain why. + +## Constraints + +- Architecture or ownership boundaries to preserve +- Existing contracts that must remain compatible +- Documentation or generated artifacts that must stay in sync + +## Implementation Notes + +- Main behavior changes +- Public API or contract changes +- Required docs or generated-file updates + +## Verification + +- Exact commands to run in each touched workspace +- Any cross-workspace checks needed for contracts, generated clients, or browser flows + +## Rollback / Compatibility + +- Backward-compatibility concerns +- Migration or deploy notes +- Safe rollback approach if the change needs to be reverted diff --git a/bff/AGENTS.md b/bff/AGENTS.md new file mode 100644 index 00000000..65e15de1 --- /dev/null +++ b/bff/AGENTS.md @@ -0,0 +1,61 @@ +# WeFa BFF – Agent Guide + +Flask Backend-for-Frontend that handles OAuth login/logout/session for the Vue SPA and proxies REST calls to the Django backend. Read alongside the repo-wide [`../AGENTS.md`](../AGENTS.md). Setup, env vars, and security model live in [`README.md`](README.md); this file captures conventions, the quality gate, and gotchas. + +## Layout + +- **Entrypoint**: [`bff.py`](bff.py) — loads `.env` and calls `bff_app.create_app()`. +- **App factory**: [`bff_app/__init__.py`](bff_app/__init__.py) — wires CORS, smorest API, blueprints. +- **Routes** (Flask blueprints): [`bff_app/routes/auth.py`](bff_app/routes/auth.py), [`bff_app/routes/proxy.py`](bff_app/routes/proxy.py), [`bff_app/routes/health.py`](bff_app/routes/health.py). +- **Services**: [`bff_app/services/auth.py`](bff_app/services/auth.py) (Authlib + PKCE), [`bff_app/services/token_cookies.py`](bff_app/services/token_cookies.py) (encrypted HttpOnly cookies). +- **Settings**: [`bff_app/settings.py`](bff_app/settings.py) — fail-fast env validation; required keys listed in `README.md`. +- **OpenAPI**: [`bff_app/openapi/generate.py`](bff_app/openapi/generate.py) emits the static spec at `bff_app/openapi/openapi.yaml`. +- **Tests**: `tests/` (one file per route + service). + +## Conventions + +- **Blueprint per concern**; register in `bff_app/__init__.py` only. Don't add routes to existing blueprints if they don't fit the concern (e.g. don't put proxy logic into `auth_bp`). +- **`flask-smorest`** for schema-validated routes — define schemas in the same file as the blueprint unless they're shared. +- **OAuth state lives in Flask's signed session cookie**; tokens live in separate encrypted cookies (`_at`, `_rt`, `_it`, `_meta`). Don't store tokens in the session. **`SESSION_COOKIE_SECURE=True` and `SESSION_COOKIE_SAMESITE=Strict` are mandatory in production** — the BFF doesn't enforce this; the deployment does. +- **PKCE**: every login flow generates a verifier; the callback validates state + verifier before token exchange. See `bff_app/services/auth.py`. +- **Failure redirects**: callback errors redirect to `FRONTEND_REDIRECT?error=`. Add new error codes to the documented list in `README.md` when introducing them. Current codes: `auth_state_missing`, `auth_state_mismatch`, `auth_provider_error`, `auth_callback_incomplete`, `auth_token_exchange_failed`, `auth_invalid_token`, `auth_cookie_too_large`. +- **Settings module is fail-fast**: missing required env vars raise at app startup. Add new required vars to both `bff_app/settings.py` validation and the `README.md` env reference. **`dotenv` loads once at process start** — adding a var to `.env.example` only is not enough. +- **Encrypted-cookie code is security-sensitive**: don't bypass key validation, don't introduce new cookie names without coordinating with the frontend. **Existing signed-session token payloads are not migrated** when the cookie scheme changes (encrypted cookies were a recent rollout). Document any further format change in the PR body so deployers know to clear sessions. + +## Quality gate + +CWD is `bff/`. + +```bash +uv sync --dev # install + dev deps +FLASK_RUN_PORT=5022 uv run flask --app bff.py run # local server +uv run pytest # full suite +uv run python -m bff_app.openapi.generate --output bff_app/openapi/openapi.yaml # regenerate spec +uv run python -m bff_app.openapi.generate --check --output bff_app/openapi/openapi.yaml # CI: spec is current +docker-compose up --build # parity with the published image +``` + +The BFF has no ruff/mypy gate today; adding one is a good first issue. + +## Tests + +- **Conftest** (`tests/conftest.py`) sets up the Flask test client with a known set of env vars; mirror its pattern when adding tests so the OAuth/PKCE state is deterministic. +- Mock the upstream IdP and the upstream Django backend via `requests` patching — never hit real endpoints. +- Encrypted cookies are exercised with a known `TOKEN_COOKIE_ENCRYPTION_KEY`; reuse the conftest fixture rather than rolling a new key per test. +- The OpenAPI spec is regression-tested in `tests/test_openapi_generation.py` — run it after touching any route schema. + +## Cross-workspace coordination + +- **Vue** consumes the BFF cookies and the proxied Django responses. When you change cookie names, redirect targets, or error codes, update the corresponding flows in `vue/` and notify the frontend on the PR. +- **Django** is the upstream backend. When the BFF proxy touches a new endpoint, confirm the Django route exists and is documented in the relevant `nside_wefa//README.md`. +- The BFF sits at the boundary; rather than expand BFF surface area, prefer pushing logic to Django (where it can be unit-tested + system-checked) or to Vue (where the user owns the state). + +## Docker / release + +- The BFF is shipped as a Docker image to GHCR on every GitHub release: `ghcr.io/n-side-dev/wefa/bff:` (and `:latest` for non-prerelease tags). See repo root `README.md`. +- **Port env vars differ by entrypoint**: `flask run` reads `FLASK_RUN_PORT`, Docker reads `PORT`, and `python bff.py` defaults to 5000 unless code overrides it. Always set `FLASK_RUN_PORT` for `flask run` and `PORT` for Docker. +- Don't change `pyproject.toml` Python ceiling (`>=3.12,<3.13`) without coordinating; some downstream Docker tooling pins 3.12. + +## Open follow-ups + +- **No central log correlation yet.** When the request-ID middleware tracked in [`../docs/agent-roadmap.md`](../docs/agent-roadmap.md) ships, the BFF should forward `X-Request-ID` so logs correlate end-to-end. diff --git a/code_review.md b/code_review.md new file mode 100644 index 00000000..bb0a23e5 --- /dev/null +++ b/code_review.md @@ -0,0 +1,23 @@ +# WeFa Review Checklist + +Use this checklist when the task is a review rather than an implementation. + +## Output Shape + +- Findings first, ordered by severity, with file references. +- Keep summaries brief and secondary to the findings. +- If there are no findings, say so explicitly and call out any residual risk or missing verification. + +## Review Priorities + +1. Correctness issues, behavioural regressions, broken contracts, and risky edge cases. +2. Missing tests, especially for non-default or opt-in paths. +3. API, documentation, release, or versioning impacts that were not updated alongside the change. +4. Auth, cookie, session, and security-sensitive concerns. +5. Maintainability issues that materially raise future change risk. + +## WeFa-Specific Prompts + +- Check that generated artifacts and documented contracts stay in sync. +- Call out missing workspace quality-gate coverage when the change crosses `django/`, `bff/`, or `vue/`. +- For Vue work, treat untranslated user-facing text as a review issue. diff --git a/django/AGENTS.md b/django/AGENTS.md new file mode 100644 index 00000000..b7cea6dd --- /dev/null +++ b/django/AGENTS.md @@ -0,0 +1,179 @@ +# WeFa Django – Agent Guide + +Backend slice of the N-SIDE WeFa toolkit. Read alongside the repo-wide [`../AGENTS.md`](../AGENTS.md). Each shipped app additionally has its own `README.md` covering its public surface — read that before extending an existing app. + +## Layout + +- Source: `nside_wefa//` — one app per concern. Existing apps: `common`, `utils`, `authentication`, `legal_consent`, `locale`, `audit`. +- Each app mirrors the same shape: `apps.py`, `checks.py`, `models/` or `models.py`, `serializers.py`, `urls.py`, `views/`, `admin.py` (when it owns models), `tests/`, `README.md`. +- Canonical references when in doubt: + - **`audit/`** — most complete: settings, system checks, registration UX, REST endpoints, admin, signals, management commands, tamper-evident model, exhaustive tests. + - **`locale/`** — smallest end-to-end: model + signal + REST + checks + tests. +- Test settings & wiring live in `demo/` — adding a new app means updating `demo/settings.py` (`INSTALLED_APPS`, `MIDDLEWARE`, `NSIDE_WEFA`) and `demo/urls.py`. +- `pytest.ini` is configured to use `demo.settings`. + +## Conventions + +### Settings access +- Every app reads from `NSIDE_WEFA.
`. Use `nside_wefa.common.settings.get_section(name)` / `get_value(name, key, default)` to read. Do not invent new `_*Configuration` private classes — the legacy ones in `legal_consent` and `locale` are kept for back-compat only. +- `override_settings(NSIDE_WEFA={...})` replaces the **whole** dict in tests. Re-include `APP_NAME` and any other section consumed by an installed app's `apps.py.ready()`. + +```python +# Bad — bespoke private config class duplicating shared infrastructure +class _LegalConsentConfiguration: + def __init__(self) -> None: + nside_wefa_settings = cast(_NsideWefaSettings, settings.NSIDE_WEFA) + configuration = nside_wefa_settings["LEGAL_CONSENT"] + self.version = configuration["VERSION"] + +config = _LegalConsentConfiguration() +version = config.version + +# Good — read through the shared helper so checks and tests behave consistently +from nside_wefa.common.settings import get_value + +version = get_value("LEGAL_CONSENT", "VERSION") +``` + +### System checks +- Every app registers via `apps.py.ready() → from . import checks`. The import is intentionally unused; `@register()` decorators in `checks.py` do the work. +- Use the helpers in `nside_wefa.utils.checks`: + - `check_apps_dependencies_order(deps)` — enforces order between **consecutive pairs**. For "X *and* Y must each precede Z" without ordering X vs Y, call it twice with separate two-element lists (see `audit/checks.py::wefa_apps_dependencies_check`). + - `check_nside_wefa_settings(...)` — validates a section + required keys + per-key validators. **Footgun: it rejects empty `{}` sections.** For all-keys-optional sections, iterate validators directly (see `audit/checks.py::audit_settings_check`). + - Primitive validators (each takes a `setting_path` for error messages): `validate_bool`, `validate_optional_positive_int`, `validate_string_list(allowed=...)`, `validate_dotted_path_callable`, `validate_model_label`, `validate_model_label_dict`. + +```python +# Bad — using check_nside_wefa_settings on an all-optional section. +# Empty NSIDE_WEFA["AUDIT"] = {} would now raise a system-check error +# even though "use all defaults" is the intended UX. +@register() +def audit_settings_check(app_configs, **kwargs): + return check_nside_wefa_settings( + section_name="AUDIT", + required_keys=[], + validators={"TAMPER_EVIDENT": validate_bool("...")}, + ) + +# Good — iterate validators only over keys that are actually present +@register() +def audit_settings_check(app_configs, **kwargs): + section = (getattr(django_settings, "NSIDE_WEFA", None) or {}).get("AUDIT") + if section is None: + return [] + validators = {"TAMPER_EVIDENT": validate_bool("NSIDE_WEFA.AUDIT.TAMPER_EVIDENT")} + errors = [] + for key, validator in validators.items(): + if key in section: + errors.extend(validator(section[key])) + return errors +``` + +### Models, signals, migrations +- OneToOne to `settings.AUTH_USER_MODEL` with `post_save` auto-creation is the toolkit pattern (`legal_consent.LegalConsent`, `locale.UserLocale`). Use `dispatch_uid="models.create_*"` so reconnects stay idempotent. +- Migrations should backfill existing users via `RunPython` (see `locale/migrations/0001_initial.py`). +- `default_auto_field = "django.db.models.BigAutoField"` on every `AppConfig`. + +### Signal-driven diffs (only emit on real change) +- Pattern used by `audit/builtin/locale.py` and `audit/builtin/legal_consent.py`: `post_init` snapshots the persisted tuple onto the instance under `_wefa_audit_previous_*`, `post_save` compares current vs snapshot and emits only on change, then refreshes the snapshot. Do not use `created` as a proxy — it misses re-saves of already-changed rows. + +```python +# Bad — `created` only fires on insert, so updates that change `code` +# silently never emit an audit event. +def _on_locale_saved(sender, instance, created, **kwargs): + if created: + api.log("locale.change", actor=instance.user, target=instance, + changes={"code": {"from": None, "to": instance.code}}) + +# Good — snapshot the persisted value at post_init, diff at post_save, +# refresh the snapshot so successive saves are also tracked. +_SNAPSHOT_ATTR = "_wefa_audit_previous_code" + +def _snapshot_code(sender, instance, **kwargs): + setattr(instance, _SNAPSHOT_ATTR, instance.code) + +def _on_locale_saved(sender, instance, created, **kwargs): + previous = getattr(instance, _SNAPSHOT_ATTR, None) + current = instance.code + if previous == current: + return + api.log("locale.change", actor=instance.user, target=instance, + changes={"code": {"from": previous, "to": current}}) + setattr(instance, _SNAPSHOT_ATTR, current) +``` + +### REST views +- `APIView`-based; explicit `permission_classes` and `serializer_class`. +- `@extend_schema` annotations on every method with `operation_id`, `tags=[""]`, `summary`, `description`, explicit `responses={...}`. +- Define `app_name` in `urls.py`; mount in `demo/urls.py` via `include("nside_wefa..urls")`. + +### Admin +- Every shipped model should be admin-registered (`audit/admin.py` is the reference for read-only admins). +- When wrapping a third-party model that's already admin-registered (e.g. `auditlog.LogEntry`), `admin.site.unregister(Model)` first inside a `try/except NotRegistered`. **`NotRegistered` lives at `django.contrib.admin.exceptions`** — the alias under `.sites` exists at runtime but isn't in the type stubs. + +### Working with `django-auditlog` (when relevant) +- **Always resolve the active model via `auditlog.get_logentry_model()`** instead of importing `LogEntry` directly. Under tamper-evidence the base `LogEntry.objects` raises `AttributeError: Manager isn't available; ... has been swapped`, so hard-coded references silently break — and silently-failing audit writes are doubly bad because `RAISE_ON_FAILURE=False` swallows them. +- `AUDITLOG_LOGENTRY_MODEL` expects Django's `app_label.ModelName` form (e.g. `audit.WefaLogEntry`), **not** the dotted Python import path. Resolved via `apps.get_model(...)` internally. + +## Quality gate + +Run before opening a PR. CWD is `django/`. + +```bash +uv sync --all-extras # install + dev deps (idempotent) +uv run pytest # full suite +uv run ruff check nside_wefa demo # lint +uv run ruff format --check nside_wefa demo # format check +uv run mypy nside_wefa/ # type check +uv run python manage.py check # system checks +``` + +Helpers: + +```bash +uv run ruff format nside_wefa demo # auto-format +uv run ruff check --fix nside_wefa demo # auto-fix lint +uv run pytest nside_wefa//tests/test_.py -x --tb=short +uv run python manage.py makemigrations --check --dry-run +``` + +## Tests + +- Mirror production layout under `nside_wefa//tests//`. Each `tests/` and subfolder needs an empty `__init__.py`. +- `django.test.TestCase` for DB-touching tests (auto-rollback per test); `rest_framework.test.APITestCase` for view tests. +- **Transaction gotcha**: a query expected to raise inside `TestCase` leaves the implicit `atomic` block in error state and subsequent queries fail with `TransactionManagementError`. Wrap the failing call in its own savepoint: + ```python + with transaction.atomic(), self.assertRaises(SomeError): + thing_that_raises() + ``` +- **Module-global registries** (e.g. `auditlog.registry.auditlog`) persist across tests. Add a `tearDown` that unregisters anything the test registered, and prefer test-only models that aren't already wired in `demo/settings.py` to avoid cross-test interference. +- **`AUDITLOG_*` settings** get set during `AppConfig.ready()` at suite boot. Tests that exercise the translation layer must snapshot, clear, and restore those keys around each case (see `audit/tests/test_settings_translation.py::_RestoreAuditlogSettings`). +- **Test under non-default settings**: every feature gated by an opt-in flag (tamper-evidence, `INCLUDE_ALL_MODELS`, `RAISE_ON_FAILURE=True`) needs a regression test with the flag flipped on. Several real bugs in past PRs shared the shape "worked in the default config, broke under the opt-in". + +## Demo project + +- `python manage.py runserver` and `python manage.py migrate` use the SQLite DB at `django/db.sqlite3` (committed for the demo). +- One-shot ORM scripts need `DJANGO_SETTINGS_MODULE` in the env: + ```bash + DJANGO_SETTINGS_MODULE=demo.settings uv run python -c ' + import django; django.setup() + ... + ' + ``` +- New apps must be wired in `demo/settings.py` (`INSTALLED_APPS`, `MIDDLEWARE` if relevant, `NSIDE_WEFA[""]`) and `demo/urls.py` **before** `manage.py makemigrations ` will work — the autodetector needs the app installed. + +## Adding a new app — checklist + +1. **Scaffold**: `nside_wefa//{__init__.py, apps.py, checks.py}`. `apps.py` sets `default_auto_field = "django.db.models.BigAutoField"` and `name = "nside_wefa."`; `ready()` does `from . import checks # noqa: F401` and any startup wiring. +2. **Wire the demo**: add to `demo/settings.py` `INSTALLED_APPS` (after `nside_wefa.common`); populate `NSIDE_WEFA[""]` if the app reads settings; register URLs in `demo/urls.py`; append middleware if needed. +3. **System checks**: dependency-order check, settings-shape check, per-key validators using the primitives from `nside_wefa.utils.checks`. Cover every key so `manage.py check` catches mistakes at boot. +4. **Models + migrations**: `python manage.py makemigrations ` once models exist; commit migration alongside the model. Backfill existing users via `RunPython` for OneToOne to `AUTH_USER_MODEL`. +5. **Tests**: mirrored `tests/` tree covering models, serializers, views, checks, signals, management commands. Include cases for opt-in flags turned on. +6. **Per-app README**: follow `nside_wefa/audit/README.md` shape — overview, installation, registration UX (if relevant), settings reference table, REST endpoints table, conventions. +7. **Top-level docs**: update `django/README.md` Features list, Included Apps, Quick Start `INSTALLED_APPS` snippet, `NSIDE_WEFA` Configuration block. +8. **Version bump**: bump `pyproject.toml` `version` when shipping; the monorepo release script lives at `scripts/wefa_version.py` (run from repo root). + +## When in doubt + +- Mirror [`nside_wefa/audit/`](nside_wefa/audit/) (latest, full surface) or [`nside_wefa/locale/`](nside_wefa/locale/) (smallest end-to-end). +- For DRF / SimpleJWT mutations of `REST_FRAMEWORK`, mirror `nside_wefa.authentication.utils.settings_initialization`. +- Before adding cross-cutting infrastructure, check [`../docs/agent-roadmap.md`](../docs/agent-roadmap.md) first — some presets are already scoped there (for example audit was tracked as E1 and request-ID observability as E8). diff --git a/django/CONTRIBUTE.md b/django/CONTRIBUTE.md index 165c16a8..198a9556 100644 --- a/django/CONTRIBUTE.md +++ b/django/CONTRIBUTE.md @@ -3,6 +3,8 @@ Thank you for your interest in contributing to N-SIDE WeFa! This document provides guidelines and instructions for setting up your development environment and contributing to the project. +> **Working with an AI agent (Codex, Claude Code, Copilot, etc.)?** Read [`AGENTS.md`](AGENTS.md) for the curated backend conventions, the quality gate, the new-app checklist, and known gotchas. This CONTRIBUTE.md focuses on the human contributor onboarding flow. + ## Table of Contents - [Development Setup](#development-setup) diff --git a/vue/.github/copilot-instructions.md b/vue/.github/copilot-instructions.md index 7fca9627..d6c8ed77 100644 --- a/vue/.github/copilot-instructions.md +++ b/vue/.github/copilot-instructions.md @@ -1,270 +1,15 @@ -# N-SIDE WeFa- Development Instructions +# WeFa Vue Compatibility Instructions -## Project Overview -**This is a PrimeVue-based component library superset** (`@nside/wefa`) built with Vue 3 and TypeScript. The library extends and enhances PrimeVue components with additional functionality, custom styling using Tailwind CSS, and domain-specific features for energy management applications. +This file exists only for tools that look specifically for `copilot-instructions.md`. -### Core Architecture -- **Base Framework**: PrimeVue 4.3.6 as the foundational UI component library -- **Enhancement Layer**: Custom components that wrap, extend, or compose PrimeVue components -- **Styling**: Tailwind CSS 4.1.11 with PrimeUI integration - **NO custom CSS files** -- **Component Pattern**: Each component is a superset that adds value to existing PrimeVue functionality +## Source Of Truth -## Component Development Guidelines +- Start with [`../AGENTS.md`](../AGENTS.md). +- For reusable frontend workflows, read [`../../.agents/skills/wefa-vue-frontend/SKILL.md`](../../.agents/skills/wefa-vue-frontend/SKILL.md). +- For TanStack Query work, also read [`../../.agents/skills/wefa-tanstack-query/SKILL.md`](../../.agents/skills/wefa-tanstack-query/SKILL.md). -### Required Deliverables for Each Component -Every component exposed by this library **MUST** include: +## Notes -1. **Single File Component (SFC)**: The main `.vue` component file -2. **Storybook Stories**: `.stories.ts` file with interaction tests. Never includes the `autodocs` tag. -3. **Unit Tests**: `.spec.ts` file with comprehensive test coverage -4. **MDX Documentation**: `.mdx` file with complete documentation including use cases. - -### Component Development Pattern -When creating new components, follow this established pattern: - -#### 1. Use PrimeVue as Foundation -```typescript -// Import PrimeVue components when needed -import Breadcrumb from 'primevue/breadcrumb' -import type { MenuItem } from 'primevue/menuitem' - -// Extend or compose PrimeVue functionality -export interface YourComponentProps { - // Add your custom props that enhance PrimeVue behavior -} -``` - -#### 2. Style with Tailwind Only -- **DO**: Use Tailwind CSS classes for all styling -- **DO**: Leverage `tailwindcss-primeui` for PrimeVue component styling -- **DON'T**: Create custom CSS files or ` - - -import './custom-styles.css' -``` - -**✅ REQUIRED APPROACH:** - -```vue - -
- -``` - -**📚 STYLING RESOURCES:** -- **Tailwind Classes**: https://tailwindcss.com/docs -- **PrimeVue Integration**: Use `tailwindcss-primeui` package -- **Theme System**: Leverage `@primeuix/themes` integration - ---- - -## 📋 AI AGENT IMPLEMENTATION EXAMPLES - -### ❌ VIOLATION EXAMPLE (AUTO-REJECT) - -```vue - - - -``` - -### ✅ CORRECT IMPLEMENTATION PATTERNS - -#### Pattern 1: WeFa First Choice -```vue - - - -``` - -#### Pattern 2: PrimeVue Composition (When WeFa Unavailable) -```vue - - - -``` - -#### Pattern 3: Complex Form Composition -```vue - - - -``` - -## Component Usage Guidelines - -### WeFa Components -```vue - -``` - -### PrimeVue Components (when WeFa doesn't have equivalent) -```vue - -``` - -### Common Tailwind Patterns for PrimeVue -```vue - -``` - ---- - -## 🔄 AI AGENT DECISION FLOW ALGORITHM - -### 🎯 STEP-BY-STEP COMPONENT SELECTION - -```mermaid -flowchart TD - A[Need UI Component] --> B{WeFa has component?} - B -->|YES| C[✅ Use WeFa
Import from @nside/wefa
END] - B -->|NO| D{Can compose with PrimeVue?} - D -->|YES| E[✅ Use PrimeVue Composition
+ Tailwind Classes
END] - D -->|NO| F[⚠️ Native HTML
+ Justification Comment
END] -``` - -### 📋 MANDATORY VALIDATION CHECKLIST - -**🔍 PRE-IMPLEMENTATION VALIDATION:** -Before writing any component code, AI agents MUST verify: - -``` -[ ] 1. COMPONENT CHECK: Searched @nside/wefa exports -[ ] 2. COMPOSITION CHECK: Evaluated PrimeVue component combination -[ ] 3. STYLING CHECK: Planned Tailwind-only approach -[ ] 4. FALLBACK CHECK: Prepared justification if using HTML -``` - -**✅ POST-IMPLEMENTATION VALIDATION:** -After writing component code, AI agents MUST validate: - -``` -[ ] ✅ IMPORT: WeFa components from '@nside/wefa' -[ ] ✅ IMPORT: PrimeVue components from 'primevue/[component]' -[ ] ✅ STYLING: Only Tailwind CSS classes used -[ ] ✅ FORBIDDEN: No