Compose domains from one type system
Scheduled5 min read By NT²
A medical pack and an IT pack should not each reinvent “expiry date.” Domains grow by composing a shared semantic catalog into category templates—then enabling the packs you need.
Compose domains from one type system
Claim: domains scale by composition
Semantic columns, not form widgets put meaning in a global field registry. This essay is about growth: how NT² Vault serves many domains without forking the product into vertical apps.
The claim: new domains are composed, not invented from scratch. Field packs
contribute vocabulary. Category templates arrange that vocabulary into schemas.
Optional packs are enabled per vault. Row-level features—expiry, password
health, share defaults—follow the active field set on an item, not a
permanent if (category === "bank") switchboard.
That is why one local-first, zero-knowledge vault can hold credentials today and grow into documents, bank details, SSH keys, and medical cards without becoming a blank page or a monolith of special cases.
The constraint: slug gates explode
The naïve way to ship verticals is category branching:
if category == credential → password UI
if category == bank → IBAN UI
if category == document → expiry cron
It feels clear on day one. It fails as the catalog grows.
Packs multiply. IT alone may include API services, servers, SSH keys, VPN profiles, and certificates. Medical adds cards, providers, prescriptions. Financial adds tax documents and subscriptions. Every feature that keys only on slug needs another branch—or silently does nothing for the new pack.
Per-item extras break the illusion. A single document item may need an extra phone field for this year’s renewal. If features only understand “document template as shipped,” sparse extras are invisible to reminders, search, and share masks.
Parallel type universes appear. Each vertical team ships its own “date,” “id number,” and “secret” under private names. You lose the registry leverage the previous essay argued for.
Micro-apps look like an escape hatch. Sandboxed UI bundles are a real product surface for specialized tools. They are the wrong registration path for field types. If understanding a schema requires loading an iframe app, the vault core no longer owns the document model.
NT²’s constraint: category labels organize collections; they must not be the only way features discover meaning.
The design: packs, templates, active fields
Field packs = vocabulary
Field packs are versioned sets of semantic type definitions. A core pack covers everyday secrets and notes. Domain packs add specialized vocabulary—financial identifiers, infrastructure fields, medical card fields—while reusing shared types like dates and secrets wherever possible.
Packs are data. They merge into one registry. They do not each ship a private runtime for “what is a date?”
Category templates = schemas
A category template picks an ordered list of field types, labels, and placement options (required, share defaults, display hints). Official packs ship ready-made templates: credential and note as core builtins; bank, document, crypto, IT, medical, retail, and others as optional enablements.
Enabling a pack is closer to installing a schema pack than installing a new product. The vault stays one app. The collection list grows.
L0 / L1 / L2 without new types
Customization has tiers, still inside the registry:
| Tier | What it is |
|---|---|
| L0 | Bundled / official templates—curated defaults |
| L1 | Custom templates that rearrange existing field types |
| L2 | Sparse per-item extra fields, still registry types only |
L2 is how one row gains an extra contact field without inventing a new category or a new field type. The active field set for that row is template placements union L2 extras.
Features read the active field set
flowchart TB
Packs[Field packs] --> Reg[Merged registry]
Reg --> Tpl[Category template]
Tpl --> Active[Active field set]
L2[Per-item extras] --> Active
Active --> Edit[Edit form]
Active --> View[View chrome]
Active --> Present[Present / share masks]
Active --> Feat[Expiry, health, recipes]
Expiry reminders care that an expiryDate (or equivalent semantic) is present
and populated—not that the slug string equals document. Password health cares
that a password-shaped field exists on the row—even if the category is an API
service template rather than classic credential. Share and present flows read
placement and type defaults from the same set.
Recipes (multi-field fingerprints) compose the same way: “enough bank fields to treat this as a bank summary” is a field-set question, not a slug question.
Sync and backup stay blind to domains
Category slugs and sealed payloads sync as data. The edge does not need a medical ontology. Composition stays a client concern; zero-knowledge stays an edge concern. That split is load-bearing.
The trade-off: enable packs, do not ship vertical apps
Composition asks users (and product) to enable the domains they need. A brand-new vault is not preloaded with every industry template. Authors must reuse types instead of minting lookalikes.
What you avoid is worse: an app store of mini-vaults, each with its own export format, or a single codebase drowning in category switches.
| Composition | Vertical fork |
|---|---|
| One vault UI | Many niche apps |
| Shared field meaning | Private schemas per vertical |
| Features follow fields | Features follow slug tables |
| Optional packs | Permanent special cases |
What we refuse
We refuse category slug as the long-term feature gate. Slugs organize lists and defaults. They are not a substitute for reading the active field set.
We refuse micro-apps as the field-registration path. Specialized UI may appear in a sandbox; semantic types still enter through the registry and template packs.
We refuse a new app per vertical. Bank, document, and SSH key are packs and templates—not separate products with separate trust stories.
We refuse growing domains by forking “password” into five private secrets. Reuse the catalog; extend it deliberately when a true new concept appears.
One catalog, many collections
Household stories on this blog talk about structure as relief: The spreadsheet on my Desktop and Already local-first, missing structure. Composition is the engineering reason that relief can span domains without turning the vault into Notion.
Next: Searchable metadata, sealed field values— how list/search stay useful while sensitive columns leave RAM as sealed indices. Then Four surfaces, one field set closes the series’ first arc.
For portable ciphertext around those fields, see CBF is how structured fields leave RAM. Try NT² Vault or read nt2.me.
Last updated 2026-11-22
Related stories
- Semantic columns, not form widgets
5 min read
- Four surfaces, one field set
5 min read
- Slots, not a blank page
6 min read