# QuezCorp Medical — Initial architecture and ERD

## Tenancy

```mermaid
flowchart LR
 P[Public patient browser] --> C[Central clinic directory / business registry]
 P --> R[Server-side clinic resolver]
 A[Clinic staff] --> R
 R --> T1[(Clinic A MySQL)]
 R --> T2[(Clinic B MySQL)]
 SA[Super Admin] --> C
 X[Counts-only daily job] --> T1
 X --> T2
 X --> C
```

The super-admin web app does not have a path to patient appointments. A separate operational job, running with restricted credentials, computes counts. In production, further separate job and web processes and grant credentials by least privilege.

## Central data model

```text
clinics(id UUID PK, slug UNIQUE, name, district, address, phone, description,
        status, plan, subscription_expires_at,
        db_host, db_port, db_name, db_username, db_password ENCRYPTED)
platform_admins(id PK, email UNIQUE, password HASHED)
aggregated_usage(clinic_id FK, period_date PK composite, booking_count, doctor_count)
platform_audit_logs(id PK, actor_type, actor_id, event, clinic_id, created_at)
```

## Per-clinic data model

```text
clinic_users(id PK, email UNIQUE, password HASHED, role, active)
doctors(id PK, name, specialization, qualifications, active)
doctor_schedules(id PK, doctor_id FK, weekday, starts_at, ends_at, slot_minutes, capacity)
appointment_slots(id PK, doctor_id FK, starts_at_utc, capacity, booked_count,
                  UNIQUE(doctor_id, starts_at_utc))
daily_queues(doctor_id FK + queue_date PRIMARY KEY, last_number)
patient_contacts(id PK, name_encrypted, phone_encrypted)
appointments(id PK, slot_id FK, doctor_id FK, patient_contact_id FK,
             reference UNIQUE, access_token_hash UNIQUE, status, queue_number)
appointment_audit_logs(id PK, appointment_id FK, actor_user_id FK, event)
```

## Security assumptions and risks

- `APP_KEY` is critical for decrypting patient contacts and tenant credentials. Keep it in a managed secret store and have a tested rotation strategy.
- The platform still holds encrypted per-clinic DB credentials, so an infrastructure or application compromise could affect more than one clinic. Tenant-user least-privilege grants and strong credential separation are essential.
- `DB::transaction()` and `SELECT ... FOR UPDATE` protect slot capacity within one tenant. Multi-database central usage totals are eventually consistent and not part of the booking transaction.
- All private booking links are bearer tokens: confirmation page only exposes booking metadata; production should implement token expiry and verified cancellation.
- Password rate limiting is per-route and IP by default; deploy at reverse proxy with trusted proxy settings and review user + IP limits.
- Clinic staff session keys are based on clinic UUID and are checked against **that clinic's DB** on every request.
- Displayed dates are Asia/Colombo; stored `starts_at_utc` is UTC.
- Route slug selects a tenant but never confers a user session in that tenant.

## Phase roadmap

1. **Included:** Foundation, central registry / per-tenant migrations, scoped login, patient booking vertical slice, clinic operations view, aggregate-only platform view, responsive design.
2. **Next:** Complete clinic onboarding, password reset, doctor verification, schedules/holidays, notification abstraction, complete roles, staff management, extended admin.
3. **Security before any pilot:** isolation tests, IDOR/CSRF tests, concurrency/load tests, data flows and DPIA determination, incident response, DPA/DPA-style contracts, backups, retention, hosting transfer review.
4. **Pilot:** sign off clinic workflow and UI, test Sinhala/Tamil, SMS provider, monitoring and deployment automation.
