Catalog Model
Status: Internal Implementation Detail Audience: DFOS implementers and protocol developers Stability: Evolving
Overview
The catalog system is DFOS's cryptographic content layer. It provides content-addressable, versioned storage for typed components (profiles, posts, etc.) with full cryptographic verification. Currently, this system is an internal implementation detail backing the API, but future versions will expose it as an extensible protocol allowing third-party developers and spaces to define custom component schemas.
What is the Catalog?
Every identity (user or space) has a catalog—a cryptographically-signed log of operations that create, update, and delete typed content components. The catalog provides:
- Cryptographic verification: All content is signed and verifiable
- Version history: Full edit history with content addressing
- Decentralized attribution: Content authorship is permanent and unforgeable
- Immutable audit trail: Changes are logged, not overwritten
Think of it as git for identity-linked content, where every change is cryptographically signed and content-addressed.
Core Concepts
Components
A component is a typed piece of content associated with an identity. Each identity can have one component per type.
Current component types (internal only):
profile: Display information (name, description, avatar, banner, background)post: Posts and comments (title, body, media attachments)
Future: Custom component types defined by third-party developers and spaces.
Documents
A document is a specific version of a component. When you update a component, a new document is created. Documents are:
- Content-addressed: CID derived from content (same content = same CID)
- Immutable: Once created, never modified
- Versioned: Documents link to previous versions via
baseDocumentCID
Operations
Operations are signed changes to the catalog. They form an append-only log, similar to identity operations (see DID Method).
Operation types:
create: Add a new component to the catalogupdate: Create a new document version for an existing componentdrop: Remove a component and its historydelete: Delete the entire catalog (irreversible)
How It Works Internally
Dual-Write Pattern
DFOS uses a dual-write architecture:
- Catalog operations provide cryptographic verification and history
- Database tables provide fast reads and queries
When you update your profile via the API:
- System creates a catalog
updateoperation - Operation is signed with your assertion key
- Operation is stored in the catalog log
- Current state is also written to the database for fast access
This gives you both performance (database queries) and cryptographic proof (catalog verification).
Content Addressing
All catalog content uses DAG-CBOR encoding and CIDs (Content Identifiers):
// Same content always produces the same CID
const document = {
content: { type: 'profile', name: 'Alice' },
baseDocumentCID: null,
createdByDID: 'did:dfos:...',
createdAt: '2025-10-24T12:00:00.000Z',
};
// CID is deterministic: encode → hash → format
const cid = await computeCID(document);
// bafyrei... (always the same for this content)
This enables:
- Verification: Recompute CID to check content integrity
- Deduplication: Same content has same CID across the system
- Linking: Documents can reference each other by CID
Signing and Verification
Every operation is signed by the creating identity using an assertion key:
- Construct unsigned operation
- Encode as DAG-CBOR
- Compute CID of encoded bytes
- Sign CID bytes with assertion key
- Create signed operation envelope
Verification reverses this process and checks that the signature matches a key in the identity's current assertion key set.
Operation Schemas
Create Operation
interface CreateOperation {
type: 'create';
identityDID: string; // Catalog owner
previousOperationCID: string | null; // Previous operation (null if first)
component: Component; // The component data
createdByDID: string; // Who created this
createdAt: string; // ISO 8601 timestamp
}
Creates a new component. Fails if component of this type already exists for this identity.
Update Operation
interface UpdateOperation {
type: 'update';
identityDID: string;
previousOperationCID: string;
component: Component;
baseDocumentCID: string | null; // Previous document version (for history chain)
createdByDID: string;
createdAt: string;
}
Updates an existing component. Creates a new document that can optionally link to the previous version.
Drop Operation
interface DropOperation {
type: 'drop';
identityDID: string;
componentType: string; // e.g., 'profile'
previousOperationCID: string;
createdByDID: string;
createdAt: string;
}
Removes a component and all its documents. Irreversible.
Delete Operation
interface DeleteOperation {
type: 'delete';
identityDID: string;
previousOperationCID: string;
createdByDID: string;
createdAt: string;
}
Deletes the entire catalog. Irreversible.
Current Usage
Profiles
User and space profiles are stored as catalog components:
{
type: 'profile',
name?: string,
description?: string,
avatar?: { id: string, canonicalUri?: string },
banner?: { id: string, canonicalUri?: string },
background?: { id: string, canonicalUri?: string }
}
All fields optional. Profile updates create new documents with full version history.
Posts
Posts and comments are catalog components with rich content:
{
type: 'post',
title?: string,
body?: string,
coverImage?: { id: string, canonicalUri?: string },
bannerImage?: { id: string, canonicalUri?: string },
attachments?: Array<{ id: string, canonicalUri?: string }>
}
Post edits create new documents. The edit history is preserved via baseDocumentCID links.
Future: Extensible Component Schemas
The catalog system is designed for extensibility. Future versions will allow:
Custom Component Types
Third-party developers and spaces will be able to define custom component schemas:
// Example: Custom "event" component for a space
{
type: 'space:metalabel:event',
title: string,
startTime: string,
endTime: string,
location?: string,
attendees?: string[] // DIDs
}
Custom types use namespaced names (space:SPACE_DOMAIN:TYPE) to prevent conflicts.
Schema Versioning
Component schemas will support versioning:
{
type: 'space:metalabel:event',
schemaVersion: 2, // Allows schema evolution
// ... fields
}
Applications can handle multiple schema versions for backwards compatibility.
Third-Party Verification
With schemas published on-chain or via IPFS, third parties can:
- Verify component content matches its schema
- Build tools that work with custom component types
- Create interoperable applications
Space-Specific Components
Spaces will be able to define components that only exist within their context:
- Custom content types for specific workflows
- Space-specific metadata and structure
- Shared schemas across related spaces
Why Not Expose It Now?
The catalog system is powerful but still evolving. We're working on:
- Schema definition language: How to formally define and publish component schemas
- Validation framework: How to validate components against schemas
- Discovery mechanism: How applications discover available component types
- Migration strategy: How to handle schema changes over time
- Access control: Who can create which component types where
Until these are stable, the catalog remains an internal detail. The API provides a stable interface while the catalog evolves underneath.
For Developers: What This Means
Today: Use the API. Profile and post operations are backed by the catalog, giving you cryptographic verification and version history automatically.
Future: Define custom content types for your applications and spaces. Build on the catalog protocol directly for maximum flexibility.
Recommendation: Build on the API now. The catalog's guarantees (verification, versioning, attribution) will carry forward even as the interface evolves.
Technical Details
CID Computation
1. Canonically encode structure as DAG-CBOR
2. Hash encoded bytes (SHA-256)
3. Create CID (v1, raw, sha256, multibase base58btc)
4. Result: bafyrei... (deterministic)
Verification Rules
- Operation structure matches schema
- CID recomputation matches claimed CID
- Operation chain is valid (
previousOperationCIDreferences check out) - Timestamps are monotonically increasing
- Signature is valid for claimed key
- Signing key is in creator's assertion key set (from DID document)
- Component-specific rules pass (e.g., component doesn't already exist for
create)
Media References
Components reference media by opaque IDs:
{
id: string, // Media object ID (e.g., "media_abc123")
canonicalUri?: string // Optional IPFS or other URI
}
The media system handles storage and serving. Catalog operations just reference IDs.
Design Philosophy
The catalog embodies several key principles:
Cryptographic verification over trust: Content authorship is provable, not asserted.
Versioning over overwriting: History is preserved, not erased.
Content addressing over location addressing: Content is identified by what it is, not where it lives.
Extensibility over lock-in: The protocol will support custom types, not just platform-defined ones.
Decoupling over coupling: Catalog provides verification layer; database provides query layer. Best of both worlds.
This creates a foundation for verifiable, extensible, user-controlled content that can outlive any single platform implementation.