Checklist: new module
Lookup-optimized version of docs/technical/creating-modules.md. Tick each box. For deeper rationale on any line, follow the link.
Skeleton
- [ ]
backend/app/modules/<name>/created with__init__.py,models.py,router.py,service.py,migrations/versions/ - [ ] Module class subclasses
BaseModule(backend/app/core/plugins/base.py) - [ ]
manifest = {...}set as class attribute (seeManifestinbackend/app/core/plugins/manifest.pyfor the full schema) - [ ] Entry point registered in
backend/pyproject.tomlunder[project.entry-points."dentalpin.modules"] - [ ]
get_models(),get_router(),get_tools()implemented (the last is mandatory even if empty — seeBaseModule)
Manifest fields
- [ ]
name,version(semver),summary,author,license,category(official|community) - [ ]
depends— every module accessed across the boundary must be listed - [ ]
installable,auto_install,removableset deliberately (default optional modules toauto_install=False) - [ ]
role_permissions— every permission listed must also be returned byget_permissions()
Database
- [ ]
clinic_idcolumn on every multi-tenant table, indexed - [ ] UUID primary keys, TIMESTAMPTZ timestamps, JSONB for flexible fields
- [ ] Soft delete via
statusfor patient-touching data - [ ]
clinic_idfilter in every query (also inside agent tool handlers)
Migrations
- [ ] Migrations live in
backend/app/modules/<name>/migrations/versions/ - [ ] First migration of the module sets
branch_labels = ("<name>",) - [ ] No revision threads through another module's chain (uninstall safety, issue #56 — see ADR 0002)
- [ ] Cross-module FKs only against modules in
manifest.depends - [ ]
alembic upgrade headsworks clean from base
Permissions
- [ ]
get_permissions()returns["resource.action", ...](no module prefix — registry adds it) - [ ] Endpoints protected with
require_permission("<module>.resource.action") - [ ] User-facing permissions added to
frontend/app/config/permissions.ts
Events
- [ ] New event types added to
backend/app/core/events/types.pyEventType - [ ] Subscribers registered via
get_event_handlers() - [ ] No direct imports of services from modules outside
depends— use the event bus (ADR 0003)
Agent tools
Every module is agent-addressable. Expose the operations an AI agent should be able to drive.
- [ ]
backend/app/modules/<name>/tools.pywith aget_tools() -> list[Tool], returned by the module class'sget_tools() - [ ] Each handler wraps an existing service method — no business logic duplicated
- [ ] Each handler filters by
ctx.clinic_id(multi-tenancy — same rule as routers) - [ ] Handlers return native values (UUID/Decimal/datetime/Pydantic) —
jsonifyat the chokepoint coerces; no manualstr()/.isoformat()/float() - [ ] PII fields use redactor-known keys (
full_name,phone,email,dni,*_id) so they tokenize before reaching the cloud - [ ]
permissions=[...]matches the gating RBAC string the HTTP route uses - [ ]
categoryset conservatively:WRITEfor mutations,DESTRUCTIVEfor deletes / irreversible side-effects - [ ]
exposes_free_text=Trueon any tool returning free prose (excluded from the cloud LLM path under redaction) - [ ] Tools listed under "Tools exposed" in the module CLAUDE.md
- [ ] See
docs/technical/copilot-agentic-architecture.md§3
Frontend layer
- [ ]
backend/app/modules/<name>/frontend/exists withnuxt.config.ts,pages/,components/ - [ ]
manifest["frontend"]["layer_path"] = "frontend" - [ ] Navigation entries declared in
manifest["frontend"]["navigation"]with namespacedpermission
Tests
- [ ] Unit + integration tests under
backend/tests/ - [ ] If
removable=True: round-trip uninstall test (seebackend/tests/test_uninstall_roundtrip.py) - [ ]
python -m pytest -vgreen; manifest-consistency tests still pass
Docs
- [ ]
backend/app/modules/<name>/CLAUDE.mdwritten fromdocs/checklists/module-claude-template.md - [ ]
backend/app/modules/<name>/CHANGELOG.mdstarted with## Unreleased - [ ]
python backend/scripts/generate_catalogs.pyre-run;docs/modules-catalog.mdanddocs/events-catalog.mdcommitted - [ ] If a new domain term: appended to
docs/glossary.md - [ ] If an architectural decision was made: ADR added under
docs/adr/NNNN-title.md
Reference modules to copy from
- Foundational, simple, non-removable →
backend/app/modules/patients/ - Removable, isolation-critical →
backend/app/modules/schedules/(issue #39) - Heavy
depends, event-driven →backend/app/modules/treatment_plan/ - Compliance/integration with external system →
backend/app/modules/verifactu/