Platform3 · Canonical architecture

Caliper 1edtech Architecture

This page is rendered directly from the committed architecture decisions. Each stable section anchor is part of the public traceability contract.

Source-bound decision record

16 committed decisions · caliper/1edtech

#caliper_served_audiences

caliper served audiences

Unspecified

Decision

developer building an LMS or learning-platform analytics consumer that ingests Caliper Analytics 1.2 events from upstream tools and renders learning-activity evidence through the Caliper 1EdTech surface alone

Alternatives and tradeoffs

  • single-tool event publisher
  • data-warehouse-only consumer
  • Caliper validator without storage

Rationale and consequences

the analytics-consumer persona makes the persona-blocking test concrete; write-only ingestion without read-back is insufficient for the loop's integration deliverable

#caliper_write_granularity

caliper write granularity

Unspecified

Decision

SHIP: Bulk-only Caliper envelope writes through `POST /caliper/v1p2/events`; no per-event POST/PUT/PATCH/DELETE operations are part of this 1EdTech surface. Re-open trigger: Re-open per-resource mutation only when three distinct integrator decisions in 90 days show that valid Caliper Sensors cannot complete the served analytics-consumer job with envelope delivery.

Alternatives and tradeoffs

  • per-event POST/PUT/PATCH/DELETE
  • both envelope and per-event write models
  • direct table CRUD

Rationale and consequences

the duplicate-primitive test rejects per-event writes because the Caliper envelope already covers single-event and batch delivery

#caliper_read_shape

caliper read shape

Unspecified

Decision

SHIP + DEFER: Ship known-key detail projections only: `GET /caliper/v1p2/events?eventIri=...` and `GET /caliper/v1p2/envelopes?hash=...`. Defer generic list/detail/sub-collection browsing. Re-open trigger: Re-open generic list/detail browsing when an approved customer-website workflow needs discovery without a known event IRI or envelope hash, or when three integrator decisions in 90 days cite missing browsing as job-blocking.

Alternatives and tradeoffs

  • list-only
  • list + detail
  • list + detail + sub-collections

Rationale and consequences

negative-complexity test ships narrow read-back because it proves persistence without turning the Sensor API into an analytics browsing API

#caliper_query_model

caliper query model

Unspecified

Decision

SHIP + DEFER: Ship exact identifier lookup parameters only (`eventIri`, `hash`). Defer filter, sort, cursor paging, and `modifiedSince` query semantics. Re-open trigger: Re-open automatically with any approved collection list endpoint, or when three integrator decisions in 90 days need Caliper activity search to complete the served-audience job.

Alternatives and tradeoffs

  • filter + sort
  • filter + cursor paging
  • filter + cursor paging + modifiedSince

Rationale and consequences

query expansion is deferred because exact lookup already covers the published read-after-write workflow and broader filtering would be a new primitive

#caliper_concurrency_model

caliper concurrency model

Unspecified

Decision

DEFER: No If-Match or ETag concurrency model ships because the Caliper 1EdTech surface has no mutable resource overwrite route. Re-open trigger: Re-open with the first approved Caliper update/delete route or any feature request that makes an existing Caliper row mutable through the public API.

Alternatives and tradeoffs

  • If-Match per resource
  • bulk-only If-Match
  • last-write-wins update routes

Rationale and consequences

the duplicate-primitive test rejects concurrency headers until there is a mutable resource primitive for them to protect

#caliper_idempotency_model

caliper idempotency model

Unspecified

Decision

SHIP: Canonical envelope/event hashes deduplicate Caliper delivery; optional `Idempotency-Key` records retry state in `platform.idempotency_key` and returns `409 conflict` if reused with different content. Re-open trigger: Re-open only if Caliper certification evidence or repeated live incidents show content-hash deduplication is insufficient for valid Sensor retries.

Alternatives and tradeoffs

  • no idempotency
  • required Idempotency-Key on every Sensor request
  • database UUID-only duplicate handling

Rationale and consequences

negative-complexity test ships canonical hashes because equivalent JSON retries collapse without imposing a new required client header

#caliper_auth_shape

caliper auth shape

Unspecified

Decision

SHIP: HS256 Bearer JWTs with tenant claims, role/roles, and optional scopes (`caliper:write`, `caliper:read`) plus an active tenant-owned `caliper.sensor` registry. Re-open trigger: Re-open school/class scoped claims only if a platform-level authorization commitment requires them across standards modules, not from Caliper alone.

Alternatives and tradeoffs

  • role-only JWT
  • scoped claims such as agentOf/schoolSourcedIds/classSourcedIds
  • API keys without tenant claims

Rationale and consequences

role plus optional scopes is the smallest auth shape that separates Sensor writes from authenticated read projections without inventing school-domain claims

#caliper_eventing_model

caliper eventing model

Unspecified

Decision

DEFER: No outbound webhooks, event stream, poll feed, or `modifiedSince` eventing model ships. Caliper event ingestion is the inbound standard primitive; read projections are exact lookups only. Re-open trigger: Re-open when a shipped workflow becomes asynchronous enough that a cold integrator cannot distinguish completion from failure, or when three integrator decisions in 90 days request event feed semantics to complete the documented job.

Alternatives and tradeoffs

  • poll-only
  • poll + modifiedSince
  • webhooks

Rationale and consequences

default defer applies because eventing would add a second way to observe data before the persona is blocked without it

