Use this file to discover all available pages before exploring further.
Clinica is built as a modular monolith: a single Node.js process organized into self-contained feature modules, each responsible for its own routing, business logic, and data access. This approach keeps the codebase navigable and cohesive while avoiding the operational overhead of microservices. The backend exposes a REST API consumed by a React single-page application, and the entire system — API, frontend, and database — runs as a three-service Docker Compose stack.
Each module lives under src/modules/<name>/ and contains exactly three files: a routes file that registers Express handlers, a controller that parses requests and sends responses, and a service that holds all business logic and database queries.
auth
Handles user registration, login, and JWT issuance. Passwords are hashed with bcrypt before storage. The issued token carries the user’s id and role.
doctor
CRUD operations for doctor profiles. Links each doctor record to a users row via user_id, allowing doctors to authenticate with the same credential system as patients.
booking
Creates, lists, and manages appointments. Enforces the unique_booking constraint (one booking per doctor per date+time slot) and validates that bookings are not placed in the past.
availability
Manages a doctor’s recurring weekly schedule (doctor_availability) and one-off blocked periods (doctor_exceptions). The frontend uses this data to render only valid time slots.
Two utilities in src/shared/ are imported by any module that needs them, keeping infrastructure concerns out of feature code.shared/db.js — exports a single pg.Pool instance configured from the DATABASE_URL environment variable. All modules query through this shared pool; there is no per-module connection management.shared/email.service.js — exports a sendEmail({ to, subject, html }) function backed by a Nodemailer Gmail transport. Credentials are read from EMAIL_USER and EMAIL_PASS environment variables.
The reminder job starts automatically after the server boots and runs for the lifetime of the process. It does not require a separate worker process or queue.
src/jobs/reminder.job.js schedules a cron task with the expression */5 * * * * (every five minutes). On each tick it executes two queries against the bookings table:
1-hour reminder — finds bookings whose date + time falls between 55 and 65 minutes from now and where reminder_1h_sent = FALSE. Sends an email to the patient, then sets reminder_1h_sent = TRUE.
24-hour reminder — same pattern with a 23–25 hour window and the reminder_24h_sent flag.
Both flags are stored on the bookings row so reminders are sent exactly once even if the job runs multiple times within the window.
services: db: # postgres:15, port 5432 (internal) api: # Node.js backend, port 3000 frontend: # Vite dev server, port 5173
api declares depends_on: db and polls the database with SELECT 1 every two seconds before seeding the admin user and starting the HTTP listener. frontend declares depends_on: api. The database volume (db_data) persists across container restarts.
init.sql runs only once — when the db_data volume is first created. To re-run it, remove the volume with docker compose down -v before starting the stack again.