One PostgreSQL schema per tenant
Requests set the search path inside a transaction; a missing tenant predicate cannot cross a boundary.
Search, rights, provenance, storage and delivery in one auditable workflow—built in Rust for teams that cannot afford to guess.
The one idea
A badge is context. A signed URL is permission to attempt. The real decision happens when the asset is fetched, against the latest evidence.
asset_74cc · distribution · exp 00:54 Unknown never becomes permission. Add evidence, then try the same URL again.
purpose=distribution · rights=unknown · decision=deny One accountable workflow
Move through the product by the job it must do. The same asset stays explainable from ingest to publication.
Find it
Search, facets, saved views and near-duplicate detection work over the same permission-scoped catalogue.
System map
Metadata, previews and search stay hot while masters move through lower-cost storage. A model upgrade never has to thaw the archive.
Stream, hash, sniff and scan.
Preview, proxy and evidence.
Search only after previews exist.
Evaluate rights, record, release.
Requests set the search path inside a transaction; a missing tenant predicate cannot cross a boundary.
PostgreSQL remains the record. Tantivy and vectors can be rebuilt, upgraded or replaced.
The API stays latency-sensitive; the worker owns CPU-heavy and untrusted media processing.
Documentation
The repository documents the contract, architectural decisions, deployment shape and unfinished work. Nothing is hidden behind a glossy status page.
mise pins the toolchain. Docker supplies PostgreSQL and SeaweedFS; the API, worker and web app remain separate processes.
mise install
mise run up
mise run dev:seedFind it. Trust it. Use it.