Files
temetro/backend
Khalid Abdi 233ce9f854 fix: QR wallet pairing broken by multi-clinic routing (v0.8.1)
QR "scan to connect" pairing has no wallet number, so nothing registered
the request with the relay and the scanning device's response was rejected
("unknown or expired request"). The backend now pre-registers the pairing
request over the relay's new hub:expect event on POST /pair, and
re-registers still-pending requests on hub (re)connect so routing survives
a relay restart. /pair now requires the clinic to have joined the network
(clear 409, surfaced in the import dialog, localized in all five langs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 19:16:33 +03:00
..
2026-06-17 20:50:09 +03:00

temetro backend

TypeScript + Express + Postgres API for temetro. Authentication is powered by Better Auth (email/password with verification, password reset, and multi-tenant organizations with role-based access control). Patient records are scoped to an organization (a clinic) and exposed over a small REST API that mirrors the frontend's Patient shape exactly.

Quick start (Docker)

docker compose pull          # fetch prebuilt images from Docker Hub (fast)
docker compose up -d         # db + backend + frontend — no setup needed

docker compose up --build instead builds from source (for development). The Compose file references the published khalidxv/temetro-backend and khalidxv/temetro-frontend images with a build fallback, so the same file serves both clinics and developers. Update with docker compose pull && docker compose up -d (see ../RELEASING.md).

No .env or manual secret generation is required: on first start the backend generates any missing secrets (BETTER_AUTH_SECRET, AI_CREDENTIALS_KEY) and persists them to a Docker volume, so they stay stable across restarts. Create a .env (from .env.example) only if you want to override something — your own auth secret, SMTP, etc.

Run only the API + database: docker compose up db backend. Browse the DB with Adminer: docker compose --profile tools up adminerhttp://localhost:8080.

Migrations are applied automatically on container start (node dist/migrate.js).

Local development (without Docker)

npm install
cp .env.example .env          # point DATABASE_URL at a local Postgres (localhost:5432)
npm run db:migrate            # apply migrations (drizzle-kit)
npm run dev                   # tsx watch on http://localhost:4000

Auth & schema workflow

The Better Auth tables are generated into src/db/schema/auth.ts from src/auth.ts. Re-run after changing auth config/plugins, then regenerate the SQL migration:

npm run auth:generate   # better-auth CLI -> src/db/schema/auth.ts
npm run db:generate     # drizzle-kit -> ./drizzle/*.sql
npm run db:migrate      # apply

API

All patient routes require a signed-in user (Better Auth session cookie) and an active organization; access is gated by the caller's clinic role.

Method Path Permission Notes
GET /api/patients patient:read list patients in the active clinic
GET /api/patients/:fileNumber patient:read one patient (404 if absent)
POST /api/patients patient:write create (409 if file number exists)
PUT /api/patients/:fileNumber patient:write replace the full record
DELETE /api/patients/:fileNumber patient:delete remove a patient

Other org-scoped resources follow the same pattern (CRUD, role-gated):

Resource Base path Permission Notes
Appointments /api/appointments appointment:* list / create / update / delete
Prescriptions /api/prescriptions prescription:* prescriber defaults to the signed-in user
Tasks /api/tasks task:* PATCH /:id for partial updates / the done toggle
Notes /api/notes — (author-scoped) private to the signed-in author
Activity GET /api/activity — (any member) audit feed of record changes
Analytics GET /api/analytics — (any member) computed clinic aggregates
Conversations /api/conversations — (participant-scoped) staff messaging; real-time over Socket.io
Notifications /api/notifications — (per-recipient) auto-generated; read-all + per-id read
Version GET /api/version — (public) running version + GitHub-release update check
Network GET /api/network — (public) detected LAN addresses for sharing the app

Real-time messaging and live notifications are delivered over Socket.io, attached to the same HTTP server; the handshake is authenticated with the Better Auth session cookie.

Auth endpoints (sign up / in / out, verify email, reset password, organizations & invitations) are served by Better Auth under /api/auth/*.

Roles

Role Patient access Prescriptions Lab results Clinic management
owner read / write / delete read / write / delete read / write full
admin read / write / delete read / write / delete read / write members, invitations, settings
doctor / member (clinician) read / write read / write / delete read / write
reception read / write (demographics)
pharmacy read read / write
lab read read / write

Environment

See .env.example. If SMTP_HOST is unset, verification / reset / invitation emails are printed to the server console instead of being sent — no setup required for local development.