8.3 KiB
inou
Medical imaging platform with AI-powered health data exploration via MCP integration.
Design Documentation
- API Design (Jan 2026):
docs/api-design-2026-01.md— token auth, REST endpoints, progressive disclosure, thumbnails, anatomy analysis
Architecture
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Portal │ │ API │ │ MCP Bridge │
│ (Go/HTML) │ │ (Go) │ │ (Go) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────┬───────┴───────────────────┘
│
┌──────┴──────┐
│ lib │
│ (shared Go) │
└──────┬──────┘
│
┌──────┴──────┐
│ SQLite │
│ (encrypted)│
└─────────────┘
Code Locations
| Component | Path | Purpose |
|---|---|---|
| lib | ~/dev/inou/lib/ |
Shared: crypto, db, types, translations |
| Portal | ~/dev/inou/portal/ |
Web UI, DICOM import, genome processing |
| API | ~/dev/inou/api/ |
REST API for LLM access |
| Viewer | ~/dev/inou/viewer/ |
DICOM viewer (Electron) |
| MCP Client | ~/dev/inou/mcp-client/ |
Claude Desktop bridge |
| Doc Processor | ~/dev/inou/doc-processor/ |
PDF extraction tool |
| Docs | ~/dev/inou/docs/ |
Design documentation |
| Deployed | /tank/inou/ |
Runtime on both staging & prod |
Environments
| Environment | Server | URL | Purpose |
|---|---|---|---|
| Production | 192.168.100.2 | https://inou.com | Live users |
| Staging | 192.168.1.253 | https://dev.inou.com | Development/testing |
Production is on an isolated VLAN (192.168.100.0/24, VLAN 10) with firewall rules restricting access.
Server Access
ssh johan@192.168.1.253 # Staging
ssh johan@192.168.100.2 # Production
Database
SQLite with encrypted fields. Single file at /tank/inou/data/inou.db.
⛔ CRITICAL: Database Access Rules
ALL database operations MUST go through lib/db_queries.go functions. NO EXCEPTIONS.
Allowed functions (defined in db_queries.go):
Save(table, struct)— INSERT/UPDATELoad(table, id, struct)— SELECT by primary keyQuery(sql, args, &slice)— SELECT with custom queriesDelete(table, pkCol, id)— DELETE by primary keyCount(sql, args...)— SELECT COUNT(*)
FORBIDDEN (requires Johan's express consent):
- Any use of
db.Exec(),db.Query(),db.QueryRow()outside db_queries.go - Any use of
lib.DB()anywhere - Any modifications to
lib/db_queries.go - Any new database wrapper functions
- Any direct SQL execution
Before making ANY database-related changes:
- ASK Johan for permission
- Explain what you need and why
- Wait for explicit approval
Verification: Run make check-db to verify no direct DB access exists.
This check runs automatically on deploy.
Key tables:
dossiers— user profiles (everyone is a dossier)entries— all health data (imaging, labs, genome, documents, etc.)dossier_access— who can access whomaudit— activity log
Querying Encrypted Data
Encryption is DETERMINISTIC. You CAN use encrypted columns in WHERE clauses by encrypting the search value: WHERE col = lib.CryptoEncrypt("value"). Do NOT pull large datasets and filter client-side when a precise query is possible.
Columns ending in _id are NOT encrypted (plain text, always filterable).
IMPORTANT: Do NOT write Python/Go scripts to decrypt database fields. Use the decrypt tool:
# Raw mode - decrypts inline
sqlite3 /tank/inou/data/inou.db "SELECT * FROM entries LIMIT 5" | /tank/inou/bin/decrypt
# JSON mode - pretty output
sqlite3 -json /tank/inou/data/inou.db "SELECT * FROM entries LIMIT 5" | /tank/inou/bin/decrypt -json
# Combine with grep
sqlite3 /tank/inou/data/inou.db "SELECT * FROM dossiers" | /tank/inou/bin/decrypt | grep -i sophia
The tool automatically detects and decrypts base64-encoded encrypted fields while leaving IDs and other plain fields unchanged. Rebuild with make decrypt if needed.
Categories (lib/types.go)
Integer enums (iota), 27 total. Key ones:
| Int | Name | Notes |
|---|---|---|
| 1 | imaging | slice, series, study (Type differentiates) |
| 2 | document | PDFs, reports |
| 3 | lab | lab results |
| 4 | genome | variants, tiers (Type differentiates) |
| 5 | upload | pending processing |
Translations in portal/lang/*.yaml (15 languages).
API Endpoints (Current)
Note: Being redesigned. See
docs/api-design-2026-01.mdfor new design.
Current endpoints:
GET /api/dossiers— list accessible dossiersGET /api/studies?dossier=X— list imaging studiesGET /api/series?dossier=X&study=Y— list seriesGET /api/slices?dossier=X&series=Y— list slicesGET /image/{id}?token=X— fetch imageGET /api/genome?dossier=X— query variantsGET /api/entries— generic entry CRUD
Deploy
Staging (default)
make deploy
Deploys to staging (192.168.1.253 / dev.inou.com). Use for development and testing.
Release to Production
make deploy-prod
Deploys to production (192.168.100.2 / inou.com). Use when ready to release.
"Release to prod" = make deploy-prod
What Deploy Does
Both commands:
- Run
check-db(blocks if violations found) - Build all binaries (FIPS 140-3 compliant)
- Stop services on target
- Copy binaries, templates, static, lang files
- Start services
- Show status
Typical Workflow
# 1. Develop and test
make deploy # Deploy to staging
# Test at https://dev.inou.com
# 2. When ready for production
make deploy-prod # Release to prod
# Live at https://inou.com
Testing
make test # Run integration tests (services must be running)
make check-db # Verify no direct DB access (runs automatically on deploy)
Integration Tests (make test)
Runs 18 tests covering the full stack:
| Category | Tests |
|---|---|
| Service Health | Portal HTTPS, API HTTPS, internal ports |
| Login Flow | Login page, send verification code |
| Authenticated Routes | Dashboard, add/view/edit dossier |
| Dossier CRUD | Create dossier, verify via API, cleanup |
| API Data Access | List dossiers/studies/series/slices |
| Image Fetch | Fetch DICOM slice |
DB Access Check (make check-db)
Scans core codebase for forbidden direct database access:
lib.DB()usagedb.Exec/Query/QueryRowoutside db_queries.go/db_schema.go- Deprecated wrappers (DBExec, DBInsert, etc.)
Runs automatically before every deploy. Blocks deployment if violations found.
MCP Bridge (Mac)
~/dev/inou/build-mac.sh
Version in build-mac.sh and viewer/main.go. Current: 1.2.0
Test Dossiers
- Sophia — brain MRI, spine MRI, CT, X-rays (May 2022)
- Johan — genome data, labs
- Alena — genome data, labs
URLs
Production:
- Portal: https://inou.com
- API: https://inou.com/api/*
- API Docs: https://inou.com/api/docs
Staging:
- Portal: https://dev.inou.com
- API: https://dev.inou.com/api/*
Key Design Decisions
- No accounts table — everyone is a dossier (for virality)
- Encrypted fields — all PII encrypted at rest via
lib.CryptoEncrypt - Categories as integers — scalable, translated at API boundary
- Type field — differentiates within category (slice/series/study all CategoryImaging)
- parent_id — hierarchy navigation, not category
- SQLite — simple, single file, handles the scale
File Editing
Native (on Linux server): Use standard tools — sed, Edit tool, etc. all work fine.
Remote (from Mac via SSH): Use claude-edit to avoid quote escaping issues:
cat /tmp/edit.json | ssh johan@192.168.1.253 "~/bin/claude-edit"
Known Limitations
- Large X-rays (2836x2336+) fail via MCP fetch
- See
~/dev/inou/TODO.mdfor roadmap