Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# TransTrack Environment Configuration
# Copy this file to .env and adjust values as needed.

# ─── Application Mode ───────────────────────────────────────────
# Set to 'development' for dev features; 'production' for release builds.
NODE_ENV=development

# Set to '1' to enable Electron dev mode (opens DevTools, loads from localhost)
ELECTRON_DEV=1

# ─── Build Configuration ────────────────────────────────────────
# Build version: 'evaluation' or 'enterprise'
# Normally set by the build scripts (npm run build:eval:* / build:enterprise:*)
# TRANSTRACK_BUILD_VERSION=evaluation

# ─── License (Development Only) ─────────────────────────────────
# WARNING: Setting this to 'true' bypasses license checks in development.
# This flag is IGNORED when NODE_ENV=production or when the app is packaged.
# NEVER ship a build with this enabled.
# LICENSE_FAIL_OPEN=false

# ─── EHR Integration (Future / Cloud Mode) ──────────────────────
# These are only used if cloud-based EHR sync is enabled (not in offline mode).
# EHR_WEBHOOK_SECRET=
# EHR_API_KEY_EPIC=
# EHR_API_KEY_CERNER=
22 changes: 16 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,25 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'

- run: npm install --ignore-scripts


- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y python3 make g++

- name: Install npm dependencies
run: npm install

- name: Rebuild native modules for CI Node version
run: npm rebuild better-sqlite3-multiple-ciphers

- run: npm audit || true

- run: npm run lint || true


- name: Run tests
run: npm test

- run: npm run build
124 changes: 124 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# TransTrack Architecture

## System Overview

TransTrack is an **offline-first, HIPAA-compliant Electron desktop application** for transplant waitlist and operations management. All data is stored locally in an AES-256 encrypted SQLite database. No cloud services are required.

## High-Level Architecture

```
┌───────────────────────────────────────────────────────────────────────┐
│ Renderer Process (React SPA) │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────────────────┐ │
│ │ Pages │ │ Components │ │ api/localClient.js │ │
│ │ Dashboard │ │ PatientCard │ │ → window.electronAPI │ │
│ │ Patients │ │ DonorForm │ │ → IPC invoke │ │
│ │ Matching │ │ Navbar │ │ │ │
│ │ Reports │ │ ErrorBound. │ │ TanStack Query caching │ │
│ │ Settings │ │ 40+ UI │ │ │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬──────────────────┘ │
│ │ │ │ │
│ └─────────────────┴──────────────────────┘ │
│ │ │
│ contextBridge (preload.cjs) │
└──────────────────────────────┼────────────────────────────────────────┘
│ IPC (80+ channels)
┌──────────────────────────────┼────────────────────────────────────────┐
│ Main Process (Electron) │ │
│ │ │
│ ┌───────────────────────────┴──────────────────────────────────────┐ │
│ │ IPC Handler Coordinator (handlers.cjs) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ auth │ │ entities │ │ admin │ │ license │ │ │
│ │ ├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤ │ │
│ │ │ barriers │ │ ahhq │ │ labs │ │ clinical │ │ │
│ │ ├──────────┤ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ │operations│ │ │
│ │ └──────────┘ ← All share session state via shared.cjs │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┴──────────────────────────────────────┐ │
│ │ Services Layer │ │
│ │ riskEngine · readinessBarriers · ahhqService · labsService │ │
│ │ transplantClock · accessControl · disasterRecovery │ │
│ │ complianceView · offlineReconciliation │ │
│ └───────────────────────────┬──────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┴──────────────────────────────────────┐ │
│ │ Database Layer │ │
│ │ init.cjs (key management, encryption, migration) │ │
│ │ schema.cjs (20+ tables, indexes, foreign keys) │ │
│ │ SQLCipher (AES-256-CBC, PBKDF2-HMAC-SHA512, 256k iterations) │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
```

## Data Flow

### Authentication
1. `AuthContext` → `api.auth.login(credentials)`
2. → IPC `auth:login` → bcrypt verify → session created (8-hour expiry)
3. Session stores `org_id` for downstream org isolation

### Entity CRUD
1. `api.entities.Patient.list()` → IPC `entity:list`
2. → `getSessionOrgId()` → org-scoped parameterized SQL
3. → Response → TanStack Query cache

### Business Functions
1. `api.functions.invoke('calculatePriorityAdvanced', { patient_id })`
2. → IPC `function:invoke` → function registry dispatch
3. → Priority scoring algorithm → DB update → audit log

