Skip to content

UCCA World Container Specification v1.0

Classification: INTERNAL — Architecture
Owner: Tim
Status: Draft
Date: 2026-03-04


1. Purpose

This document defines the canonical structure for a UCCA World Container — the standard deployable unit that encapsulates a regulatory domain. Every world, regardless of jurisdiction or industry, conforms to this specification. The specification serves as the "mother horda" — the authoritative template from which all world instances are derived.

No world is built from scratch. Every world is an instantiation of this template with domain-specific variables.


2. Platform Layer Model

UCCA operates a four-layer access hierarchy. The World Container exists at Layer 2 and provides the structural foundation for Layers 3 and 4.

Layer 1 — UCCA Platform (Super Admin)

Operators: UCCA staff (Tim, Jimmy, future team).
Scope: Full platform visibility. All clients, all worlds, governance, health, billing, account switcher.
URL pattern: ops.ucca.online/...
Database: ops-db (platform telemetry, client registry, billing).

Layer 2 — Client Administration (UCCA-side)

Operators: UCCA staff, scoped to a single client.
Scope: Internal CRM/admin for one customer — billing, support notes, data analytics, world configuration, ingestion monitoring. The client never sees this layer.
URL pattern: ops.ucca.online/clients/[client-id]/...
Database: ops-db (client record) + client's world database(s) (read access).

Layer 3 — Client Environment

Operators: Client admin (Bill) and client staff.
Scope: The client's own control panel. Bill manages his business here — onboards staff, assigns roles, configures security profiles, manages compliance, views his data. Staff see the same environment scoped by role permissions. Bill can white-label this layer.
URL pattern: [client-slug].ucca.online/... or client's own domain (white-label).
Database: Client's world database(s) via contract endpoints.

Layer 4 — Client End Users

Operators: Bill's customers / end users.
Scope: Flat access layer. Bill provisions users here. Primarily access control — consume data, no management. Bill can step down into this view. UCCA hides this layer by default but can enable visibility.
URL pattern: Same domain as Layer 3, session-scoped.
Database: Same as Layer 3, read-only subset.

Step-Down Mechanic

Each layer's admin can step into the layer below and see what those users see:

  • Layer 1 → steps into Layer 2 (select client from account switcher)
  • Layer 2 → steps into Layer 3 (view as client admin)
  • Layer 3 → steps into Layer 4 (view as end user)

The step-down is a session context switch, not a URL change. A banner indicates the current viewing context.


3. What Is a World

A World is a self-contained regulatory domain. It represents one jurisdiction-industry combination with its own:

  • Authority data (the regulatory register for that domain)
  • Schema (conformant to the canonical UCCA schema contract)
  • Ingestion pipeline (domain-specific data sourcing)
  • API endpoints (conformant to the UCCA endpoint contract)
  • Configuration (infrastructure bindings, metadata, auth)

Examples of worlds:

  • au-vet — Australian Vocational Education and Training
  • uk-caa — United Kingdom Civil Aviation Authority
  • us-faa — United States Federal Aviation Administration
  • au-ahpra — Australian Health Practitioner Regulation Agency

A world is not a customer. A world is a domain. Multiple customers can operate within the same world (e.g., multiple RTOs in au-vet). A customer may also span multiple worlds.


4. World Container Directory Structure

Every world container conforms to this directory structure. No exceptions. No additions outside this tree without specification amendment.

worlds/[world-id]/
├── world.config.json              # World metadata and infrastructure bindings
├── schema/
│   └── schema.sql                 # Canonical database schema for this world
├── api/
│   ├── qualifications.js          # Qualification endpoints
│   ├── units.js                   # Unit/competency endpoints
│   ├── authorities.js             # Authority/provider endpoints (RTOs, etc.)
│   ├── scope.js                   # Scope of registration endpoints
│   ├── verify.js                  # Verification endpoints
│   └── health.js                  # World health check endpoint
├── tools/
│   ├── ingest/                    # Data ingestion scripts (domain-specific)
│   │   ├── source-config.json     # Source API configuration
│   │   └── [source]-parser.mjs    # Parser scripts per data source
│   ├── enrich/                    # Enrichment scripts
│   └── validate/                  # Data validation scripts
├── assets/
│   ├── branding/                  # World-specific branding (if applicable)
│   └── reference/                 # Reference data, code tables
└── docs/
    ├── WORLD.md                   # World documentation
    ├── DATA-SOURCES.md            # Authority data source documentation
    └── CHANGELOG.md               # World change log

