Tenants Guide
jinflow is multi-tenant. Each tenant is an independent analytical workspace with its own data, AFS, and KLS.
Tenant Layout
Section titled “Tenant Layout”live_root/ millesime/ domaine_zufferey/ afs/ ← analytical framework (copy of pack + tenant-specific additions) raw/ ← immutable source CSVs (from DLZ) build/ ← intermediaries (compiled SQL, enriched CSVs) store/ ← KLS + SIS + logs + snapshotsPack-Qualified IDs
Section titled “Pack-Qualified IDs”All commands use pack.tenant notation:
jin make --tenant millesime.domaine_zuffereyjin explore --tenant millesime.domaine_zuffereyjin afs update --tenant millesime.domaine_zuffereyCreating a Tenant
Section titled “Creating a Tenant”# From a pack name (resolved via pack_root)jin init --pack millesime --tenant domaine_new --source-system opale
# From a pack pathjin init --pack /path/to/jinflow-pack-millesime --tenant domaine_new --source-system opaleThis creates live_root/millesime/domaine_new/ with:
afs/— copy of the packraw/,build/,store/— empty, ready for data
Syncing Pack → Tenant
Section titled “Syncing Pack → Tenant”When the pack is updated (new signals, theses, etc.):
# Dry-run (see what would change)jin afs update --tenant millesime.domaine_zufferey
# Apply changesjin afs update --tenant millesime.domaine_zufferey --do-it
# All tenants across all packsjin afs update --all --do-it
# Force pack version on conflictsjin afs update --tenant millesime.domaine_zufferey --do-it --forceThree-way sync: pack base manifest tracks what was synced last. If both pack and tenant changed the same file → conflict (not overwritten unless --force).
Building
Section titled “Building”jin make --tenant millesime.domaine_zufferey # build one tenantjin make --pack millesime # all tenants in packjin make --all # all tenants, all packsjin make --all --sync # sync DLZ + buildjin make --tenant millesime.domaine_zufferey --extract # Excel → CSV → sync → buildjin make --tenant millesime.domaine_zufferey --clean # clear intermediaries, full rebuildThe Extraction Contract (pipeline.yml)
Section titled “The Extraction Contract (pipeline.yml)”Every tenant has a pipeline.yml at afs/scripts/pipeline.yml that declares every file crossing the extraction layer: exact path, SHA-256 pin, source type, expected schema, attribution. The configuration IS the contract, and the contract is the audit trail. Reading it tells you the complete universe of what jin make --extract will ever touch.
extract: - id: opale_cases_v2026_02 script: extract_opale_xlsx_csv.py purpose: summary: "OPALE clinical export — cases, procedures, materials, billing events" delivered_by: "Sapheneia (Raffa channel)" delivered_at: "2026-02-17" source: type: system_export path: "opale/xslx/V2026-02/cases.xlsx" sha256: "a3b5c7f89012e8d4cdef0123456789abcdef0123456789abcdef0123456789ab" output: - { path: "build/csv/cases.csv", required: true } - { path: "build/csv/procedures.csv", required: true } expected: sheets: - name: "Fälle" required_columns: ["ABT", "FALL", "EINTRITT", "AUSTRITT"] min_rows: 10000The file is tenant-specific and fully self-contained — there is no pack-level inheritance. Two tenants in the same pack using the same source system still have different pipeline.yml files because delivery channels, file versions, and auxiliary files differ.
See the Extraction Guide for the six source types, the zero-transform rule, and the jin extract --contract inspection command.
Data Flow
Section titled “Data Flow”The pipeline has two phases: pre-make (gathers inputs, has side effects) and make (a pure function, AFS in → KLS out).
Cloning a Tenant
Section titled “Cloning a Tenant”jin clone --source millesime.domaine_zufferey --name experiment# Creates: millesime.domaine_zufferey_experiment (shares DLZ with source)Snapshots
Section titled “Snapshots”jin make --snapshot # auto-tag: YYYYMMDD-HHMMjin make --snapshot post-audit # named tagSnapshots are immutable — make refuses to overwrite them.
Configuration
Section titled “Configuration”# Set default tenantjin us --tenant millesime.domaine_zufferey
# Show current configjin usOutput:
Live root: /path/to/jinflow-live Pack root: /path/to/jinflow-packhub (4 packs) DLZ: /path/to/jinflow-datalandingzone (ok) Current tenant: millesime.domaine_zuffereyMulti-Pack
Section titled “Multi-Pack”Each pack is an independent analytical domain. Tenants belong to one pack:
live_root/ millesime/ ← winemaking analytics domaine_zufferey/ domaine_clavien/ alptrack/ ← ski resort analytics resort_alpine/ resort_glacier/Packs are developed independently (separate git repos) and synced to tenants via jin afs update.