docs: rewrite README — skinny packages, supply chain, cloud providers, accurate counts
All checks were successful
CI / skinny-install (aco) (push) Successful in 49s
CI / skinny-install (api) (push) Successful in 29s
CI / skinny-install (bcda) (push) Successful in 23s
CI / skinny-install (bib) (push) Successful in 35s
CI / skinny-install (bls) (push) Successful in 20s
CI / skinny-install (ccw) (push) Successful in 24s
CI / skinny-install (cli) (push) Successful in 27s
CI / skinny-install (cms) (push) Successful in 24s
CI / skinny-install (conf) (push) Successful in 26s
CI / skinny-install (pfs) (push) Successful in 26s
CI / skinny-install (rex) (push) Successful in 24s
CI / lint-test (push) Successful in 5m49s
Deploy / build-scan-report (push) Successful in 3m5s
All checks were successful
CI / skinny-install (aco) (push) Successful in 49s
CI / skinny-install (api) (push) Successful in 29s
CI / skinny-install (bcda) (push) Successful in 23s
CI / skinny-install (bib) (push) Successful in 35s
CI / skinny-install (bls) (push) Successful in 20s
CI / skinny-install (ccw) (push) Successful in 24s
CI / skinny-install (cli) (push) Successful in 27s
CI / skinny-install (cms) (push) Successful in 24s
CI / skinny-install (conf) (push) Successful in 26s
CI / skinny-install (pfs) (push) Successful in 26s
CI / skinny-install (rex) (push) Successful in 24s
CI / lint-test (push) Successful in 5m49s
Deploy / build-scan-report (push) Successful in 3m5s
This commit is contained in:
116
README.md
116
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||

