Guidelines¶
Source of truth for code, UI, and process conventions in Aletheia. Anything written here is authoritative — code that violates these guidelines should be flagged in review and fixed.
This folder is for code authors and Claude. End-user / operator documentation lives in docs/. Roadmap and planning live in roadmap/. Cross-repo API and infra contracts live in contracts/.
Why a separate top-level folder¶
- Single audience per file (Claude + developers writing code), single tone.
- Mechanical scoping for hooks, audits, and PR-time checks (
guidelines/**). - Drift is visible: a missing file for a recurring UI or backend primitive is an obvious gap.
- Symmetric with the existing top-level concept folders (
roadmap/,contracts/,docs/).
Layout¶
guidelines/
README.md # this file — index + status of every guideline
ui/ # per-component visual rules
search-sort-filter.md
lists.md
forms.md
detail-pages.md
dropdowns.md
badges.md
design-tokens.md
ux/ # system-wide interaction patterns (cross-component)
page-states.md
feedback-and-confirmation.md
navigation.md
microcopy.md
backend/ # Django patterns
views.md
models.md
migrations.md
forms.md
admin.md
security/ # auth, isolation, PII
multi-tenant-isolation.md
auth-and-permissions.md
pii-and-logging.md
celery/ # background jobs and beat schedule
task-conventions.md
integrations/ # external connectors (Doctolib, Pennylane, Logosw, INPI)
overview.md
doctolib.md
pennylane.md
logosw.md
inpi.md
imports/ # AbstractImporter / ImportRow patterns
abstract-importer.md
testing/
pytest-patterns.md
i18n/
translation-rules.md
development-workflow/
overview.md
ui/ vs ux/. ui/ is per-component visual rules (badges, lists, forms, dropdowns). ux/ is cross-component interaction patterns (empty/loading/error states, navigation, microcopy, feedback channels). When in doubt: if it's about one component's appearance, it's ui/; if it's a pattern that applies across many components, it's ux/.
Granularity rule. Every topic gets a folder, even if it currently holds a single file. Topics naturally grow (i18n splits into translation rules + model strings + JS strings; dev-workflow splits into git + environments + deploys), and folder-per-topic costs almost nothing today while making future splits painless. Audit globs stay uniform: guidelines/*/....
Naming. Folders and files are kebab-case. File names describe content, not topic (translation-rules.md, not i18n.md inside i18n/). No UPPER_CASE, no dates in filenames.
File format¶
Every guideline file should open with the same frontmatter so the status table stays accurate without manual bookkeeping:
# {Title}
> **Status:** Implemented | Draft | Placeholder
> **Last reviewed:** YYYY-MM-DD
> **Owner:** (optional)
## Scope
One paragraph: what this guideline covers and when it kicks in.
## Rules
The actual rules — copy-pasteable snippets preferred over prose.
## Known deviations
Where the codebase doesn't yet follow the rule, with a pointer to the roadmap item that closes the gap.
Status¶
Statuses: - Implemented — content is current and authoritative. - Draft — content exists but hasn't been reviewed against current code. - Placeholder — file exists to mark the gap; content to be written from an audit + skeleton/reference-page extraction.
| Path | Status | Last reviewed | Notes |
|---|---|---|---|
i18n/translation-rules.md |
Draft | 2025-12-04 | Migrated from docs/I18N_GUIDELINES.md — verify against current LANGUAGE_CODE='nl-be' trick before promoting to Implemented |
development-workflow/overview.md |
Draft | 2026-04-14 | Migrated from docs/DEVELOPMENT_WORKFLOW.md — verify deploy section still matches Makefile + deploy.sh |
ui/search-sort-filter.md |
Implemented | 2026-04-18 | Authoritative for list/sort/filter stack; one known deviation (finance module) tracked in roadmap/backlog/finance-filter-unify.md |
ui/lists.md |
Implemented | 2026-04-18 | Mined from skeleton + reference impls (practices, patients, holders); covers file layout, two empty states, action column, density rules; defers sort/filter to search-sort-filter.md |
ui/forms.md |
Implemented | 2026-04-18 | Mined from skeleton + form-enhancements.{css,js} + holder_form (contextual reference); covers Alpine state, edit-mode safeguards, validation/auto-format hooks |
ui/detail-pages.md |
Implemented | 2026-04-18 | Mined from skeleton + entity/practice references; covers heading + actions, two-column card grid, audit footer, layout-table-vs-data-table distinction; substitution cheatsheet for the 15 <h5>-in-card-header audit hits |
ui/dropdowns.md |
Placeholder | — | Document SearchSelect widget + sort/filter conventions for <select> options |
ui/badges.md |
Implemented | 2026-04-18 | 4-state status palette + badge-type family modifier pattern; entity & movement variants; flags 2 internal inconsistencies (naming scheme, hardcoded oklch in module CSS) |
ui/design-tokens.md |
Implemented | 2026-04-18 | Full catalogue mined from static/css/base.css; includes audit cheatsheet for the 2026-04 hardcoded-value findings |
ux/page-states.md |
Placeholder | — | Empty / loading / error / no-permission states across all pages |
ux/feedback-and-confirmation.md |
Placeholder | — | Toast vs banner vs modal, confirmation dialog patterns |
ux/navigation.md |
Placeholder | — | Top nav, breadcrumbs, deep-linking, redirect-after-action rules |
ux/microcopy.md |
Placeholder | — | Tone, button verbs, error messages, FR/EN consistency |
backend/views.md |
Placeholder | — | Document SortableFilterableListMixin, HtmxResponseMixin, CBV conventions |
backend/models.md |
Placeholder | — | Document TimeStampedModel, AuditModel, SoftDeleteModel usage |
backend/migrations.md |
Placeholder | — | When to write a data migration, naming conventions |
backend/forms.md |
Placeholder | — | Django form / ModelForm conventions, complements ui/forms.md |
backend/admin.md |
Placeholder | — | When to register, list_display / list_filter / inline conventions |
security/multi-tenant-isolation.md |
Placeholder | — | High blast radius — practice scoping rules, queryset filtering |
security/auth-and-permissions.md |
Placeholder | — | Custom User, login, permission decorators / mixins |
security/pii-and-logging.md |
Placeholder | — | What never to log, Sentry scrubbing, PII categories |
celery/task-conventions.md |
Placeholder | — | Task naming, idempotency, retry, beat schedule, failure surfacing |
integrations/overview.md |
Placeholder | — | Shared connector patterns (auth, retry, pagination, persistence) |
integrations/doctolib.md |
Placeholder | — | Doctolib API, daily 3 AM sync, appointment reconciliation |
integrations/pennylane.md |
Placeholder | — | Pennylane Redshift + REST v2, dual-backend abstraction |
integrations/logosw.md |
Placeholder | — | File-based ingestion via apps/collection/ + apps/imports/ |
integrations/inpi.md |
Placeholder | — | INPI RNE via apps/annuaire/, code→label mappings |
imports/abstract-importer.md |
Placeholder | — | Document AbstractImporter lifecycle, ImportRow tracking, bulk mode |
testing/pytest-patterns.md |
Placeholder | — | Fixture conventions, integration vs unit boundary |
Roadmap for this folder¶
Linear bring-up (one-time)¶
- Beef up content — turn placeholders into Implemented files by mining: recent "consistency sweep" commits, reference implementations (patients/treatments/holders), and
templates/skeletons/. Track asroadmap/in-progress/guidelines-flesh-out.mdonce started. - Retroactive audit — run a subagent that grep-walks
templates/andapps/*/views.pyagainst every Implemented guideline. Output a ranked punch list toroadmap/backlog/. Triggered after step 1 stabilises a primitive. - Proactive enforcement — add a PostToolUse hook (or PR-time
ui-conformancesubagent) that re-runs the same checks on edited files. Should also flag new patterns that appear in code but aren't covered by any guideline — the drift-detection signal. - CLAUDE.md tightening — once the guidelines folder is the single pointer surface, the CLAUDE.md "UI Design System" section becomes a thin index into
guidelines/ui/rather than a partial duplicate.
Ongoing — audit vs. challenge¶
Two recurring activities, different questions:
- Audit (continuous, mechanical) — "does the code follow the rules?" — surfaces violations of existing rules. Output: backlog entries to fix code. Eventually hook-driven.
- Challenge (periodic, judgmental) — "are the rules the right rules?" — surfaces missing rules, stale assumptions, primitives that should exist but don't. Output: ideas to evolve guidelines themselves.
Audit alone produces a locally-consistent codebase converging on possibly-suboptimal rules. Challenge alone produces evolving rules nobody adopts. Need both.
Challenge pass — template¶
Run a challenge against one primitive at a time. Cap at 1-2 challenges per quarter, only against primitives showing a real signal (see triggers below). Resist the urge to re-litigate everything.
Triggers — run a challenge when one is true:
- Recurring deviations in audit output for the same primitive (3+ deferred items in a row → the rule is missing, not the code is wrong).
- User pain surfaces in real flows (e.g. "I had to fix the dropdown sorting on every form" → ui/dropdowns.md needs a challenge).
- External drift — a new reference design system landed (Material You, Geist, Primer) and our equivalent primitive feels old.
- Time-based — primitive is Implemented but hasn't been reviewed in >12 months.
Process:
-
Pick one primitive. Write the trigger in one sentence: "Challenge
ui/forms.mdbecause [reason]." If you can't fill that sentence, don't run the challenge. -
Spawn a challenge subagent. Skeleton prompt:
Read
guidelines/<primitive>.md. Then: - Survey 5 real implementations in the codebase that should follow it. Note where the rule fits, where it doesn't, where the implementation diverged anyway. - Compare to 1-2 external references (name them: e.g. GitHub Primer forms, Vercel Geist forms). - Identify 3 things the current rule does not address but should. - Identify 1-2 rules that look outdated or rarely useful and propose retiring or rewording them. - Output: a single Markdown report under 500 words, structured as "Keep / Change / Add / Drop." Don't write to any guideline file — just propose. -
Triage the report. For each Keep/Change/Add/Drop:
- Quick wins (clear consensus, low risk) → edit the guideline directly, bump
Last reviewed, note the change in commit message. - Bigger changes (need design discussion) → file as
roadmap/ideas/guideline-<primitive>-challenge.md. Promote to backlog only after discussion. -
Rejected → note inline in the guideline as a "Considered and rejected" anchor (so the next challenge doesn't re-propose it).
-
Bump status if material. A challenge that significantly rewrites a guideline resets its status to Draft until re-reviewed against current code. A challenge that confirms-with-tweaks keeps it Implemented but updates
Last reviewed. -
Close the loop. Add a one-liner to the bottom of the challenged guideline: "Last challenged: YYYY-MM-DD — see
roadmap/ideas/...(orcommit <sha>) for outcome."
Output convention:
- Challenge reports go to roadmap/ideas/guideline-<primitive>-challenge-YYYY-MM.md if bigger than a quick edit.
- Audit reports go to roadmap/backlog/<primitive>-audit-YYYY-MM.md (the convention used 2026-04).
What NOT to challenge: - Placeholders. If the guideline isn't Implemented yet, you're writing it, not challenging it. - Rules that came from a recent incident or post-mortem. Those have their reason in the commit message; respect it. - Anything you'd reword purely for style. Challenges need to surface a real gap, not a rewrite for taste.
Update this README's status table whenever a file's status changes — it is the only manually-maintained index.