# Pediatric AI Scribe - Architecture Overview

## System Overview

The Pediatric AI Scribe is a self-hosted, Dockerized clinical documentation assistant built on the following stack:

- **Runtime:** Node.js 20 (Alpine) with Express
- **Database:** PostgreSQL 16 with the pgvector extension for embedding-based similarity search
- **Containerization:** Docker Compose with two services (app + database)
- **Frontend:** Vanilla JavaScript single-page application (no framework)

The application provides AI-powered transcription, note generation, and learning tools for pediatric clinicians. It runs entirely behind a reverse proxy and is designed for single-institution or personal deployment.

---

## File Structure

```
/
├── server.js                        # Application entry point
├── package.json
├── Dockerfile
├── docker-compose.yml
├── sw.js                            # Service worker (copied into public/)
│
├── src/
│   ├── routes/                      # 27 route files (Express routers)
│   │   ├── encounters.js
│   │   ├── auth.js
│   │   ├── admin.js
│   │   ├── learning.js
│   │   ├── ...                      # (27 total)
│   │
│   ├── utils/
│   │   ├── ai.js                    # LLM client abstraction (OpenAI-compatible)
│   │   ├── models.js                # Model registry and selection
│   │   ├── prompts.js               # System/user prompt templates
│   │   ├── config.js                # App settings helpers (DB-backed)
│   │   ├── logger.js                # Winston logger setup
│   │   ├── embeddings.js            # pgvector embedding generation
│   │   ├── transcribeAWS.js         # AWS Transcribe integration
│   │   ├── transcribeGoogle.js      # Google Cloud Speech-to-Text
│   │   ├── transcribeLocal.js       # Local Whisper WASM transcription
│   │   └── ttsGoogle.js             # Google Cloud Text-to-Speech
│   │
│   ├── middleware/
│   │   ├── auth.js                  # JWT + session authentication
│   │   └── logging.js               # Request/response logging middleware
│   │
│   └── db/
│       └── database.js              # PostgreSQL connection pool + query helpers
│
├── public/                          # Static frontend assets
│   ├── index.html                   # SPA shell
│   ├── app.js                       # Tab/navigation manager
│   ├── components/                  # HTML partials loaded via fetch
│   ├── js/                          # 20+ JS modules
│   └── css/                         # Stylesheets
│
└── scripts/                         # Utility and migration scripts
```

---

## Request Flow

Every incoming HTTP request passes through the following middleware chain in order:

```
Client Request
  |
  v
Helmet (CSP headers, security hardening)
  |
  v
CORS (origin validation)
  |
  v
Cookie Parser (signed cookies for sessions)
  |
  v
Rate Limiting (per-IP and per-route limits)
  |
  v
Static File Serving (public/ directory)
  |
  v
Route Matching (src/routes/*.js)
  |
  v
Auth Middleware (JWT verification, role checks)
  |
  v
Route Handler (business logic, DB queries, AI calls)
  |
  v
JSON Response
```

Static assets are served before route matching, so unauthenticated users can load the SPA shell and login page. All API routes under `/api/` require authentication unless explicitly excluded (e.g., `/api/auth/login`, `/api/auth/register`).

---

## Frontend Architecture

The frontend is a vanilla JavaScript SPA with no build step and no framework.

### Loading

`index.html` serves as the application shell. It contains a `<div class="app-body">` placeholder and loads 20+ JS modules via `<script defer>` tags. On startup, `app.js` initializes the tab system and fetches HTML partials from `components/` into the `.app-body` container.

### Module Communication

Because there is no framework or module bundler, frontend modules communicate through two mechanisms:

1. **Window globals** -- Shared state and utility functions are attached to `window` (e.g., `window.currentUser`, `window.apiCall`).
2. **CustomEvents** -- Modules dispatch and listen for `CustomEvent` instances on `document` to coordinate loosely-coupled updates (e.g., when an encounter is saved, other tabs refresh their data).

### Tab Navigation

Tabs are managed by `app.js`. Clicking a tab fetches the corresponding HTML partial from `components/`, injects it into `.app-body`, and invokes the module's initialization function. Only one tab is active at a time; previous tab content is replaced.

---

## Docker Configuration

### Application Container

- **Base image:** `node:20-alpine`
- **System dependencies:** `ffmpeg` (audio processing for transcription)
- **Bundled models:** Self-hosted Whisper WASM models for browser-side and server-side local transcription
- **Internal port:** 3000

### Database Container

- **Image:** `pgvector/pgvector:pg16`
- **Extension:** pgvector is loaded automatically for vector similarity search on learning content embeddings

### Port Mapping

The application binds to the loopback interface only:

```
127.0.0.1:3552 -> container:3000
```

This means the app is not directly accessible from the network. A reverse proxy (e.g., Nginx, Caddy) should terminate TLS and forward traffic to `127.0.0.1:3552`.

### Volumes

| Volume | Purpose |
|---|---|
| `pgdata` | PostgreSQL data directory (persistent) |
| `scribe-logs` | Application file logs written by Winston |

---

## Service Worker

The file `sw.js` is registered by the frontend and implements a two-strategy caching model:

### Static Assets (Cache-First)

Requests for CSS, JS, images, fonts, and HTML partials are served from the cache first. If the cache misses, the network is used and the response is cached for future requests. This enables fast repeat loads and basic offline shell rendering.

### API Requests (Network-First)

Requests to `/api/` endpoints always attempt the network first. If the network fails (e.g., offline or timeout), the service worker falls back to a cached response if one exists. This ensures users always see the freshest data when connected.

### Precaching

On installation, the service worker precaches the application shell: `index.html`, `app.js`, core CSS, and critical component partials. This set of assets is enough to render the login screen and basic UI skeleton without any network requests.