|
||||
|
||||
Healthcare analytics platform on self-hosted infrastructure. Replaces dbt SQL models with narwhals DataFrame-agnostic expression functions, backed by DuckDB locally and Iceberg/Trino in the lakehouse. 22 services, 13 data pipelines, 11,931 tests at 99% coverage.
|
||||
Healthcare analytics platform on self-hosted infrastructure. Replaces dbt SQL models with narwhals DataFrame-agnostic expression functions, backed by DuckDB locally and Iceberg/Trino in the lakehouse. 22 services, 13 data pipelines, 11,955 tests at 99% coverage.
|
||||
|
||||
## Quick start
|
||||
|
||||
@@ -12,7 +12,6 @@ ROOT_KEY=$(openssl rand -hex 32)
|
||||
cat > .env <<EOF
|
||||
DOMAIN=homelab.fhirworx.io
|
||||
HOST_IP=192.168.1.192
|
||||
WOODPECKER_ADMIN=kert
|
||||
EOF
|
||||
|
||||
# 2. Start core services and bootstrap credentials
|
||||
@@ -26,6 +25,20 @@ docker compose up -d
|
||||
curl -s http://localhost:8000/health | python3 -m json.tool
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
The package supports skinny installs — install only the modules you need:
|
||||
|
||||
```bash
|
||||
pip install stack[aco] # ACO analytics only
|
||||
pip install stack[bib] # bibliography only
|
||||
pip install stack[cli] # CLI (pulls aco + api + bib)
|
||||
pip install stack[all] # everything
|
||||
pip install stack[aco,aws] # ACO analytics with AWS storage
|
||||
```
|
||||
|
||||
11 modules available as optional extras: `conf`, `aco`, `api`, `bcda`, `bib`, `bls`, `ccw`, `cli`, `cms`, `pfs`, `rex`. Cloud providers: `aws`, `gcp`, `azure`. Aggregates: `all`, `lake`.
|
||||
|
||||
## Services
|
||||
|
||||
All services route through Traefik at `*.homelab.fhirworx.io`.
|
||||
@@ -36,7 +49,6 @@ All services route through Traefik at `*.homelab.fhirworx.io`.
|
||||
| Notebooks | `notebooks.homelab.fhirworx.io` | Marimo notebooks (GPU-accelerated) |
|
||||
| Docs | `docs.homelab.fhirworx.io` | Docusaurus — API reference + CMS bibliography |
|
||||
| Gitea | `gitea.homelab.fhirworx.io` | Git server, container registry, LFS |
|
||||
| Woodpecker CI | `ci.homelab.fhirworx.io` | CI/CD pipelines |
|
||||
| Zotero | `zotero.homelab.fhirworx.io` | Reference manager (KasmVNC desktop) |
|
||||
| Dashboard | `homelab.fhirworx.io` | Service launcher |
|
||||
| RustFS | `s3.homelab.fhirworx.io` | S3-compatible object storage |
|
||||
@@ -54,20 +66,20 @@ All services route through Traefik at `*.homelab.fhirworx.io`.
|
||||
|
||||
```
|
||||
CCLF/BCDA/CMS data
|
||||
│
|
||||
▼
|
||||
|
|
||||
v
|
||||
src/aco/express/ narwhals expressions (DataFrame-agnostic)
|
||||
│
|
||||
▼
|
||||
|
|
||||
v
|
||||
src/aco/pipe/ pipeline runner with schema validation
|
||||
│
|
||||
▼
|
||||
DuckDB (local) ──or── Iceberg + Trino (lakehouse)
|
||||
│
|
||||
▼
|
||||
|
|
||||
v
|
||||
DuckDB (local) --or-- Iceberg + Trino (lakehouse) --or-- Databricks
|
||||
|
|
||||
v
|
||||
src/api/ FastAPI (health, runs, bib)
|
||||
│
|
||||
▼
|
||||
|
|
||||
v
|
||||
notebooks/ Marimo interactive analysis
|
||||
```
|
||||
|
||||
@@ -101,10 +113,11 @@ All services route through Traefik at `*.homelab.fhirworx.io`.
|
||||
|
||||
- `cfg` — attribute access (`cfg.db.aco`)
|
||||
- `path("db.aco")` — absolute path resolution relative to repo root
|
||||
- `context()` — environment switching (local/lake/databricks/trino)
|
||||
- `context()` — environment switching (local/lake/databricks/trino/aws/gcp/azure)
|
||||
- `secret("api.secret", "STACK_API_SECRET")` — env var with config fallback
|
||||
- `storage.get_filesystem()` — multi-cloud storage abstraction (S3/GCS/ABFS/local)
|
||||
|
||||
Override context at runtime: `STACK_CONTEXT=lake`.
|
||||
Override context at runtime: `STACK_CONTEXT=lake` (or `aws`, `gcp`, `azure`).
|
||||
|
||||
### Bibliography
|
||||
|
||||
@@ -137,19 +150,13 @@ uv run python dev/scripts/gen_config.py --check # verify (used in CI)
|
||||
uv run python dev/scripts/gen_config.py --backend github # one-off override
|
||||
```
|
||||
|
||||
The generator:
|
||||
1. Reads image definitions from `stack.toml [images]`
|
||||
2. Dispatches to the active backend emitter (`dev/scripts/backends/{backend}.py`)
|
||||
3. Writes workflow YAML files to the correct directory
|
||||
4. Auto-removes stale workflows from inactive backend directories
|
||||
The generator reads image definitions from `stack.toml [images]`, dispatches to the active backend emitter (`dev/scripts/backends/{backend}.py`), writes workflow YAML, and auto-removes stale workflows from inactive backend directories.
|
||||
|
||||
Each backend has its own `[ci.{backend}]` config section in `stack.toml` with runner labels, registry endpoints, and authentication settings.
|
||||
### Workflows
|
||||
|
||||
### Pipelines
|
||||
Seven workflows generated per backend:
|
||||
|
||||
Six workflows generated per backend:
|
||||
|
||||
| Pipeline | Trigger | What it does |
|
||||
| Workflow | Trigger | What it does |
|
||||
|----------|---------|--------------|
|
||||
| `ci.yml` | Push/PR | Ruff lint + format, pytest (99% coverage), gen_config --check, skinny-install matrix |
|
||||
| `deploy.yml` | Push to main | Build 5 images, Trivy scan, vuln reporting |
|
||||
@@ -157,6 +164,7 @@ Six workflows generated per backend:
|
||||
| `rebuild-all.yml` | Manual | Full rebuild + scan + deploy |
|
||||
| `infra-ci.yml` | Path-filtered push | Hadolint Dockerfiles, dry-run builds |
|
||||
| `release.yml` | Tag (`v*`) | `uv build` + release |
|
||||
| `pkg-supply-chain.yml` | Daily / push | Package inventory, mirror sync, drift detection, vuln scan |
|
||||
|
||||
### Secret mapping
|
||||
|
||||
@@ -168,26 +176,27 @@ Six workflows generated per backend:
|
||||
|
||||
### Image tagging
|
||||
|
||||
Images are tagged with the short commit SHA (8 chars):
|
||||
|
||||
```
|
||||
fhirworx/api:22ebc46e
|
||||
fhirworx/notebooks:a4a2dcb0
|
||||
fhirworx/docs:a4a2dcb0
|
||||
```
|
||||
|
||||
Compose resolves via `${COMMIT_SHA:-latest}` from `.env`. Custom images: `api`, `notebooks`, `zotero`, `docs`, `mc`.
|
||||
Images are tagged with the short commit SHA (8 chars). Compose resolves via `${COMMIT_SHA:-latest}` from `.env`. Custom images: `api`, `notebooks`, `zotero`, `docs`, `mc`.
|
||||
|
||||
### Vulnerability management
|
||||
|
||||
The `harden.yml` pipeline rebuilds all images with `--no-cache` to pick up OS patches, runs Trivy scans, and auto-files or auto-closes Gitea issues via `api.diag.vuln`.
|
||||
|
||||
### Package supply chain
|
||||
|
||||
Daily automated pipeline (`pkg-supply-chain.yml`) that:
|
||||
1. Scans Dockerfiles, pyproject.toml, and CI workflows for all package dependencies
|
||||
2. Syncs packages to the Gitea package registry (local mirror)
|
||||
3. Detects drift between manifest and mirror
|
||||
4. Runs Trivy vulnerability scans on dependencies
|
||||
5. Auto-creates Gitea issues for missing packages and CVEs
|
||||
|
||||
## Credential management
|
||||
|
||||
All 19 service credentials derive from a single 256-bit root key via HKDF-SHA256. No passwords stored in `.env` — they regenerate deterministically from root key + commit SHA on each deploy.
|
||||
|
||||
```
|
||||
ROOT_KEY + commit_sha → HKDF-SHA256 → all credentials → .env + backends
|
||||
ROOT_KEY + commit_sha -> HKDF-SHA256 -> all credentials -> .env + backends
|
||||
```
|
||||
|
||||
| Tier | Salt | Rotates |
|
||||
@@ -214,7 +223,7 @@ ROOT_KEY=$KEY uv run python -m api.auth derive $COMMIT_SHA --redact
|
||||
| `storage` | internal | PostgreSQL, RustFS |
|
||||
| `data` | internal | Nessie, Trino, Polaris |
|
||||
| `observability` | internal | Grafana, Prometheus, Jaeger, Loki |
|
||||
| `ci` | external | Woodpecker, Gitea, RustFS |
|
||||
| `ci` | external | Gitea, Act Runner, RustFS |
|
||||
|
||||
## Design system
|
||||
|
||||
@@ -231,6 +240,29 @@ Theme: **loch** (deep-navy). Traefik's `inject-loch` middleware rewrites HTML to
|
||||
|
||||
Query via Trino CLI, JDBC, Web UI, PyIceberg, or DuckDB+PyArrow.
|
||||
|
||||
### Cloud deployment
|
||||
|
||||
The platform runs on self-hosted Docker Compose by default. Cloud provider guides in `cloud/`:
|
||||
|
||||
| Provider | Storage | Catalog | Compute | Context |
|
||||
|----------|---------|---------|---------|---------|
|
||||
| Self-hosted | RustFS (S3) | Nessie / Polaris | Docker Compose | `local` / `lake` |
|
||||
| AWS | S3 | Glue | ECS / EKS | `aws` |
|
||||
| GCP | GCS | BigQuery | Cloud Run / GKE | `gcp` |
|
||||
| Azure | ABFS | Unity Catalog | Container Apps / AKS | `azure` |
|
||||
| Databricks | DBFS | Unity Catalog | Databricks Jobs | `databricks` |
|
||||
|
||||
Switch with `STACK_CONTEXT=aws` or edit `stack.toml [context] active`.
|
||||
|
||||
## Databricks
|
||||
|
||||
Databricks Asset Bundle (`databricks.yml`) is auto-generated from the pipeline registry. 13 pipeline tasks with dependency ordering, 3 targets (dev/staging/prod), daily schedule.
|
||||
|
||||
```bash
|
||||
uv run python dev/scripts/gen_config.py --dab-sql # generate SQL + DDL (~4 min)
|
||||
databricks bundle deploy -t dev # deploy to Databricks
|
||||
```
|
||||
|
||||
## Project layout
|
||||
|
||||
```
|
||||
@@ -257,16 +289,20 @@ stack/
|
||||
│ ├── prometheus/ Metrics collection
|
||||
│ ├── loki/ Log aggregation
|
||||
│ └── ... coredns, nginx, trino, polaris, rustfs, act-runner, gitea
|
||||
├── assets/ Branding and styles
|
||||
├── assets/ Branding, styles, generated artifacts
|
||||
│ ├── css/ Per-service CSS (dashboard, gitea, marimo, woodpecker)
|
||||
│ ├── icons/ Favicons, logos, SVGs
|
||||
│ ├── icons/ Favicons, logos, coverage badge
|
||||
│ └── nature.py Nature-conformant chart palette
|
||||
├── cloud/ Cloud provider deployment guides
|
||||
│ ├── self-hosted/ Docker Compose (default)
|
||||
│ ├── aws/ S3, RDS, Glue, ECS
|
||||
│ ├── gcp/ GCS, Cloud SQL, BigQuery, Cloud Run
|
||||
│ └── azure/ ABFS, Azure SQL, Unity Catalog, Container Apps
|
||||
├── dev/ Dev tooling (scripts, hooks, seeds)
|
||||
├── dev/ Dev tooling
|
||||
│ ├── scripts/ Code generators, bootstrap, supply chain tools
|
||||
│ ├── hooks/ Git pre-commit hook
|
||||
│ ├── seeds/ Reference data (BCDA samples, CMS docs)
|
||||
│ └── pipelines/ CI-agnostic pipeline specs
|
||||
├── tests/ 11,955 tests at 99% coverage
|
||||
├── notebooks/ Marimo notebooks
|
||||
├── docs/ Docusaurus site
|
||||
|
||||
Reference in New Issue
Block a user