mirror of
https://github.com/temetro/temetro.git
synced 2026-08-27 19:06:52 +00:00
Add TypeScript + Express + Postgres backend with Better Auth
Implements the first temetro backend: an Express 5 API on Postgres via Drizzle ORM, with authentication and multi-tenant clinics powered by Better Auth. - Auth: email/password with required email verification, password reset, rate limiting, CSRF/trusted-origins, secure cookies, session audit hook. - Organizations (clinics) with RBAC (owner/admin/member/viewer) and an extended `patient` permission set; member invitations by email. - Org-scoped patient records mirroring the frontend Patient shape, with CRUD endpoints gated by permission (read/write/delete). - Email helper logs links to the console when SMTP is unset (zero-setup local dev); Dockerfile + docker-compose (db + backend + frontend) with migrations applied on startup and a configurable Postgres host port. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# temetro backend
|
||||
|
||||
TypeScript + Express + Postgres API for [temetro](../). Authentication is powered by
|
||||
[Better Auth](https://better-auth.com) (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)
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# set a strong secret:
|
||||
# openssl rand -base64 32 -> paste into BETTER_AUTH_SECRET
|
||||
docker compose up # db + backend + frontend
|
||||
```
|
||||
|
||||
- Frontend → http://localhost:3000
|
||||
- Backend → http://localhost:4000 (health: `GET /health`, auth health: `GET /api/auth/ok`)
|
||||
- Postgres → localhost:5432
|
||||
|
||||
Run only the API + database: `docker compose up db backend`.
|
||||
Browse the DB with Adminer: `docker compose --profile tools up adminer` → http://localhost:8080.
|
||||
|
||||
Migrations are applied automatically on container start (`node dist/migrate.js`).
|
||||
|
||||
## Local development (without Docker)
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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 |
|
||||
|
||||
Auth endpoints (sign up / in / out, verify email, reset password, organizations & invitations) are
|
||||
served by Better Auth under `/api/auth/*`.
|
||||
|
||||
### Roles
|
||||
|
||||
| Role | Patient access | Clinic management |
|
||||
| --- | --- | --- |
|
||||
| `owner` | read / write / delete | full |
|
||||
| `admin` | read / write / delete | members, invitations, settings |
|
||||
| `member` (clinician) | read / write | — |
|
||||
| `viewer` | read | — |
|
||||
|
||||
## 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.
|
||||
Reference in New Issue
Block a user