5. world.config.json — The World Manifest

This is the single source of truth for a world's identity and infrastructure bindings. The platform reads this file to know what a world is and how to connect to it.

{
  "world_id": "au-vet",
  "display_name": "Australian VET",
  "jurisdiction": "AU",
  "domain": "Vocational Education and Training",
  "status": "active",
  "version": "1.0.0",

  "authority_source": {
    "name": "training.gov.au",
    "type": "government_api",
    "base_url": "https://training.gov.au/api",
    "refresh_cadence": "weekly",
    "mirror_strategy": "full_local"
  },

  "infrastructure": {
    "compute": {
      "provider": "cloudflare",
      "type": "workers",
      "binding": "world_worker"
    },
    "database": {
      "provider": "cloudflare",
      "type": "d1",
      "binding": "rtopacks_db",
      "override_endpoint": null
    },
    "storage": {
      "provider": "cloudflare",
      "type": "r2",
      "bucket": "au-vet-assets",
      "override_endpoint": null
    },
    "backup": {
      "provider": "google",
      "type": "drive",
      "folder_id": "xxx",
      "override_endpoint": null
    }
  },

  "endpoints": {
    "qualifications": "/api/worlds/au-vet/qualifications",
    "units": "/api/worlds/au-vet/units",
    "authorities": "/api/worlds/au-vet/authorities",
    "scope": "/api/worlds/au-vet/scope",
    "verify": "/api/worlds/au-vet/verify",
    "health": "/api/worlds/au-vet/health"
  },

  "schema_version": "v4",

  "owner": {
    "client_id": "ucca-internal",
    "contact": "tim@ucca.online"
  },

  "feature_flags": {
    "white_label": false,
    "end_user_layer": false,
    "custom_infrastructure": false
  }
}

Infrastructure Override Pattern

The override_endpoint field in each infrastructure block is the decoupling mechanism. When null, the world uses the default UCCA infrastructure (Cloudflare). When populated, the world's API routes call the override endpoint instead.

This is how Bill runs his data on AWS while using the UCCA verification engine:

"database": {
  "provider": "aws",
  "type": "rds-postgres",
  "binding": null,
  "override_endpoint": "https://api.newclient.com/data"
}

The UCCA platform doesn't care. It calls the contract endpoints. The world config routes those calls to wherever the data lives.


6. Endpoint Contract

Every world must expose these endpoints. The implementation varies by infrastructure choice. The contract does not.

Required Endpoints

Endpoint Method Purpose Response Contract
/qualifications GET List/search qualifications { items: [], total, page, limit }
/qualifications/[code] GET Single qualification with units { qualification: {}, units: { core: [], elective: [] }, specialisations: [] }
/units GET List/search units { items: [], total, page, limit }
/units/[code] GET Single unit with reverse lookup { unit: {}, qualifications: [] }
/authorities GET List/search authorities (RTOs, etc.) { items: [], total, page, limit }
/authorities/[code] GET Single authority with scope { authority: {}, scope: [] }
/scope GET Scope lookup { items: [], total, page, limit }
/verify POST Verification request { result: {}, evidence_chain: [] }
/health GET World health status { status, database, last_sync, record_counts }

Response Headers (All Endpoints)

All world endpoints must include UCCA provenance headers:

X-UCCA-World: au-vet
X-UCCA-Schema-Version: v4
X-UCCA-Source: training.gov.au
X-UCCA-Timestamp: 2026-03-04T10:00:00Z

Search Convention

All list endpoints accept: ?q=search&page=1&limit=25&sort=code&order=asc

Error Convention

All endpoints return errors as: { error: { code, message, world_id } }


7. Schema Contract

Every world's database schema must include these canonical tables. Column names are standardised. Additional domain-specific columns are permitted but must not conflict with canonical columns.

Required Tables

