Files
dyolink/backend
Amin Mousavi 3f97940a16 feat: wire voice entry into the treatment workspace
Makes the feature reachable end to end: availability is fetched alongside the
catalogs, the capture hook drives the segmented control, and confirming the
review sheet appends a new detail.

Confirm always appends — it never edits an existing detail and never calls
onAddDetail. Ticked rows land on top of the seeded defaults, so unticking the
type row leaves the appointment-purpose default rather than a blank. Lab-side
rows ride on a lab case draft keyed by the detail's *client* id, so a brand-new
unsaved detail can carry a lab, due date and per-tooth prosthesis map.

Availability comes from the API rather than a NEXT_PUBLIC_* var, since those are
baked in at build time; a failure fetching it degrades to no microphone rather
than taking the treatment tab down.

From review of this commit:

- Unticking "teeth" while leaving "prosthesis" ticked attached prosthesis rows
  for teeth the detail does not contain. Nothing downstream filters them —
  assertCompleteToothProsthesisMap only checks detail-teeth ⊆ map, never the
  reverse — so they would have reached task generation as lab work for teeth
  nobody is treating. The map is now filtered to the detail's own teeth.
- The microphone was gated on the URL locale while the server resolved
  everything from req.user.language. Those diverge (a bookmarked /fa/ URL, a
  language toggle whose save failed), which would transcribe Persian with an
  English hint and anchor "next Thursday" to a Monday week instead of a Saturday
  one — or 403 from a visibly-enabled button. The client now sends the locale the
  microphone was offered in, so the gate and the request agree by construction.

Also fixed from the previous review: a civil YYYY-MM-DD date rendered a day
early west of Greenwich (parsed as UTC midnight); the missing-teeth list
hardcoded the Arabic comma for all locales; and voiceApply had no ICU plural, so
the common single-field case read "Apply 1 fields".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 23:05:30 +03:30
..

Dyolink — Backend (NestJS)

Prerequisites

  • Node.js 20+ and npm
  • PostgreSQL reachable from your machine — either installed locally or run via Docker (see below)

First-time setup

  1. Clone the monorepo and go to the backend app:

    git clone <repository-url> dyolink
    cd dyolink/backend
    
  2. Install dependencies

    npm install
    
  3. Environment

    Copy .env.example to .env and set at least:

    • DATABASE_URL — PostgreSQL connection string for your dev database
    • JWT_SECRET — strong secret for signing tokens
      Do not commit .env.
  4. Database for local dev

    Option A — Postgres in Docker (no local install, e.g. Mac)
    From backend/, with .env present (copy from .env.example first):

    • Ensure DATABASE_URL uses localhost as the host (not postgres). Match user, password, and DB name to POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB in the same file.
    docker compose -f docker-compose.postgres.yml up -d
    

    Wait until Postgres is healthy (docker compose -f docker-compose.postgres.yml ps). The container creates the database on first start.

    To stop Postgres (data is kept in the named volume): docker compose -f docker-compose.postgres.yml down

    Option B — Postgres installed on the machine
    Create an empty database, then point DATABASE_URL at it.

  5. Generate Prisma Client

    npm run prisma:generate
    
  6. Apply migrations (creates/updates tables to match prisma/schema.prisma)

    npm run prisma:migrate
    

    This runs prisma migrate dev. Use it during development when the schema changes.

  7. Seed (optional — reference data only)

    npm run prisma:seed
    

    This does not wipe your database. It only upserts lookup data: organization types (CLINIC, LAB), subscription plans, and tab permissions. Existing users, organizations, memberships, patients, appointments, and links are left unchanged.

    To start from an empty database with fresh tables and reference data, see Reset database (clean slate) below.

Reset database (clean slate)

Use this when you want to delete all application data (users, organizations, patients, sessions, etc.) and rebuild the schema from migrations, then run the seed.

From backend/:

npx prisma migrate reset

Prisma will prompt for confirmation, drop the database, re-apply all migrations, and run prisma/seed.ts automatically.

What gets removed: everything in the database, including organizations and all related rows.

What the seed adds back: only reference data (types, plans, permissions) — not demo users or organizations. Register again or use your own test data after a reset.

Docker Postgres dev: if you also want to wipe the Docker volume (not only tables), stop the container and remove the volume:

docker compose -f docker-compose.postgres.yml down -v
docker compose -f docker-compose.postgres.yml up -d
npm run prisma:migrate
npm run prisma:seed

Do not run migrate reset against production or shared staging databases.

Run (development)

npm run start:dev

API listens on http://localhost:3000 by default (PORT in .env).

If the frontend runs on another origin (e.g. http://localhost:3001), set FRONTEND_URL in .env to that URL (CORS and invite links use it).

After pulling latest main

git pull
npm install
npm run prisma:generate
npm run prisma:migrate

If teammates added migrations, the migrate step above applies them. Resolve migration conflicts locally before pushing.

Useful commands

Command Purpose
npm run prisma:generate Regenerate client after schema.prisma changes
npm run prisma:migrate Dev migrations (migrate dev)
npm run prisma:deploy Production-style apply (migrate deploy) — e.g. CI/containers
npm run prisma:seed Upsert reference data only (does not clear existing rows)
npx prisma migrate reset Drop DB, re-migrate, run seed — dev clean slate
npm run build Compile Nest app
npm run start:prod Run compiled app (node dist/main)

Docker

File Purpose
Dockerfile Production API image
docker-compose.postgres.yml Local dev Postgres only (port mapped to host)

For full-stack deployment and CI, see the repository root README.md.