# dsnme013/cannda-health architecture

> Architecture diagram of the GitHub repository dsnme013/cannda-health, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-21). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/dsnme013/cannda-health
- Repository: https://github.com/dsnme013/cannda-health

## Overview

1. **Repository shape**
   - This is a monorepo with three main parts: a **Next.js frontend**, a **Fastify/Node.js backend API**, and a **PostgreSQL/PostGIS database** with migration and sync scripts.
   - The backend is the primary application server; the frontend is a separate client app that talks to it over HTTP.

2. **Frontend boundary**
   - The frontend lives under `frontend/src/app` using the Next.js App Router.
   - Main user-facing flows are:
     - homepage/search entry,
     - search results,
     - clinic detail pages,
     - appointment booking pages.
   - UI is composed from reusable components such as `SearchInterface`, `FilterPanel`, `Map`, `ClinicCard`, and `AppointmentBooking`, with custom hooks for debounce, geolocation, and search state.

3. **Backend API boundary**
   - The backend is organized around route modules: `search`, `clinics`, `locations`, `appointments`, and `sync`.
   - `backend/server.js` is the API entry point, and `backend/routes/index.js` likely wires the route modules together.
   - This backend is the single source of truth for provider lookup, availability/booking, and data synchronization operations.

4. **Search and discovery subsystem**
   - Search is split across `backend/services/search-engine.js`, `location-service.js`, and `utils/distance.js`.
   - The architecture suggests a hybrid search flow:
     - text / full-text lookup in PostgreSQL,
     - spatial filtering with PostGIS for radius-based queries,
     - ranking or enrichment through service-layer logic.
   - The frontend’s search page and map consume these search results to display providers near a location.

5. **Geospatial handling**
   - Location is a first-class concern throughout the system.
   - The backend has a dedicated `geocoding-service` and `locations` routes, which indicates addresses or user-entered places are converted into coordinates before search.
   - PostGIS in PostgreSQL is important here: it supports distance queries, geo-indexing, and provider/radius filtering.

6. **Appointment workflow**
   - Appointment behavior is separated into `appointments` routes and `appointment-service`.
   - The frontend booking page and booking component likely call these endpoints to fetch availability and create bookings.
   - The README mentions virtual and in-person appointments, so the booking layer likely normalizes multiple appointment types behind one API.

7. **External data ingestion**
   - `backend/services/alberta-api.js` and `database/scripts/sync-alberta-data.js` show an integration with an external Alberta healthcare data source.
   - `data-sync.js` suggests a controlled import pipeline that pulls external provider data into the local database.
   - The `sync` route exposes this functionality operationally, likely for manual or scheduled refreshes.

8. **Persistence and schema management**
   - Database structure is managed with SQL files under `database/migrations` plus `database/init.sql`.
   - Seed migrations indicate the database is preloaded with sample or baseline healthcare data.
   - `database/scripts/migrate.js` is the schema-management entry point, making schema changes explicit and versioned.

9. **Caching and operational controls**
   - Redis is configured separately in `backend/config/redis.js` and used by middleware such as `cache.js` and `rate-limit.js`.
   - That means expensive search or location queries can be cached, and API traffic can be throttled at the edge of the backend.
   - `validation.js` indicates request payloads are checked before business logic runs.

10. **Request/data flow**
   - A typical user flow is: frontend collects search criteria or location → backend geocodes if needed → backend queries PostgreSQL/PostGIS and possibly Redis → frontend renders provider cards, map markers, and clinic details.
   - For booking, the frontend sends appointment requests to the backend → backend validates and processes them through the appointment service → database state is updated.

11. **Deployment and runtime packaging**
   - Both frontend and backend have Dockerfiles, and the repo includes `docker-compose.yml`, so the system is designed to run as containerized services.
   - The top-level `scripts/setup.sh` and `scripts/deploy.sh` indicate environment bootstrap and deployment automation around those containers.

12. **Architecture takeaway for diagrams**
   - The key boundaries to draw are:
     - browser/client UI,
     - backend API,
     - PostgreSQL/PostGIS datastore,
     - Redis cache,
     - external Alberta data source / geocoding provider.
   - The most important data flows are search/location lookup, clinic detail retrieval, appointment booking, and external data sync into the local database.