Table Purpose Canonical Columns
qualifications Credential register qual_code, title, status, level, package_code, package_title
units Competency register unit_code, title, status, usage_recommendation
authorities Provider register authority_code, name, status, type
qualification_units Qual-unit junction qualification_code, unit_code, role (core/elective)
authority_scope Authority-qual junction authority_code, qual_code, status
qualification_specialisations Specialisation register qualification_code, specialisation_code, title

Naming Convention

  • World-specific tables are prefixed with the world ID: auvet_rto_contacts
  • Canonical tables use generic names (no prefix)
  • Junction tables use the pattern [parent]_[child]

8. Terraform Module — The Mother Horda

The world container is provisioned via a Terraform module. The module is the authoritative definition of what a world IS. Individual worlds are instantiations with variables.

Module Structure

infrastructure/
  modules/
    world/                          # The mother horda
      main.tf                       # Resource definitions
      variables.tf                  # What makes each world unique
      outputs.tf                    # What a world exposes
      d1.tf                         # Database provisioning
      r2.tf                         # Object storage provisioning
      worker.tf                     # Compute provisioning
      dns.tf                        # DNS and routing
      security.tf                   # WAF, rate limiting, headers

  sandbox/
    main.tf                         # Test instantiation of the module
    terraform.tfvars                # Sandbox variables

  environments/
    au-vet/
      main.tf                       # module "au-vet" { source = "../../modules/world" }
      terraform.tfvars              # au-vet specific variables
    [future-world]/
      main.tf
      terraform.tfvars

Module Variables (variables.tf)

variable "world_id" {
  description = "Unique world identifier (e.g., au-vet, uk-caa)"
  type        = string
}

variable "display_name" {
  description = "Human-readable world name"
  type        = string
}

variable "jurisdiction" {
  description = "ISO country code"
  type        = string
}

variable "domain" {
  description = "Regulatory domain name"
  type        = string
}

variable "client_id" {
  description = "Owning client identifier"
  type        = string
  default     = "ucca-internal"
}

variable "database_name" {
  description = "D1 database name"
  type        = string
}

variable "r2_bucket" {
  description = "R2 bucket name for world assets"
  type        = string
}

variable "custom_domain" {
  description = "Custom domain for white-label (null for default)"
  type        = string
  default     = null
}

variable "enable_end_user_layer" {
  description = "Enable Layer 4 for this world"
  type        = bool
  default     = false
}

Module Outputs (outputs.tf)

output "world_id" {
  value = var.world_id
}

output "database_id" {
  value = cloudflare_d1_database.world_db.id
}

output "api_endpoint" {
  value = "https://api.ucca.online/worlds/${var.world_id}"
}

output "health_endpoint" {
  value = "https://api.ucca.online/worlds/${var.world_id}/health"
}

Sandbox Usage

# sandbox/main.tf
module "sandbox_world" {
  source = "../modules/world"

  world_id      = "sandbox"
  display_name  = "Sandbox World"
  jurisdiction  = "XX"
  domain        = "Testing"
  database_name = "sandbox-db"
  r2_bucket     = "sandbox-assets"
}

The sandbox is where module changes are tested. When satisfied, the module is committed and all environments inherit the change on next terraform apply.


9. Isolation Boundaries

Data Isolation

  • Each world has its own D1 database instance. No shared tables across worlds.
  • Each world has its own R2 bucket. No shared object storage.
  • Platform data (ops-db) never contains world-specific authority data.

Code Isolation

  • World-specific code lives under worlds/[world-id]/. No world code in platform directories.
  • API routes are namespaced: /api/worlds/[world-id]/...
  • Shared platform code (auth, billing, telemetry) lives in platform directories and is imported by worlds, never duplicated.

Compute Isolation

  • Default: all worlds share the ops Worker with route-based dispatch.
  • Scale: individual worlds can be promoted to their own Worker when traffic justifies it.
  • Custom infrastructure: worlds with override_endpoint run their own compute entirely.

Auth Isolation

  • Layer 1/2 auth: UCCA platform credentials. Managed by UCCA.
  • Layer 3/4 auth: Client credentials. Managed by client admin.
  • Cross-layer access is via step-down tokens, not shared credentials.

10. Migration Path — RTOpacks as First Container

RTOpacks (au-vet) is currently interleaved with the Layer 1 platform. The migration to a proper world container requires:

Phase 1 — Namespace API Routes