## Security Architecture

| Layer | Mechanism |
|-------|-----------|
| **Data at rest** | AES-256-CBC via SQLCipher |
| **Key management** | 256-bit random key, file permissions `0o600` |
| **Org isolation** | `getSessionOrgId()` enforced on all queries; org_id never from client |
| **SQL injection** | Parameterized queries; `ALLOWED_ORDER_COLUMNS` whitelist |
| **Authentication** | bcrypt (cost 12), 8-hour sessions, 5-attempt lockout |
| **Audit trail** | Immutable `audit_logs` table, cannot be modified via API |
| **Access control** | Role-based with break-the-glass justification logging |

## Module Map

### Frontend (`src/`)
| Module | Files | Purpose |
|--------|-------|---------|
| Pages | 13 | Dashboard, Patients, DonorMatching, Reports, Settings, etc. |
| Components | 50+ | Domain components + Radix/shadcn UI primitives |
| API | 2 | `localClient.js` (Electron IPC) with dev mock fallback |
| Hooks | 2 | `useIsMobile`, `useJustifiedAccess` |
| Lib | 5 | Auth context, query client, navigation, utils |

### Electron Main (`electron/`)
| Module | Files | Purpose |
|--------|-------|---------|
| IPC Handlers | 9 modules | Auth, entities, admin, license, barriers, aHHQ, labs, clinical, operations |
| Services | 9 | Risk engine, barriers, aHHQ, labs, clock, access, recovery, compliance, reconciliation |
| Database | 2 | Schema definitions, encryption, migrations |
| License | 3 | Manager, feature gate, tier definitions |
| Functions | 1 | Priority scoring, donor matching, FHIR import |

## Build Variants

| Variant | App ID | Restrictions |
|---------|--------|-------------|
| **Evaluation** | `com.transtrack.evaluation` | 14-day trial, 50 patients, 1 user, watermark |
| **Enterprise** | `com.transtrack.enterprise` | Full features, requires license activation |

## Technology Stack

| Layer | Technology |
|-------|------------|
| Desktop | Electron 35 |
| Frontend | React 18, Vite 6 |
| Styling | Tailwind CSS, Radix UI (shadcn) |
| State | TanStack React Query v5 |
| Forms | React Hook Form + Zod |
| Database | SQLite via better-sqlite3-multiple-ciphers |
| Charts | Recharts |
| Routing | React Router v6 (HashRouter) |
24 changes: 10 additions & 14 deletions electron/database/init.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -552,17 +552,17 @@ async function seedDefaultData(defaultOrgId) {
if (!adminExists || adminExists.count === 0) {
const bcrypt = require('bcryptjs');

// Default admin password - CHANGE THIS AFTER FIRST LOGIN!
const defaultPassword = 'Admin123!';
const mustChangePassword = true;

// Create default admin user
const adminId = uuidv4();
const hashedPassword = await bcrypt.hash(defaultPassword, 12);
const now = new Date().toISOString();

db.prepare(`
INSERT INTO users (id, org_id, email, password_hash, full_name, role, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
INSERT INTO users (id, org_id, email, password_hash, full_name, role, is_active, must_change_password, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
adminId,
defaultOrgId,
Expand All @@ -571,21 +571,17 @@ async function seedDefaultData(defaultOrgId) {
'System Administrator',
'admin',
1,
mustChangePassword ? 1 : 0,
now,
now
);

// Log credentials to console for first-time setup
console.log('');
console.log('╔══════════════════════════════════════════════════════════════╗');
console.log('║ INITIAL ADMIN CREDENTIALS CREATED ║');
console.log('╠══════════════════════════════════════════════════════════════╣');
console.log('║ Email: admin@transtrack.local ║');
console.log('║ Password: Admin123! ║');
console.log('╠══════════════════════════════════════════════════════════════╣');
console.log('║ ⚠️ CHANGE YOUR PASSWORD AFTER FIRST LOGIN! ║');
console.log('╚══════════════════════════════════════════════════════════════╝');
console.log('');
if (process.env.NODE_ENV === 'development') {
console.log('');
console.log('Initial admin credentials: admin@transtrack.local / Admin123!');
console.log('CHANGE YOUR PASSWORD AFTER FIRST LOGIN');
console.log('');
}

// Create default priority weights for this organization
const weightsId = uuidv4();
Expand Down
Loading
Loading