Source-bound decision record
20 committed decisions · ed_fi/1edtech
#overview
edfi served audiences
activeOwner: platform3-loopDate: 2026-06-04
Decision
district and SIS integrators building attendance, discipline, transcript, program, demographic, staff, calendar, and related administrative workflows against the complete Ed-Fi UDM on the TimeBack 1EdTech surface
Alternatives and tradeoffs
- teacher or parent plain-language report builder
- Alpha attendance/program/transcript report generator
- standalone Ed-Fi ODS operator
- one-time CSV-only migration script
Rationale and consequences
the Ed-Fi 1EdTech surface is the standards-shaped administrative-record base that later Alpha views and skill packs build on
#eitd-000-source-contract
edfi source contract
activeOwner: platform3-loopDate: 2026-06-04
Decision
Use Ed-Fi Data Standard for Suite 3 v6.1.0 as the source contract. The generated data dictionary passes through Ed-Fi UDM entities, references, descriptors, field meanings, and domain guidance by linking to Ed-Fi's Data Handbook, v6 model reference, UML diagrams, default descriptors, and API guidelines. Platform3 documents only the behavior Ed-Fi does not decide for this hosted multi-tenant platform.
Alternatives and tradeoffs
- Copy every Ed-Fi field definition into platform3 docs
- Use only sample API payloads or prior ODS tables
Rationale and consequences
The simplest durable architecture is to let Ed-Fi own Ed-Fi semantics and let platform3 own only the missing platform behavior: identity boundary, local IDs, deletion retention, descriptors, draft state, and HTTP/API contracts.
#eitd-001-complete-model-scope
edfi complete model scope
activeOwner: platform3-loopDate: 2026-06-04
Decision
Implement the complete Ed-Fi UDM model on the 1EdTech surface: every domain, entity, association, reference, and descriptor published for Data Standard v6.1. No admission list and no Alpha-demand filter ship here. Unused Ed-Fi tables remain available and harmless. Cutting unused fields, renaming CEDS/Ed-Fi terms, and adding Alpha-only status fields happens only in the later Alpha surface.
Alternatives and tradeoffs
- Implement only the domains Alpha already needs
- Implement only high-volume SIS domains
Rationale and consequences
Complete base coverage is simpler than a defended subset because it makes the 1EdTech surface a stable source and pushes audience-specific cuts to the surface designed to make them.
#eitd-002-gap-a1-roster-reference-boundary
edfi roster reference boundary
activeOwner: platform3-loopDate: 2026-06-04
Decision
Every Ed-Fi-module row that touches a roster person, organization, class, course, section, or enrollment anchor must reference platform3 OneRoster sourcedIds through foreign keys. The Ed-Fi module may store Ed-Fi administrative attributes and Ed-Fi external identification codes, but it may not mint a local roster fact. A write that references an unknown OneRoster identity fails with a typed edfi:platform3_roster_required Problem.
Alternatives and tradeoffs
- Let Ed-Fi create its own student, staff, school, and section records
- Copy OneRoster identity fields into Ed-Fi tables
Rationale and consequences
A foreign-key boundary is simpler than reconciliation logic. It turns identity alignment into a write-time invariant instead of a recurring report-cleanup problem.
#eitd-003-gap-a2-platform-minted-local-id
edfi platform minted local id
activeOwner: platform3-loopDate: 2026-06-04
Decision
Every Ed-Fi persisted row receives a platform-minted local identifier, edfi_local_id, that is never a OneRoster sourcedId and never an Ed-Fi natural key. OneRoster sourcedIds remain explicit FK fields. Ed-Fi natural keys and external identification codes remain pass-through Ed-Fi fields. The API exposes all three only where the caller needs them and labels them by provenance.
Alternatives and tradeoffs
- Use the OneRoster sourcedId as the Ed-Fi row id
- Use Ed-Fi natural keys as local row ids
Rationale and consequences
A separate local id is the smallest way to keep platform identity, roster identity, and Ed-Fi source identity distinct without teaching consumers precedence rules.
#eitd-004-gap-a3-soft-delete
edfi soft delete retention
activeOwner: platform3-loopDate: 2026-06-04
Decision
Ed-Fi deletes and corrections are represented as soft-deleted records with deletion metadata. Public deletes mark rows deleted, preserve original values, write audit entries, and keep rows available through includeDeleted=true or audit/detail routes authorized for compliance. No public operation hard-deletes Ed-Fi records.
Alternatives and tradeoffs
- Hard-delete rows on DELETE or missing import row
- Keep only audit text after deletion
Rationale and consequences
Soft deletion is the simplest correction model that satisfies audit needs and mirrors the NWEAMap retention rule already approved upstream.
#eitd-005-gap-a4-descriptors-as-governed-tags
edfi descriptors governed tags
activeOwner: platform3-loopDate: 2026-06-04
Decision
Every Ed-Fi descriptor is represented in the platform governed tag registry as a code-list definition with namespace, codeValue, shortDescription, description, effective dates, and standard_status. Descriptor use on Ed-Fi objects references the governed code entry. Ed-Fi standard descriptor values are seeded from Ed-Fi's default descriptor source; district-local values are accepted only through governed registry writes, never as free text metadata.
Alternatives and tradeoffs
- Store descriptor strings directly on each Ed-Fi row
- Create a bespoke descriptor table family separate from tags
Rationale and consequences
Descriptors are governed code lists. The governed tag registry already exists to hold open-but-controlled values, so using it prevents a second code-list subsystem.
#eitd-006-gap-a5-draft-precanonical-state
edfi draft precanonical state
activeOwner: platform3-loopDate: 2026-06-04
Decision
An Ed-Fi record entry can exist as a draft before it becomes canonical. Draft records never carry a platform3 acknowledgement id, never count as canonical, never appear in ordinary canonical list endpoints, and never satisfy downstream references. A record becomes canonical only after platform3 validation succeeds and the platform returns ack_id plus ETag.
Alternatives and tradeoffs
- No drafts; reject until every field validates
- Store invalid records in canonical tables with a status flag
Rationale and consequences
Separating draft from canonical state removes ambiguity at the read boundary while avoiding app-local patch tables for partially entered administrative records.
#eitd-101-axis-write-granularity
edfi api axis write granularity
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP both per-resource writes for UDM resources/descriptors/drafts and bulk import/export jobs for Ed-Fi bulk/XML or equivalent complete-model exchange. The two paths share validation, idempotency, roster-reference checks, descriptor governance, soft-delete behavior, and canonical acknowledgement. For teacher attendance marking specifically, the canonical between-bells path is append-only POST to StudentSchoolAttendanceEvent or StudentSectionAttendanceEvent; detail PUT/PATCH/DELETE are correction paths after an acknowledged row exists.
Alternatives and tradeoffs
- bulk-only
- per-resource only
Rationale and consequences
This removes app-local staging and migration logic while avoiding two semantic persistence models: both write paths end in the same canonical records. Attendance marks are events, so treating normal teacher marks as append-only avoids forcing a classroom app through overwrite semantics during the narrow between-bells window.
#eitd-102-axis-read-shape
edfi api axis read shape
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP list plus detail plus narrow reference sub-collections. Every UDM collection and descriptor has list and detail reads. Narrow sub-collections are allowed only where the UDM reference already defines the parent-child relationship, such as a student's attendance events, a school's bell schedules, or a staff member's assignments. Unrestricted graph expansion is deferred.
Alternatives and tradeoffs
- list-only
- list plus detail only
Rationale and consequences
UDM-bounded sub-collections remove repeated client-side joins without inventing arbitrary projections.
#eitd-103-axis-query-model
edfi api axis query model
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP documented filters, stable sort keys, Ed-Fi offset+limit paging, platform opaque cursor paging, and modifiedSince for canonical collections and append-like operational collections. Offset mode accepts limit plus a non-negative offset and returns page.offset, page.nextOffset when another offset page exists, links.next, totalCount, page.totalCount, and the HTTP Total-Count header. Cursor mode accepts limit plus cursor and returns page.nextCursor when another cursor page exists. A request that mixes cursor with offset is invalid and returns edfi:invalid_query_parameter; unsupported query parameters are also typed 400 Problems rather than being ignored.
Alternatives and tradeoffs
- none
- filter and sort only
- opaque cursor as the only paging mode
Rationale and consequences
Two named paging modes are simpler than pretending Ed-Fi offset does not exist or forcing every high-volume client through offset. The contract is explicit: offset+limit for Ed-Fi compatibility, cursor for platform-owned high-volume replay, and mixed cursor+offset rejected at the boundary.
#eitd-104-axis-concurrency-model
edfi api axis concurrency model
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP per-resource optimistic concurrency. Canonical detail reads return ETag. PUT, PATCH, DELETE, draft promotion, and descriptor updates that can overwrite customer-visible work require If-Match. Missing required validators return 428; stale validators return 412 or the documented conflict Problem. Bulk jobs use job idempotency and per-row conflict reporting instead of row-level If-Match headers. The attendance teacher-mark contract publishes a stable client cap of 8 concurrent POSTs for a 32-student daily plus section roster batch and confirms each row with ack_id plus ETag. Deployed Postgres/Vercel storage must preserve serverless-safe pool sizing, keep Supabase transaction-pooler URLs in transaction mode instead of rewriting them to session mode, and serialize schema startup so the published cap is production-verifiable.
Alternatives and tradeoffs
- none
- bulk-only concurrency
Rationale and consequences
ETag plus If-Match is the smallest interoperable protection against lost updates and does not duplicate idempotency. Publishing the attendance cap removes guesswork for SIS clients while keeping the server-owned acknowledgement and idempotency semantics as the source of truth. The transaction-pooler, pool-size, and migration startup guardrails make that cap an operational contract rather than a local-only benchmark.
#eitd-105-axis-idempotency-model
edfi api axis idempotency model
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP Idempotency-Key on retryable writes, persisted through platform.idempotency_key with tenant, module, surface, method, route template, operation id, request hash, response replay metadata, and canonical record pointers. Bulk imports also compute a package/source hash for import evidence, but that hash does not replace Idempotency-Key on command retry.
Alternatives and tradeoffs
- none
- natural unique constraints only
Rationale and consequences
One retry ledger shared with platform prevents every Ed-Fi handler from inventing duplicate detection.
#eitd-106-axis-auth-shape
edfi api axis auth shape
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP platform HS256 Bearer JWTs with tenant_id or tenantId, roles, scopes, and OneRoster relationship-scoped claims where visibility must narrow by student, staff, school, or class. The Ed-Fi module does not mint independent Ed-Fi identities. Public demo minting is restricted to tenantId=demo; real-tenant tokens are operator-minted.
Alternatives and tradeoffs
- role-only JWT
- separate Ed-Fi auth system
Rationale and consequences
The platform token already carries tenant and operation authority; adding relationship-scoped visibility keeps authorization tied to the single roster source.
#eitd-107-axis-eventing-model
edfi api axis eventing model
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP poll plus modifiedSince for change discovery. Webhooks, event streams, and push subscriptions are deferred. modifiedSince applies to canonical collections, descriptors, drafts, import/export jobs, and audit-like operational collections where timestamp semantics are documented.
Alternatives and tradeoffs
Rationale and consequences
modifiedSince removes full-poll complexity while avoiding a duplicate delivery primitive.
#eitd-108-axis-error-envelope
edfi api axis error envelope
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP typed RFC 7807 Problem Details with stable type URIs, stable edfi:* codes, requestId, traceId, status, title, detail, and optional fieldErrors. Problem details must redact PII, secrets, source file bytes, headers, user agents, and raw request bodies.
Alternatives and tradeoffs
- no common envelope
- plain RFC 7807 with free-text type
Rationale and consequences
Typed Problems keep the standard shape and add the stable fields integrators and support need.
#eitd-109-axis-tenant-routing
edfi api axis tenant routing
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP tenant routing by the signed JWT tenant claim for ordinary Ed-Fi resource routes. The surface does not require /tenants/{id} prefixes or tenant headers on Ed-Fi-shaped collection paths. Public demo token minting accepts tenantId=demo only. Real tenant tokens are minted out of band by operators or the driver.
Alternatives and tradeoffs
- tenant in URL
- tenant in header
Rationale and consequences
JWT tenant routing gives one source of tenant truth on Ed-Fi resource routes while preserving the route shape integrators expect.
#eitd-110-axis-conformance-evidence
edfi api axis conformance evidence
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP local executable conformance evidence: UDM coverage manifest, generated dictionary coverage checks, descriptor governance checks, OneRoster FK checks, soft-delete checks, draft/canonical-state checks, HTTP contract tests, and live smoke probes. DEFER official Ed-Fi certification or compatibility claims until external evidence exists.
Alternatives and tradeoffs
- no conformance evidence
- claim official certification now
Rationale and consequences
Local evidence is the smallest honest trust mechanism; official labels require official proof.
#eitd-111-axis-privacy-retention
edfi api axis privacy retention
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP GDPR-style export, redaction, retention, erasure/tombstone handling, and privileged-read audit for Ed-Fi data. Ordinary deletes are soft deletes under EITD-004. Hard erasure is a controlled privacy operation that redacts or tombstones PII while preserving non-PII audit facts required for compliance.
Alternatives and tradeoffs
- no privacy behavior beyond auth
- DELETE per route only
Rationale and consequences
Privacy behavior must be an architecture contract because every downstream artifact will otherwise decide it differently.
#eitd-112-axis-list-endpoints
edfi api axis list endpoints
activeOwner: platform3-loopDate: 2026-06-04
Decision
SHIP one documented list endpoint per generated Ed-Fi UDM collection and descriptor catalog, plus list endpoints for drafts, imports, exports, and conformance/evidence where authorized. Every list endpoint inherits the EITD-103 query contract: limit, offset, cursor, modifiedSince, sort, documented filters, page.offset, page.nextOffset, page.nextCursor, links.next, totalCount, page.totalCount, HTTP Total-Count, and edfi:invalid_query_parameter for unsupported, malformed, or mixed cursor+offset requests. Write-and-remember-only resources are not allowed on this surface.
Alternatives and tradeoffs
- write-and-remember only
- lists for common domains only
Rationale and consequences
A complete model needs complete discoverability. One list per collection is easier for agents and humans than hidden support-only IDs.