v2.1.0
First release cut through the automated pipeline. The eleven modules that
landed since 2.0.0 — payments, copilot, verifactu, recalls, schedules,
notifications, periodontogram, clinical_notes, accounting_export,
migration_import, whatsapp_kapso — are listed per-PR in the generated
release notes and documented in their own module CHANGELOGs; the
narrative version of that work belongs to the next major.
Added
-
Prebuilt images and a one-command install. Tagging a release now
builds and publishesghcr.io/martinezsalmeron/dentalpin-backendand
-frontend, and publishes the GitHub Release with notes taken from
this file.docker-compose.prod.ymlruns the stack straight from those
images with no clone and no build; a Caddy container fronts both
services on a single origin, so TLS is provisioned automatically from
PUBLIC_URLand there is no CORS to configure. One image serves every
deployment — Nuxt overridesruntimeConfig.public.apiBaseUrlfrom
NUXT_PUBLIC_API_BASE_URLat boot rather than baking the URL in. -
First-time setup assistant (issue #85). A fresh install (no users)
now bootstraps from the UI:GET /api/v1/auth/setup/statusreports
whether the system is initialized, andPOST /api/v1/auth/setup
atomically creates the first clinic + admin user + admin membership and
returns tokens. The endpoint is self-closing (409 once any account
exists). The frontend redirects unauthenticated visitors of an empty
system to a 2-step/setupwizard (admin account → clinic basics);
remaining configuration is handled by the existing onboarding checklist.
Changed
-
Removed the public
POST /api/v1/auth/registerendpoint. It created
orphan users with no clinic membership (unusable, and unused by the UI);
the first-run setup assistant replaces it. -
Alembic history squashed. The 29-migration main-linear chain
inherited from Fase A collapsed into one0001_core_initialfor
core tables + 11 module-owned initials under
backend/app/modules/<name>/migrations/versions/<mod>_0001_initial.py.
Each module's initial lives in its own package so community module
authors can pattern-match their own migrations on the official
examples. Cross-module FKs live on the "late" side — the only
circular dep (appointment_treatments.planned_treatment_item_id
→planned_treatment_items) is created intp_0001after both
tables exist. Round-tripupgrade head → downgrade base → upgrade headis clean andtest_alembic_roundtripno longer xfails.
Fixed
-
docker-compose.ymlhardcodedhttp://localhost:8000as the frontend's
API base (build arg + runtime env), so the documentedAPI_BASE_URLin
.envhad no effect and the app was unreachable from any device other
than the Docker host — the browser resolvedlocalhostto itself.
Both now read${API_BASE_URL:-http://localhost:8000}. -
Clinic timezone selector only offered 15 curated European/American
zones. It now lists the runtime's full IANA set (Intl.supportedValuesOf)
in a searchableUSelectMenu; the backend already validated against
zoneinfo, so any IANA id was accepted all along.
Install
curl -O https://raw.githubusercontent.com/martinezsalmeron/dentalpin/main/docker-compose.prod.yml
curl -O https://raw.githubusercontent.com/martinezsalmeron/dentalpin/main/Caddyfile
curl -o .env https://raw.githubusercontent.com/martinezsalmeron/dentalpin/main/.env.prod.example
# set PUBLIC_URL, POSTGRES_PASSWORD, SECRET_KEY
# and DENTALPIN_VERSION=2.1.0 to pin this release, then:
docker compose -f docker-compose.prod.yml up -dImages: ghcr.io/martinezsalmeron/dentalpin-backend:2.1.0 · ghcr.io/martinezsalmeron/dentalpin-frontend:2.1.0
What's Changed
- feat(modules): admin module manager UI + reconcile base_revision by @martinezsalmeron in #54
- fix(plugins): unblock restart + alembic under uvicorn --reload by @martinezsalmeron in #57
- fix(plugins): harden module uninstall pipeline by @martinezsalmeron in #59
- feat(patients): redesign info tab with medical snapshot first (#52) by @martinezsalmeron in #58
- Feat/docs reorg 67 by @martinezsalmeron in #69
- feat(currency): unify currency as clinic-level setting (#68) by @martinezsalmeron in #70
- refactor(core): Fase 1 — drop dead code + simplify plugin layer by @martinezsalmeron in #71
- fix(agenda): paint per-day clinic_closed time in week view + CI lint by @martinezsalmeron in #72
- feat(recalls): patient call-back workflow (issue #62) by @martinezsalmeron in #74
- feat(payments): lists redesign + patient ledger subtab + module by @martinezsalmeron in #77
- feat(periodontogram): SEPA snapshot module by @martinezsalmeron in #80
- Feat/periodontogram module by @martinezsalmeron in #84
- docs(readme): introduce AI Copilot agentic feature by @martinezsalmeron in #86
- feat(accounting_export): gestoría export module for invoices + payments (#73) by @martinezsalmeron in #87
- feat(notifications): multi-channel gateway + outbox (Phase 1, #63) by @martinezsalmeron in #88
- feat(whatsapp_kapso): WhatsApp via Kapso + bidirectional replies (Phase 2, #63) by @martinezsalmeron in #89
- fix(docs): repair docs-portal dead links + refresh events catalog by @martinezsalmeron in #90
- fix: audit remediation batch — contained security & correctness fixes by @martinezsalmeron in #96
- fix(billing,payments): S3 money-path concurrency guards (C1/C2/C4) — closes #97 by @martinezsalmeron in #98
- fix(ci,docs): S4 — the module-contract CI gates CLAUDE.md advertises (closes #94) by @martinezsalmeron in #99
- fix(frontend): S5 silent-failure fixes, tranche 1 (useApi query + odontogram error state) by @martinezsalmeron in #100
- docs: add Telegram community channel to README by @martinezsalmeron in #102
- feat(i18n): add French translation by @ermix3 in #103
- fix(tests,i18n): stop CI connection exhaustion; correct French dental terms by @martinezsalmeron in #104
- fix(catalog): surface API error detail in useCatalog toasts by @martinezsalmeron in #106
- docs(collaborators): English translation + per-country Founding Partner cap by @martinezsalmeron in #107
- feat(deploy): prebuilt images on ghcr + one-command production install by @martinezsalmeron in #109
- chore(github): issue templates, security policy, funding link by @martinezsalmeron in #110
- fix(release): install snippet pointed at files the tag does not have by @martinezsalmeron in #111
- docs(changelog): cut 2.1.0 by @martinezsalmeron in #120
New Contributors
Full Changelog: v2.0.0...v2.1.0