# QTI Assessment App Deliverable Spec

Build a small customer-facing assessment app that proves the QTI 1EdTech surface can power authoring, delivery, results, privacy cleanup, and conformance evidence. The app may be a static frontend, a local web app, or a hosted preview, but all QTI domain data must flow through the QTI API.

## Inputs

- `QTI_BASE_URL`: `https://platform3-andymontgomery-9773s-projects.vercel.app/qti/1edtech/implementation/api`
- Demo flow: call `POST /dev/mint?tenantId=demo` and use the returned token, tenant id, candidate ref, and demo package URL.
- Real-tenant flow: read `QTI_REVIEWER_JWT`, `QTI_REVIEWER_TENANT_ID`, and `QTI_CANDIDATE_REF` from environment variables or a secret store.
- Proof flow: run `checks/qti-surface-check.sh` first and keep its redacted `check-summary.json` as app-build evidence.

## Required Screens

1. Credential setup
   - Shows current base URL and tenant id.
   - Lets the operator choose demo or real tenant.
   - Never displays a raw JWT.

2. Item bank ingest
   - Downloads the demo package URL or accepts operator-provided package bytes.
   - Calls `POST /tenants/{tenantId}/qti/packages` with `Idempotency-Key`, `Content-Type: application/zip`, and `X-QTI-Profile: qti-3.0`.
   - Stores returned `packageId`, `artifactId`, and `artifactVersionId` in app state.

3. Catalog lists
   - Calls `GET /tenants/{tenantId}/qti/packages`, `GET /tenants/{tenantId}/qti/artifacts`, and `GET /tenants/{tenantId}/qti/artifact-versions`.
   - Displays the API-returned `items` and `nextCursor` fields only.
   - Does not add local filters, joins, or search semantics.

4. Delivery preview
   - Calls `GET /tenants/{tenantId}/qti/artifact-versions/{artifactVersionId}/delivery-json`.
   - Renders only fields returned by the API.
   - Does not infer QTI scoring, response cardinality, or item rules locally.

5. Authoring read/write
   - Calls `GET /tenants/{tenantId}/qti/artifacts/{artifactId}/authoring-json`.
   - Captures the response `ETag`.
   - For a smoke run, writes the exact response body back through `PUT /tenants/{tenantId}/qti/artifacts/{artifactId}/authoring-json` with `If-Match`.

6. Delivery session and attempt
   - Calls `POST /tenants/{tenantId}/qti/delivery-sessions`.
   - Calls `POST /tenants/{tenantId}/qti/delivery-sessions/{deliverySessionId}/attempts`.
   - Displays `outcomeState.SCORE` and processing trace values returned by the API.

7. Runtime privacy cleanup
   - Calls `GET /tenants/{tenantId}/qti/candidates/{candidateRef}/runtime-data`.
   - Calls `DELETE /tenants/{tenantId}/qti/candidates/{candidateRef}/runtime-data`.
   - Shows the delete status and confirms no raw JWT or direct learner identity is shown.

8. Conformance evidence
   - Calls `POST /qti/conformance-runs`.
   - Displays returned `conformanceRunId`, `status`, and assertion summary.

## Required Evidence Panel

Show a compact evidence panel with:

- Canonical docs cited: customer website quickstart, API contracts, data dictionary.
- Proof-check summary from `checks/qti-surface-check.sh`.
- `requestId` values when present.
- `packageId`, `artifactId`, `artifactVersionId`, `deliverySessionId`, `attemptId`, and `conformanceRunId` when returned.
- Score, processing trace event, runtime counts, delete status, conformance status, and assertion counts.
- Token handling statement: `JWT redacted; token supplied by demo mint or operator secret.`

## Forbidden

- No QTI XML parser.
- No schema/scoring engine.
- No local response-processing rules.
- No idempotency replay ledger.
- No copied QTI enum, norm, or database schema table.
- No local search, filtering, joins, or paging behavior beyond the surface-published list endpoints.

If the app cannot meet the required screens without one of the forbidden items, report a surface leak instead of adding local logic.
