Skip to main content

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 catalog
  • update: Create a new document version for an existing component
  • drop: Remove a component and its history
  • delete: Delete the entire catalog (irreversible)

How It Works Internally

Dual-Write Pattern

DFOS uses a dual-write architecture:

  1. Catalog operations provide cryptographic verification and history
  2. Database tables provide fast reads and queries

When you update your profile via the API:

  1. System creates a catalog update operation
  2. Operation is signed with your assertion key
  3. Operation is stored in the catalog log
  4. 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:

  1. Construct unsigned operation
  2. Encode as DAG-CBOR
  3. Compute CID of encoded bytes
  4. Sign CID bytes with assertion key
  5. 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:

  1. Schema definition language: How to formally define and publish component schemas
  2. Validation framework: How to validate components against schemas
  3. Discovery mechanism: How applications discover available component types
  4. Migration strategy: How to handle schema changes over time
  5. 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

  1. Operation structure matches schema
  2. CID recomputation matches claimed CID
  3. Operation chain is valid (previousOperationCID references check out)
  4. Timestamps are monotonically increasing
  5. Signature is valid for claimed key
  6. Signing key is in creator's assertion key set (from DID document)
  7. 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.