inou/CLAUDE.md

8.0 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/UPDATE
  • Load(table, id, struct) — SELECT by primary key
  • Query(sql, args, &slice) — SELECT with custom queries
  • Delete(table, pkCol, id) — DELETE by primary key
  • Count(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:

  1. ASK Johan for permission
  2. Explain what you need and why
  3. 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 whom
  • audit — activity log

Querying Encrypted Data

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.md for new design.

Current endpoints:

  • GET /api/dossiers — list accessible dossiers
  • GET /api/studies?dossier=X — list imaging studies
  • GET /api/series?dossier=X&study=Y — list series
  • GET /api/slices?dossier=X&series=Y — list slices
  • GET /image/{id}?token=X — fetch image
  • GET /api/genome?dossier=X — query variants
  • GET /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:

  1. Run check-db (blocks if violations found)
  2. Build all binaries (FIPS 140-3 compliant)
  3. Stop services on target
  4. Copy binaries, templates, static, lang files
  5. Start services
  6. 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() usage
  • db.Exec/Query/QueryRow outside 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:

Staging:

Key Design Decisions

  1. No accounts table — everyone is a dossier (for virality)
  2. Encrypted fields — all PII encrypted at rest via lib.CryptoEncrypt
  3. Categories as integers — scalable, translated at API boundary
  4. Type field — differentiates within category (slice/series/study all CategoryImaging)
  5. parent_id — hierarchy navigation, not category
  6. 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.md for roadmap