#caliper_error_envelope

caliper error envelope

Unspecified

Decision

SHIP: RFC 7807-style Problem JSON with stable platform problem type URIs, flat `code` values such as `invalid_request`, `unauthorized`, `forbidden`, `conflict`, `not_found`, `unsupported_media_type`, and `source_validation_failed`, plus field-level codes such as `unsupported_caliper_action`. Re-open trigger: Re-open only if platform PITD-006 changes the shared Problem contract or SDK generation needs a public problem-code registry.

Alternatives and tradeoffs

  • no error envelope
  • plain prose errors
  • surface-prefixed namespace on every Problem code value

Rationale and consequences

negative-complexity test ships stable Problem codes because integrators can branch on codes while the platform keeps one shared envelope

#caliper_tenant_routing

caliper tenant routing

Unspecified

Decision

SHIP: Tenant is routed by required `X-Timeback-Tenant` header plus a matching JWT tenant claim on `CALIPER_BASE_URL`; there is no tenant path prefix and no JWT-only hidden tenant routing. Re-open trigger: Re-open only if platform-wide routing changes or a Caliper certification test forbids the additional tenant header.

Alternatives and tradeoffs

  • tenant in URL
  • JWT-only hidden tenant routing
  • tenant inferred from actor/group/entity payloads

Rationale and consequences

tenant header plus JWT match removes ambiguity without corrupting Caliper JSON-LD payload semantics

#caliper_conformance_evidence

caliper conformance evidence

Unspecified

Decision

SHIP + DEFER: Ship local spec-runner, transport, docs, live demo/reviewer, surface-QC, and integration evidence in `caliper.conformance_run`; defer official 1EdTech certification until external evidence exists. Re-open trigger: Re-open official certification when a customer contract, compliance requirement, or successful 1EdTech certification run provides external evidence to link.

Alternatives and tradeoffs

  • no conformance evidence
  • claim official certification from local tests
  • external certification required before first release

Rationale and consequences

negative-complexity test ships local evidence because it prevents silent overclaiming while giving reviewers concrete proof

#caliper_privacy_retention

caliper privacy retention

Unspecified

Decision

SHIP + DEFER: Ship tenant-scoped raw-payload preservation with redaction from Problems, logs, audit metadata, traces, search indexes, public docs, and conformance evidence. Defer a Caliper-specific public DELETE or age-based retention API. Re-open trigger: Re-open Caliper-specific deletion or retention endpoints when platform privacy policy names retention periods or a legal/compliance workflow requires a public erasure operation for Caliper learner activity.

Alternatives and tradeoffs

  • reject all learner PII in raw Caliper payloads
  • copy raw payload data to logs and audit rows
  • ship public DELETE endpoints without platform retention policy

Rationale and consequences

negative-complexity test ships redaction now because it removes a silent privacy failure; deletion API is deferred until policy exists

#caliper_list_endpoints

caliper list endpoints

Unspecified

Decision

DEFER: Write-and-remember: no collection list endpoints ship. Integrators keep event IRIs and envelope hashes from their own Caliper payloads and use exact read projections for verification. Re-open trigger: Re-open with the read-shape trigger, or when an approved integration app needs activity browsing as its first-screen workflow without an event IRI or envelope hash supplied by the user's own Sensor flow.

Alternatives and tradeoffs

  • one list endpoint per collection
  • list + detail + sub-collections
  • broad analytics browsing in the first 1EdTech surface

Rationale and consequences

default defer applies because exact read projections already prove persistence and collection browsing is a new API primitive

#caliper_sensor_api_endpoint

caliper sensor api endpoint

Unspecified

Decision

POST /caliper/v1p2/events accepts a Caliper Analytics 1.2 Sensor API envelope with sensor, sendTime, dataVersion=http://purl.imsglobal.org/ctx/caliper/v1p2, and data[]; successful ingest returns 204 No Content and no JSON body

Alternatives and tradeoffs

  • older unversioned event route
  • accepted response with a batch-id JSON body
  • per-event POST without a Sensor envelope

Rationale and consequences

the approved customer website and implementation use the v1p2 Sensor API path and 204 success contract; returning a batch body from the Sensor endpoint was rejected to keep certification-style transport behavior clean

#caliper_operational_read_projections

caliper operational read projections

Unspecified

Decision

GET /caliper/v1p2/events?eventIri={eventIri} and GET /caliper/v1p2/envelopes?hash={envelopeHash} are authenticated TimeBack operational read projections for read-after-write proof; they are not official Caliper Sensor API certification operations

Alternatives and tradeoffs

  • no read-back
  • actor/action collection-filter list endpoints
  • direct database access for reviewers and integrators

Rationale and consequences

narrow read projections let cold reviewers and integrators prove persisted state without expanding the Sensor API into a broad analytics query surface

#caliper_demo_token_mint

caliper demo token mint

Unspecified

Decision

POST /dev/mint?tenantId=00000000-0000-4000-8000-00000000ca12 mints short-lived demo JWTs on the same CALIPER_BASE_URL; real-tenant reviewer tokens are minted out of band by the loop driver

Alternatives and tradeoffs

  • separate demo deployment
  • public minting for arbitrary tenants
  • manual credentials required before the quickstart

Rationale and consequences

single-deploy tenant scoping avoids Vercel cold-start state loss while still letting a cold integrator run the demo without human credential setup