Conspectus resource

Specification status

Specification only. The Conspectus HTTP API is not implemented in the application code yet. This hub is the working product narrative: data shapes, intended paths, and idempotency ideas. After the API spec is finalized, implementation and OpenAPI will follow.

Single entry point for the ETR conspectus (study note): what the learner produces in the human workflow, how that maps to JSON fields, and how HTTP methods are expected to fit together. Human methodology (not normative for field shapes): Methodology.

Business context

A conspectus is a saved study note created after a learning session. Our methodology uses a 3-step process: Extract (pull cues from content), Transform (write a summary paragraph and bullet points). The API stores this package, along with scheduling info: slot (A–D ladder), next_review_at, and an optional title. Retrieval is planned via API endpoints for due and review; slot movement will live in a dedicated schedule policy module once implemented.

Each conspectus is owned by a User identified by the (system_user_id, system_uuid) pair (in requests or query params)—the same key as the User.

From study notes to API fields

The methodology uses a three-column cue sheet during Extract. The HTTP body splits that work into: (1) everything from the cue sheet → cue_sheet (JSON object); (2) Transform output → dense_paragraph and bullets; (3) optional heading for the whole note → title. Identity → system_user_id + system_uuid (see Data contract).

Recommended cue_sheet shape (explicit routing)

The API accepts any JSON object for cue_sheet. For clarity across clients and docs, this hub uses one documented convention: one array rows, each element is one horizontal row of the paper table; inside each element, three string fields match the three columns left to right.

Paper column (methodology) Position in row JSON path (under cue_sheet) Meaning
Column 1 — keywords / anchors left cell rows[n].keywords Short cue words (one to a few per methodology).
Column 2 — questions / gaps middle cell rows[n].question What to recall or explain; gaps to close.
Column 3 — hints / micro-answers right cell rows[n].hint Minimal hint only (not full notes).

Index n: the first data row on paper is n = 0 (first element of rows), the second row is n = 1, and so on. Order in the array is top-to-bottom as on the sheet.

Optional string cue_sheet.topic repeats the session theme inside the Extract payload; you can also set the API field title for the whole conspectus (list views, cards). They may match (as in the example below) or differ if your product needs it.

Real cue sheet → cue_sheet JSON (same content)

Below, the left column is what a learner might actually fill in on paper during Extract (one horizontal line = one idea). The right column is the same information as the cue_sheet object you send in the API — no extra fields, only structure. First line on paper = rows[0], next = rows[1], top to bottom. Use the property names keywords, question, hint (not ad-hoc kw / q abbreviations) so different clients agree on one shape.

On paper (three columns)

Topic on paper (optional): “Water cycle” — also fits cue_sheet.topic below
Keywords Questions Hints
evaporation What drives water into vapor? Sun heats surface
condensation Where do clouds form? Cooling air
precipitation Rain vs snow depends on? Temperature aloft

In JSON (cue_sheet only)

{
                    "topic": "Water cycle",
                    "rows": [
                    {
                    "keywords": "evaporation",
                    "question": "What drives water into vapor?",
                    "hint": "Sun heats surface"
                    },
                    {
                    "keywords": "condensation",
                    "question": "Where do clouds form?",
                    "hint": "Cooling air"
                    },
                    {
                    "keywords": "precipitation",
                    "question": "Rain vs snow depends on?",
                    "hint": "Temperature aloft"
                    }
                    ]
                    }
  • Row 1 of the table → rows[0] — left cell = rows[0].keywords, middle = rows[0].question, right = rows[0].hint.
  • Row 2rows[1], row 3rows[2] — same rule.
  • Optional session theme: either only cue_sheet.topic here, or repeat it in the request field title for lists (see worked example).

Transform layer (same POST body)

Learner artifact (methodology) API field (request body) Notes
One dense paragraph (sources closed) dense_paragraph (string) Single string; not split across cells.
Bullet list (Feynman-style) bullets (array of strings) Each array element is one bullet line; order = your UI order.
Optional title for the note title (string, optional) Separate from cue_sheet.topic; often the same phrase.

Data contract (summary)

Full schemas are in OpenAPI; this table is the shorthand for reviews and client onboarding.

Field What the learner meant API notes
system_user_id, system_uuid Which account this note belongs to (from your integration). Required on create / due / patch / review / errors; must match an existing user.
title Optional short label (chapter, topic). Omit or string; max length per OpenAPI.
cue_sheet The lean capture from Extract (e.g. rows with keyword / question / hint). Arbitrary JSON object (not an array at the top level). Must be valid JSON.
dense_paragraph Transform: one paragraph in their own words, sources closed. Required non-empty string.
bullets Transform: bullet list explaining the idea simply. Array of non-empty strings; typical length 5–7 in methodology docs.
slot, next_review_at, … Scheduling — usually not typed by the user on create. Set by server from SchedulePolicy; updated on review.

