Source-bound decision record
21 committed decisions · case/1edtech
#case_alignment_resource
case alignment resource
Unspecified
Decision
SHIP Alignment as a tenant-scoped TimeBack resource with fields alignmentId, externalSystem, externalId, cfItemUri, cfItemIdentifier, label, metadata, createdAt, updatedAt, and import_batch_id. Alignments are never emitted inside CFPackage export and never counted as CFAssociations.
Alternatives and tradeoffs
- Store external IDs in CFItem extensions
- Store external IDs as CFAssociation ext:* edges
- Separate Alignment resource
Rationale and consequences
A separate Alignment resource lets integrators resolve their own external IDs without leaking tenant-specific identifiers into spec-pure CASE exports.
#case_association_validation
case association validation
Unspecified
Decision
SHIP validation that accepts the CASE 1.1 associationType values and ext:* extension values matching the OpenAPI pattern. originNodeURI and destinationNodeURI targetType default to CASE and accept ext:* for non-CASE targets. Cross-framework exactMatchOf, replacedBy, isRelatedTo, isPeerOf, precedes, hasSkillLevel, exemplar, and isTranslationOf remain canonical CFAssociation edges.
Alternatives and tradeoffs
- Free-form associationType
- Closed enum only
- Known enum plus ext:* validation
Rationale and consequences
Known CASE values plus ext:* validation preserves 1EdTech extensibility while turning typos into deterministic validation errors.
#case_auth_shape
case auth shape
Unspecified
Decision
SHIP platform JWTs with tenantId, role or roles, and CASE scopes: case:read, case:write, case:import, and case:admin. DEFER school, class, and person-scoped claims unless a future CASE workflow introduces tenant-internal visibility boundaries.
Alternatives and tradeoffs
- Role-only JWT
- Role plus CASE scopes
- School/class/domain claims
Rationale and consequences
CASE graph data needs tenant and scope separation but does not need school, class, or person relationship claims.
#case_case11_extensions_markdown
case case11 extensions markdown
Unspecified
Decision
SHIP lossless storage and API pass-through for CASE 1.1 fields and extensions. Statement, notes, and description fields remain source text in API responses; customer docs tell browser apps to render Markdown/LaTeX through a sanitizer. The implementation must not emit pre-rendered trusted HTML for these fields.
Alternatives and tradeoffs
- Strip extensions and Markdown
- Render source Markdown as trusted HTML in API responses
- Preserve source text and extensions; sanitize at render boundaries
Rationale and consequences
Lossless source-text storage preserves CASE 1.1 round trips while sanitizing at the browser boundary keeps rendered standards safe.
#case_concurrency_model
case concurrency model
Unspecified
Decision
SHIP ETag on mutable resource reads and require If-Match for PUT, PATCH, and DELETE of CFDocument, CFItem, CFAssociation, and Alignment. Missing validators return 428; stale validators return 412; package import conflicts return a typed 409 with conflicting identifiers.
Alternatives and tradeoffs
- No concurrency model
- Bulk-only package version
- Per-resource ETag and If-Match
Rationale and consequences
ETag and If-Match prevent silent overwrites of standards tree edits with standard HTTP semantics.
#case_conformance_evidence
case conformance evidence
Unspecified
Decision
SHIP local evidence: OpenAPI path tests, JSON schema validation, package import/export round trips, auth/error/idempotency/concurrency tests, live demo and reviewer smoke tests, surface QC, and an integration app. DEFER official 1EdTech certification claim until a certificate or TrustEd Apps Directory listing exists.
Alternatives and tradeoffs
- No conformance evidence
- Claim official certification from local tests
- Local evidence with explicit non-certification
Rationale and consequences
Local executable evidence gives integrators reproducible proof without falsely claiming external 1EdTech certification.
#case_data_model_primitives
case data model primitives
Unspecified
Decision
Persist CFDocument, CFItem, and CFAssociation as first-class CASE resources, persist imported CFDefinitions and CFRubrics as read-through support tables, and add Alignment as a separate platform resource for external-system ID to CFItem links.
Alternatives and tradeoffs
- CFDocument and CFItem only
- Store raw CFPackage JSON only
- Put external IDs into CFAssociation extensions
Rationale and consequences
First-class CASE tables give the visual browser relational integrity and graph queries while Alignment keeps external IDs outside canonical CASE data.
#case_error_envelope
case error envelope
Unspecified
Decision
SHIP typed RFC 7807 Problem Details with stable type URIs, code values prefixed case:, requestId, traceId, optional fieldErrors, and optional rowErrors for package import. Initial codes include case:validation_failed, case:not_found, case:forbidden, case:unsupported_query_parameter, case:association_cycle, case:missing_parent, case:idempotency_conflict, case:precondition_required, case:precondition_failed, and case:package_import_failed.
Alternatives and tradeoffs
- No envelope
- Plain RFC 7807 only
- Typed RFC 7807 with case:* codes
Rationale and consequences
Typed Problems with case:* codes let clients branch on stable machine fields and attach request evidence to support tickets.
#case_eventing_model
case eventing model
Unspecified
Decision
SHIP polling through list filters and updatedSince. DEFER webhooks and push streams until three integrator decisions in 90 days show that polling prevents a visual browser or standards-sync app from completing its documented job.
Alternatives and tradeoffs
- No change observation
- Poll with updated filters
- Webhooks now
Rationale and consequences
Pollable updated filters cover the first browser refresh job without adding webhook subscription and replay infrastructure.
#case_idempotency_model
case idempotency model
Unspecified
Decision
SHIP Idempotency-Key on retryable writes, persisted in platform.idempotency_key with method, route template, tenant, request hash, and response replay metadata. CFPackage imports also store a canonical package hash and import_batch_id for audit and duplicate-import detection.
Alternatives and tradeoffs
- No idempotency
- Natural unique constraints only
- Idempotency-Key plus package hash
Rationale and consequences
The platform retry ledger plus package hashes makes imports and edits safe across network retries and duplicate submissions.
#case_item_tree_invariant
case item tree invariant
Unspecified
Decision
SHIP exactly one active isChildOf placement per CFItem within a tenant: the destination is either the owning CFDocument root or another CFItem in the same CFDocument. Additional cross-framework relationships use other CFAssociation types.
Alternatives and tradeoffs
- Allow no parent
- Allow multiple tree parents
- Exactly one isChildOf parent plus other association edges
Rationale and consequences
Exactly one structural isChildOf parent gives visual browsers a deterministic tree while other associations remain graph edges.
#case_list_endpoints
case list endpoints
Unspecified
Decision
SHIP list endpoints for CFDocuments, CFItems, CFAssociations, and Alignments. Definition support resources imported from CFDefinitions and CFRubrics remain official detail reads unless a future app needs definition browsing.
Alternatives and tradeoffs
- Write-and-remember
- Only official CFDocuments list
- One list per browser-owned collection
Rationale and consequences
Cold browser apps need discoverable CFItem, CFAssociation, and Alignment collections instead of remembered identifiers only.
#case_model_scope_definitions_rubrics
case model scope definitions rubrics
Unspecified
Decision
SHIP package import persistence and official detail reads for CFConcept, CFSubject, CFLicense, CFItemType, CFAssociationGrouping, and CFRubric. DEFER first-class list/create/update/delete authoring for those support resources until a standards-authoring or rubric-browser integration decision cites it as job-blocking.
Alternatives and tradeoffs
- Ignore definitions and rubrics
- Full CRUD for every definition and rubric class
- Persist and read through definitions/rubrics from packages
Rationale and consequences
Read-through support preserves official CASE lookup routes and package round trips without expanding first-release authoring scope.
#case_package_import_export
case package import export
Unspecified
Decision
SHIP POST /CFPackages for transactional import and GET /CFPackages/{sourcedId} for spec-pure export. Import persists CFDocument, CFItems, CFAssociations, CFDefinitions, and CFRubrics with _platform.tenant_id and _platform.import_batch_id sidecar metadata. Export omits platform metadata and Alignment rows.
Alternatives and tradeoffs
- No package import/export
- Export platform metadata inside CFPackage extensions
- Spec-pure package with sidecar audit provenance
Rationale and consequences
CFPackage remains the clean interchange envelope while platform audit metadata stays in sidecar persistence fields.
#case_privacy_retention
case privacy retention
Unspecified
Decision
SHIP tenant-scoped rows with audit provenance, redaction from Problems/logs/evidence, soft-retire semantics for CFDocument/CFItem/CFAssociation deletes, hard delete only for Alignment when no audit retention rule requires a tombstone, and spec-pure CFPackage exports that omit platform metadata. DEFER age-based retention and public erasure APIs until platform policy names a required retention period.
Alternatives and tradeoffs
- No privacy or retention behavior
- Hard DELETE everything
- Tenant isolation, redaction, and soft-retire
Rationale and consequences
Tenant isolation, redaction, and soft retirement protect institutional standards data without inventing learner-data retention APIs.
#case_query_model
case query model
Unspecified
Decision
SHIP official CASE list parameters where the spec defines them, plus named filters on TimeBack list and sub-collection routes: CFDocumentURI, parentIdentifier, originIdentifier, destinationIdentifier, associationType, subject, educationLevel, updatedSince, limit, offset, sort, orderBy, and fields. DEFER replacing official offset paging with cursor paging until three integrator decisions in 90 days cite offset paging as job-blocking at framework scale.
Alternatives and tradeoffs
- No query model
- Arbitrary expression filters
- Official CASE params plus named filters
Rationale and consequences
Official CASE query parameters plus named browser filters give predictable discovery without an undocumented query language.
#case_read_shape
case read shape
Unspecified
Decision
SHIP list + detail + package + narrow sub-collection reads: document lists/details, item lists/details, association lists/details, CFPackage export, item association sets, item children, item parents, item related edges, and Alignment lookup.
Alternatives and tradeoffs
- List-only
- List plus detail only
- List plus detail plus narrow sub-collections
Rationale and consequences
List, detail, package, and narrow sub-collection reads let a frontend navigate large standards graphs without owning a local database.
#case_served_audiences
case served audiences
Unspecified
Decision
The served audience is a developer building a visual standards-browser app against this CASE 1EdTech surface alone. The browser must navigate CFDocument -> CFItem hierarchies, follow CFAssociation cross-framework relationships, and resolve external IDs through Alignment.
Alternatives and tradeoffs
- Standards publisher first
- One-time ETL pipeline
- Spec validator
Rationale and consequences
The visual standards-browser persona makes persona-blocking concrete and keeps publisher-only or validator-only features from expanding the first surface.
#case_source_contract
case source contract
Unspecified
Decision
Official CASE Provider reads are preserved under /ims/case/v1p1. TimeBack adds write, list, package import, and Alignment routes under the same base path only where the visual-browser job needs persistence or discovery, and every such route is labeled as a TimeBack extension in downstream docs.
Alternatives and tradeoffs
- Implement only official GET operations
- Replace CASE paths with TimeBack CRUD paths
- Use official reads plus labeled TimeBack write and browse extensions
Rationale and consequences
Preserving official CASE reads while labeling TimeBack extensions keeps the surface recognizable and prevents accidental certification overclaims.
#case_tenant_routing
case tenant routing
Unspecified
Decision
SHIP tenant routing by signed JWT tenantId on flat /ims/case/v1p1 paths. /dev/mint?tenantId=demo may mint demo tokens only for the demo tenant. No X-Timeback-Tenant header or /tenants/{tenantId} prefix is part of the CASE surface.
Alternatives and tradeoffs
- Tenant in URL
- Tenant in header
- Tenant in JWT only
Rationale and consequences
JWT tenant routing preserves the official /ims/case/v1p1 path shape while enforcing platform tenant isolation.
#case_write_granularity
case write granularity
Unspecified
Decision
SHIP both CFPackage bulk import/export and per-resource POST, PUT, PATCH, and DELETE for CFDocument, CFItem, CFAssociation, and Alignment.
Alternatives and tradeoffs
- Bulk-only CFPackage import
- Per-resource writes only
- Both bulk import and per-resource writes
Rationale and consequences
Bulk package import and per-resource CRUD solve different jobs: initial framework ingestion and ongoing browser/editor maintenance.