Main entry points: [`backend/routes/index.js`](https://github.com/dsnme013/cannda-health/blob/main/backend/routes/index.js) (Routes), [`database/init.sql`](https://github.com/dsnme013/cannda-health/blob/main/database/init.sql) (Schema), [`frontend/src/lib/api.js`](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/lib/api.js) (API Client), [`frontend/src/components/SearchInterface.jsx`](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/SearchInterface.jsx) (Search UI)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_frontend["Frontend"]
  node_frontend_home["Home<br/>Next.js page<br/>[page.js]"]
  node_frontend_search["Search<br/>Next.js page<br/>[page.js]"]
  node_frontend_clinic["Clinic<br/>Next.js page<br/>[page.js]"]
  node_frontend_booking["Booking<br/>Next.js page<br/>[page.js]"]
  node_frontend_search_ui["Search UI<br/>React components"]
  node_frontend_map["Map<br/>React component<br/>[Map.jsx]"]
  node_frontend_clinic_card["Clinic Card<br/>React component<br/>[ClinicCard.jsx]"]
  node_frontend_booking_comp["Booking Form<br/>React component"]
  node_frontend_hooks["Hooks<br/>[useSearch.js]"]
  node_frontend_api["API Client<br/>HTTP client<br/>[api.js]"]
end

subgraph group_backend["Backend API"]
  node_backend_server["Server<br/>Fastify entrypoint<br/>[server.js]"]
  node_backend_routes["Routes<br/>Route wiring<br/>[index.js]"]
  node_backend_search["Search API<br/>Route module<br/>[search.js]"]
  node_backend_clinics["Clinics API<br/>Route module<br/>[clinics.js]"]
  node_backend_locations["Locations API<br/>Route module<br/>[locations.js]"]
  node_backend_appointments["Appointments API<br/>Route module<br/>[appointments.js]"]
  node_backend_sync["Sync API<br/>Route module<br/>[sync.js]"]
  node_backend_search_engine["Search Engine<br/>[search-engine.js]"]
  node_backend_location_service["Location Service"]
  node_backend_geocoding["Geocoding"]
  node_backend_appointments_service["Booking Service"]
  node_backend_data_sync["Data Sync<br/>[data-sync.js]"]
  node_backend_alberta_api["Alberta API<br/>External integration<br/>[alberta-api.js]"]
  node_backend_middleware["Middleware<br/>Cross-cutting<br/>[cache.js]"]
  node_backend_config["Config<br/>[database.js]"]
end

subgraph group_database["Database"]
  node_database_schema[("Schema<br/>[init.sql]")]
  node_database_migrations["Migrations"]
  node_database_migrate["Migrate Tool<br/>Script<br/>[migrate.js]"]
  node_database_sync_script["Sync Script"]
end

subgraph group_ops["Ops"]
  node_redis[("Redis<br/>Cache store<br/>[redis.js]")]
  node_external_client(("Client Apps<br/>Browser/client"))
end

node_external_client -->|"uses"| node_frontend_home
node_frontend_home -->|"renders"| node_frontend_search_ui
node_frontend_search -->|"renders"| node_frontend_search_ui
node_frontend_search -->|"renders"| node_frontend_map
node_frontend_search -->|"lists"| node_frontend_clinic_card
node_frontend_clinic -->|"renders"| node_frontend_clinic_card
node_frontend_booking -->|"renders"| node_frontend_booking_comp
node_frontend_search_ui -->|"uses"| node_frontend_hooks
node_frontend_map -->|"fetches"| node_frontend_api
node_frontend_search_ui -->|"calls"| node_frontend_api
node_frontend_clinic_card -->|"calls"| node_frontend_api
node_frontend_booking_comp -->|"calls"| node_frontend_api
node_frontend_api -->|"HTTP"| node_backend_server
node_backend_server -->|"registers"| node_backend_routes
node_backend_routes -->|"includes"| node_backend_search
node_backend_routes -->|"includes"| node_backend_clinics
node_backend_routes -->|"includes"| node_backend_locations
node_backend_routes -->|"includes"| node_backend_appointments
node_backend_routes -->|"includes"| node_backend_sync
node_backend_search -->|"uses"| node_backend_search_engine
node_backend_search -->|"uses"| node_backend_location_service
node_backend_locations -->|"uses"| node_backend_geocoding
node_backend_appointments -->|"uses"| node_backend_appointments_service
node_backend_sync -->|"uses"| node_backend_data_sync
node_backend_data_sync -->|"fetches"| node_backend_alberta_api
node_backend_search_engine -->|"queries"| node_database_schema
node_backend_location_service -->|"queries"| node_database_schema
node_backend_appointments_service -->|"updates"| node_database_schema
node_backend_geocoding -->|"reads"| node_database_schema
node_backend_search_engine -->|"caches"| node_redis
node_backend_middleware -->|"uses"| node_redis
node_backend_server -->|"applies"| node_backend_middleware
node_database_migrations -->|"builds"| node_database_schema
node_database_migrate -->|"runs"| node_database_migrations
node_database_sync_script -->|"invokes"| node_backend_data_sync
node_database_sync_script -->|"loads"| node_database_schema
node_backend_config -->|"configures"| node_database_schema
node_backend_config -->|"configures"| node_redis

click node_frontend_home "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/page.js"
click node_frontend_search "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/search/page.js"
click node_frontend_clinic "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/clinic/[id]/page.js"
click node_frontend_booking "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/appointment/page.js"
click node_frontend_search_ui "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/SearchInterface.jsx"
click node_frontend_map "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/Map.jsx"
click node_frontend_clinic_card "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/ClinicCard.jsx"
click node_frontend_booking_comp "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/AppointmentBooking.jsx"
click node_frontend_hooks "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/hooks/useSearch.js"
click node_frontend_api "https://github.com/dsnme013/cannda-health/blob/main/frontend/src/lib/api.js"
click node_backend_server "https://github.com/dsnme013/cannda-health/blob/main/backend/server.js"
click node_backend_routes "https://github.com/dsnme013/cannda-health/blob/main/backend/routes/index.js"
click node_backend_search "https://github.com/dsnme013/cannda-health/blob/main/backend/routes/search.js"
click node_backend_clinics "https://github.com/dsnme013/cannda-health/blob/main/backend/routes/clinics.js"
click node_backend_locations "https://github.com/dsnme013/cannda-health/blob/main/backend/routes/locations.js"
click node_backend_appointments "https://github.com/dsnme013/cannda-health/blob/main/backend/routes/appointments.js"
click node_backend_sync "https://github.com/dsnme013/cannda-health/blob/main/backend/routes/sync.js"
click node_backend_search_engine "https://github.com/dsnme013/cannda-health/blob/main/backend/services/search-engine.js"
click node_backend_location_service "https://github.com/dsnme013/cannda-health/blob/main/backend/services/location-service.js"
click node_backend_geocoding "https://github.com/dsnme013/cannda-health/blob/main/backend/services/geocoding-service.js"
click node_backend_appointments_service "https://github.com/dsnme013/cannda-health/blob/main/backend/services/appointment-service.js"
click node_backend_data_sync "https://github.com/dsnme013/cannda-health/blob/main/backend/services/data-sync.js"
click node_backend_alberta_api "https://github.com/dsnme013/cannda-health/blob/main/backend/services/alberta-api.js"
click node_backend_middleware "https://github.com/dsnme013/cannda-health/blob/main/backend/middleware/cache.js"
click node_backend_config "https://github.com/dsnme013/cannda-health/blob/main/backend/config/database.js"
click node_database_schema "https://github.com/dsnme013/cannda-health/blob/main/database/init.sql"
click node_database_migrations "https://github.com/dsnme013/cannda-health/blob/main/database/migrations/001_create_tables.sql"
click node_database_migrate "https://github.com/dsnme013/cannda-health/blob/main/database/scripts/migrate.js"
click node_database_sync_script "https://github.com/dsnme013/cannda-health/blob/main/database/scripts/sync-alberta-data.js"
click node_redis "https://github.com/dsnme013/cannda-health/blob/main/backend/config/redis.js"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_frontend_home,node_frontend_search,node_frontend_clinic,node_frontend_booking,node_frontend_search_ui,node_frontend_map,node_frontend_clinic_card,node_frontend_booking_comp,node_frontend_hooks,node_frontend_api toneBlue
class node_backend_server,node_backend_routes,node_backend_search,node_backend_clinics,node_backend_locations,node_backend_appointments,node_backend_sync,node_backend_search_engine,node_backend_location_service,node_backend_geocoding,node_backend_appointments_service,node_backend_data_sync,node_backend_alberta_api,node_backend_middleware,node_backend_config toneAmber
class node_database_schema,node_database_migrations,node_database_migrate,node_database_sync_script toneMint
class node_redis,node_external_client toneRose
```

## Components

### Frontend

Next.js client app

- [Home](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/page.js): Next.js page · Homepage and search entry · `frontend/src/app/page.js`
- [Search](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/search/page.js): Next.js page · Search results view · `frontend/src/app/search/page.js`
- [Clinic](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/clinic/[id]/page.js): Next.js page · Clinic detail view · `frontend/src/app/clinic/[id]/page.js`
- [Booking](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/app/appointment/page.js): Next.js page · Appointment booking view · `frontend/src/app/appointment/page.js`
- [Search UI](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/SearchInterface.jsx): React components · Search and filter interface · `frontend/src/components/SearchInterface.jsx`
- [Map](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/Map.jsx): React component · Location and marker display · `frontend/src/components/Map.jsx`
- [Clinic Card](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/ClinicCard.jsx): React component · Provider summary card · `frontend/src/components/ClinicCard.jsx`
- [Booking Form](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/components/AppointmentBooking.jsx): React component · Appointment booking UI · `frontend/src/components/AppointmentBooking.jsx`
- [Hooks](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/hooks/useSearch.js): React hooks · Debounce, geolocation, and search state · `frontend/src/hooks/useSearch.js`
- [API Client](https://github.com/dsnme013/cannda-health/blob/main/frontend/src/lib/api.js): HTTP client · Frontend calls to backend API · `frontend/src/lib/api.js`

### Backend API

Fastify/Node application server

- [Server](https://github.com/dsnme013/cannda-health/blob/main/backend/server.js): Fastify entrypoint · Backend API bootstrap · `backend/server.js`
- [Routes](https://github.com/dsnme013/cannda-health/blob/main/backend/routes/index.js): Route wiring · Central route registration · `backend/routes/index.js`
- [Search API](https://github.com/dsnme013/cannda-health/blob/main/backend/routes/search.js): Route module · Search and discovery endpoints · `backend/routes/search.js`
- [Clinics API](https://github.com/dsnme013/cannda-health/blob/main/backend/routes/clinics.js): Route module · Clinic detail endpoints · `backend/routes/clinics.js`
- [Locations API](https://github.com/dsnme013/cannda-health/blob/main/backend/routes/locations.js): Route module · Geocoding and location endpoints · `backend/routes/locations.js`
- [Appointments API](https://github.com/dsnme013/cannda-health/blob/main/backend/routes/appointments.js): Route module · Availability and booking endpoints · `backend/routes/appointments.js`
- [Sync API](https://github.com/dsnme013/cannda-health/blob/main/backend/routes/sync.js): Route module · Data refresh and import endpoints · `backend/routes/sync.js`
- [Search Engine](https://github.com/dsnme013/cannda-health/blob/main/backend/services/search-engine.js): Service · Text and spatial provider lookup · `backend/services/search-engine.js`
- [Location Service](https://github.com/dsnme013/cannda-health/blob/main/backend/services/location-service.js): Service · Coordinate lookup and radius queries · `backend/services/location-service.js`
- [Geocoding](https://github.com/dsnme013/cannda-health/blob/main/backend/services/geocoding-service.js): Service · Address-to-coordinate resolution · `backend/services/geocoding-service.js`
- [Booking Service](https://github.com/dsnme013/cannda-health/blob/main/backend/services/appointment-service.js): Service · Appointment normalization and processing · `backend/services/appointment-service.js`
- [Data Sync](https://github.com/dsnme013/cannda-health/blob/main/backend/services/data-sync.js): Service · Import pipeline for external provider data · `backend/services/data-sync.js`
- [Alberta API](https://github.com/dsnme013/cannda-health/blob/main/backend/services/alberta-api.js): External integration · External healthcare data source adapter · `backend/services/alberta-api.js`
- [Middleware](https://github.com/dsnme013/cannda-health/blob/main/backend/middleware/cache.js): Cross-cutting · Cache, rate limit, and validation · `backend/middleware/cache.js`
- [Config](https://github.com/dsnme013/cannda-health/blob/main/backend/config/database.js): Runtime config · Database, Redis, and constants · `backend/config/database.js`

### Database

PostgreSQL/PostGIS schema and sync

- [Schema](https://github.com/dsnme013/cannda-health/blob/main/database/init.sql): SQL schema · Tables and indexes · `database/init.sql`
- [Migrations](https://github.com/dsnme013/cannda-health/blob/main/database/migrations/001_create_tables.sql): SQL migrations · Versioned schema changes and seeds · `database/migrations/001_create_tables.sql`
- [Migrate Tool](https://github.com/dsnme013/cannda-health/blob/main/database/scripts/migrate.js): Script · Schema migration runner · `database/scripts/migrate.js`
- [Sync Script](https://github.com/dsnme013/cannda-health/blob/main/database/scripts/sync-alberta-data.js): Script · External Alberta data import runner · `database/scripts/sync-alberta-data.js`

### Ops

Container and deployment support

- [Redis](https://github.com/dsnme013/cannda-health/blob/main/backend/config/redis.js): Cache store · Caching and rate limiting backend · `backend/config/redis.js`
- **Client Apps**: Browser/client · Users interacting with the frontend

## Connections

- Client Apps → Home: uses · Users start at the homepage or search entry
- Home → Search UI: renders · Homepage composes the main search interface
- Search → Search UI: renders · Search page uses the search interface
- Search → Map: renders · Search results show map and nearby providers
- Search → Clinic Card: lists · Search results are summarized as clinic cards
- Clinic → Clinic Card: renders · Clinic page reuses provider presentation
- Booking → Booking Form: renders · Booking page centers on appointment form
- Search UI → Hooks: uses · Search UI relies on state and geolocation hooks
- Map → API Client: fetches · Map loads providers and locations through the API client
- Search UI → API Client: calls · Search submissions are sent to the backend
- Clinic Card → API Client: calls · Clinic detail data comes from API requests
- Booking Form → API Client: calls · Booking actions are sent to the backend
- API Client → Server: HTTP · Frontend talks to the backend API over HTTP
- Server → Routes: registers · Server bootstraps the route tree
- Routes → Search API: includes · Search endpoints are mounted
- Routes → Clinics API: includes · Clinic endpoints are mounted
- Routes → Locations API: includes · Location and geocoding endpoints are mounted
- Routes → Appointments API: includes · Appointment endpoints are mounted
- Routes → Sync API: includes · Sync endpoints are mounted
- Search API → Search Engine: uses · Search route delegates provider lookup
- Search API → Location Service: uses · Search route uses location-aware filtering
- Locations API → Geocoding: uses · Location route resolves user-entered places
- Appointments API → Booking Service: uses · Booking route delegates appointment logic
- Sync API → Data Sync: uses · Sync route triggers import pipeline
- Data Sync → Alberta API: fetches · External provider data is pulled from Alberta source
- Search Engine → Schema: queries · Search uses PostgreSQL/PostGIS data
- Location Service → Schema: queries · Location lookups use the datastore
- Booking Service → Schema: updates · Bookings update persistent appointment state
- Geocoding → Schema: reads · Geocoding and provider lookup share stored location data
- Search Engine → Redis: caches · Search results can be cached
- Middleware → Redis: uses · Cache and rate-limit controls rely on Redis
- Server → Middleware: applies · Middleware wraps incoming requests
- Migrations → Schema: builds · Migrations create and evolve the schema
- Migrate Tool → Migrations: runs · Migration runner applies SQL files
- Sync Script → Data Sync: invokes · Script reuses sync pipeline logic
- Sync Script → Schema: loads · Imported data is persisted to the database
- Config → Schema: configures · Database connection settings support schema access
- Config → Redis: configures · Redis connection settings support cache access