Worked example

Scenario: the learner studied the water cycle (evaporation, condensation, precipitation). They already have a user with the same (system_user_id, system_uuid) in our database. Below is a realistic POST /api/v1/conspectuses body: the cue_sheet object is the same as in the paper ↔ JSON example above (three rows); add dense_paragraph and bullets for the Transform layer.

{
                    "system_user_id": "learner-01",
                    "system_uuid": "b2c3d4e5-0002-4000-8000-000000000002",
                    "title": "The water cycle",
                    "cue_sheet": {
                    "topic": "Water cycle",
                    "rows": [
                    {
                    "keywords": "evaporation",
                    "question": "What drives water into vapor?",
                    "hint": "Sun heats surface"
                    },
                    {
                    "keywords": "condensation",
                    "question": "Where do clouds form?",
                    "hint": "Cooling air"
                    },
                    {
                    "keywords": "precipitation",
                    "question": "Rain vs snow depends on?",
                    "hint": "Temperature aloft"
                    }
                    ]
                    },
                    "dense_paragraph": "The sun heats oceans and lakes so water evaporates. Rising vapor cools and condenses into clouds. When droplets or ice grow heavy enough, water returns as rain or snow.",
                    "bullets": [
                    "Evaporation moves water from surface to atmosphere.",
                    "Condensation forms clouds when air cools.",
                    "Precipitation completes the loop back to Earth.",
                    "Energy from the sun drives the cycle.",
                    "The same water moves through states and locations over time."
                    ]
                    }

After 201 Created, the response includes conspectus_uuid, slot (starts at A), next_review_at, and timestamps. Use Idempotency-Key on this POST as for other critical writes.

Method pages (per endpoint)

Navigation matches HTTP method + path (how clients are expected to call the API). Planned operationId names appear in the table; OpenAPI will be generated when routes exist.

Use the sidebar under API → Conspectus, or open a row below. Schedule summary (FR-5) is documented here as a related read surface. The error log (/api/v1/errors, FR-4) has a dedicated Error log hub — separate internal nav, same product scope.

Method & path operationId Internal doc
POST /api/v1/conspectuses createConspectus Method page
GET /api/v1/conspectuses/due listDueConspectuses Method page
PATCH /api/v1/conspectuses/{conspectus_uuid} patchConspectus Method page
POST /api/v1/conspectuses/{conspectus_uuid}/actions/review reviewConspectus Method page
GET /api/v1/schedule/summary getScheduleSummary Method page

API surface

Planned conspectus routes share prefix /api/v1/conspectuses. Writes that change scheduling are expected to use POST …/actions/review (command-style). When implemented, routes should require X-API-Key and rate limiting per ADR 0005.

POST /api/v1/conspectuses

operationId
createConspectus
Idempotency
Required Idempotency-Key; path key /api/v1/conspectuses.
Success
201 Created — full conspectus including conspectus_uuid, slot, next_review_at.

GET /api/v1/conspectuses/due

operationId
listDueConspectuses
Idempotency
Not used (read).
Success
200 OK — JSON array of ConspectusResponse.

PATCH /api/v1/conspectuses/{conspectus_uuid}

operationId
patchConspectus
Idempotency
Required; scope PATCH /api/v1/conspectuses/{uuid} (per resource).
Success
200 OK — updated ETR fields; scheduling unchanged.

POST /api/v1/conspectuses/{conspectus_uuid}/actions/review

operationId
reviewConspectus
Idempotency
Required; path includes concrete conspectus_uuid (…/actions/review).
Success
200 OK — updated conspectus body.

GET /api/v1/schedule/summary

operationId
getScheduleSummary
Idempotency
Not used (read).
Success
200 OK — slot histogram + due_now_count (aggregates conspectus rows).

Request path and layers

Middleware in app/main.py (metrics, body limit, API key + rate limit, security headers, request ID) → route handler → service → repository → SQLite. Writes that use idempotency also touch idempotency_keys via IdempotencyRepository.

Technical overview

Current codebase: user identity and idempotency infrastructure only (app/api/v1/user.py, shared middleware in app/main.py, SQLite via SQLITE_DB_PATH). Conspectus, schedule, and error-log persistence are not present until the spec is implemented (new routers, services, repositories, ORM models, and Alembic migrations).

Ownership and change management

Who changes this feature: contributors following CONTRIBUTING.md — PRs on main, review, green CI.

  • Quality gate: make verify-ci (lint, types, OpenAPI, contract tests, tests, docs-check).
  • Contract: HTTP changes → code + make openapi-accept-changes (ADR 0007).
  • Internal narrative: update this hub and method pages when behavior or idempotency paths change (ADR 0026).

Page history

Date Change Author
Added Page history section (repository baseline). Ivan Boyarkin