Current: /api/ops/qualifications/
Target: /api/worlds/au-vet/qualifications/

Maintain /api/ops/ routes as redirects during transition.

Phase 2 — Relocate World Code

Current: apps/ops-v2/app/api/ops/qualifications/
Target: worlds/au-vet/api/qualifications.js

The ops app imports world API handlers rather than containing them.

Phase 3 — Isolate World UI

Current: /w/[workspace]/ops/... pages contain world-specific data views.
Target: World data views are loaded from world container, rendered within Layer 2 chrome.

Phase 4 — Generate world.config.json

Create the au-vet manifest from existing configuration. This becomes the reference config for all future worlds.


11. Code Classification Prism

Until the platform/world boundary is fully understood, every file in a world container carries a classification header. This is an observational tool, not a governance decision. The classifications evolve as patterns emerge.

Classification Header

Every source file in the world container includes this header block:

// @ucca-scope: platform | world | unknown
// @ucca-maintainer: ucca | client | shared | unknown
// @ucca-versioning: platform-track | world-track | independent

Scope — where this code conceptually belongs:

  • platform — generic to all worlds. UCCA maintains this. Qualification search logic, pagination, auth, schema migrations, health checks.
  • world — specific to this regulatory domain. The TGA parser, AU-VET specific enrichment rules, domain-specific validation.
  • unknown — not yet classified. This is the honest default.

Maintainer — who is responsible for this code in a multi-tenant future:

  • ucca — UCCA maintains and updates. Client receives updates automatically. Breaking changes follow a release cycle.
  • client — client owns and maintains. UCCA provides the scaffold but the client customises. Ingestion scripts for their data sources, custom business logic.
  • shared — both parties touch this. Configuration files, role templates, branding assets. Requires clear merge/override rules.
  • unknown — not yet determined. Default classification.

Versioning — how updates propagate:

  • platform-track — this file tracks the platform release. When UCCA updates the module, this file updates in all worlds. Client cannot override.
  • world-track — this file tracks the world's own release cycle. UCCA may provide templates but the world's version is authoritative.
  • independent — this file has no upstream dependency. It exists only in this world.

Expected Classification Patterns (Hypothesis)

Based on au-vet development so far, the likely split:

Component Likely Scope Likely Maintainer Reasoning
world.config.json world shared UCCA defines schema, client sets values
schema/schema.sql platform ucca Canonical tables are universal
schema/extensions.sql world client Domain-specific columns and tables
api/qualifications.js platform ucca Search/list logic is generic
api/verify.js platform ucca Verification engine is the product
api/health.js platform ucca Health check contract is standard
tools/ingest/*.mjs world client Data sources are domain-specific
tools/enrich/*.mjs world shared Enrichment patterns may be reusable
tools/validate/*.mjs platform ucca Validation against schema contract
assets/branding/ world client Client's visual identity
assets/reference/ world client Domain-specific reference data
docs/ world shared Documentation is world-specific

These are hypotheses. The prism exists to validate or refute them as au-vet reaches completion.

Prism Report

At any point, a classification report can be generated:

grep -r "@ucca-scope" worlds/au-vet/ | sort | uniq -c

This produces a count of files by scope, revealing the actual platform/world boundary from observed data rather than architectural assumptions.

When to Draw the Line

The classification boundary becomes a governance decision when:

  1. au-vet is feature-complete (all API endpoints, ingestion, UI)
  2. A second world is being planned (forces the question: what do we copy vs. share?)
  3. A client requests custom infrastructure (forces the question: what can they change?)

Until then, classify honestly. unknown is a valid and encouraged answer.


12. What This Specification Is NOT

  • It is NOT a customer onboarding specification (that's a separate document).
  • It is NOT a billing model (Layer 2 concern).
  • It is NOT a white-label specification (Layer 3 concern).
  • It is NOT a FedRAMP compliance document (though it enables FedRAMP by design).

It IS the structural definition of what a world is, what it contains, and how it connects to the platform.


13. Document Control

Version Date Author Change
1.0 2026-03-04 Tim / Claude Initial specification

Version History

Version Date Change Author
1.0 2026-03-04 Initial draft Tim Rignold
1.1 2026-03-11 Filed to knowledge site with frontmatter Claude Code