AI-assisted course schema design
Status: architectural decisions closed. This document covers the AI-assisted course creation flow: how the admin builds a schema before anything exists in the database, and why each piece is where it is.
It complements
v2-dynamic-courses.md(which covers the full design-time/runtime cycle) andcontent-generation.md(v1 pipeline). Where this document contradicts the other, the most recent one wins for the design phase; runtime is not touched here.
Depends on: v2-dynamic-courses.md, architecture.md, llm-integration.md.
1. Stateless AI endpoints for design
The design phase uses stateless AI endpoints. The frontend is the workspace: all
state lives in React (useState) until the admin confirms. The backend endpoints
receive the full context and return results without persisting anything.
1.1 Current surface
| Endpoint | Input | Output |
|---|---|---|
POST /ai/schema-propose |
{ title, description, intent_density } |
{ nodes } |
1.2 Planned surface (backlog)
| Endpoint | Purpose |
|---|---|
POST /ai/schema-refine |
Refine an existing schema from admin feedback |
POST /ai/node-suggest |
Suggest a new node given the current schema |
POST /ai/autocomplete |
Complete a node’s fields (summary, outcome) |
1.3 Pattern
Each endpoint is independent and testable in isolation. There are no shared sessions nor server-side state between calls. Context is sent on every request: a schema is 5-15 nodes, a few KB, a trivial payload.
1.4 Why stateless
| Discarded alternative | Problem |
|---|---|
| Server-side workspace session | Orphaned courses from abandoned sessions; needs cleanup |
| Redis for intermediate state | New infrastructure for data that fits in the body |
| “Draft” entity in the DB | Garbage of unfinished drafts; the course list gets polluted |
Advantages of the chosen approach:
- No orphaned data. An abandoned design session leaves no trace on the server.
- Resilient. A browser reload loses only the local draft, not a server session. The admin can copy their draft before closing if they want (it’s plain JSON in React state).
- Extensible. Every new AI feature is a new endpoint, with no coupling to a
“workspace” entity. Adding
POST /ai/schema-refinedoes not touch any existing endpoint. - No extra infrastructure. No need for Redis, session tables, or a cleanup cron job.
2. The course is created only on confirmation
The course is not created in the database when the admin starts designing. It is created only when the admin accepts the schema and clicks “Create”. At that point:
POST /courses → creates the course (title, description, delivery_mode)
PUT /courses/{id}/schema → writes the schema nodes
POST /courses/{id}/schema/validate → blocking gate (if the admin validates on the spot)
2.1 Consequences
- The
coursestable only contains real courses, never drafts. - No jobs are needed to clean up abandoned drafts.
- The admin panel’s “Content” list reflects exactly what exists.
- The SPA flow is a clean transition: React state → POST → the entity exists.
2.2 Contrast with v1
In v1, the course is created first and content is generated afterward
(POST /courses/{id}/generate). The difference is that in v1 the admin cannot design
anything before creating: the course is an empty container until the pipeline
finishes. In the new flow, the entire creative phase happens before the course
exists.
3. Multi-model routing for design tasks
Different AI tasks in the design phase can use different models. The
resolve_llm_config(org_settings, purpose=...) infrastructure already supports
selection by purpose.
3.1 Current assignment
| Task | Model type | Typical latency | Purpose |
|---|---|---|---|
| Schema proposal | Fast (8B, GPT-4o-mini) | 2-5 s | "schema_design" |
| Per-node content generation (runtime) | Heavy | 1-3 s | "runtime_heavy" |
Schema proposal only generates structure: titles, summaries, prerequisites. It does not generate learning content. That makes it viable for fast, cheap models.
3.2 Planned assignment (backlog)
| Task | Model type | Purpose |
|---|---|---|
| Suggestions/autocomplete | Fast | "schema_assist" |
| Domain fine-tuned models | Specialized | "schema_design_ft" |
The router needs no changes: adding a new purpose is a matter of declaring it in the
organization’s configuration and passing it to resolve_llm_config.
4. Real-time interactive editor
The schema editor separates two types of operations by their latency:
4.1 Local operations (instant, no AI)
- Edit a node’s title or summary.
- Delete a node.
- Reorder nodes (drag & drop).
- Add a node manually.
- Change prerequisites.
These operations mutate React state directly. They do not trigger server calls.
4.2 AI operations (fast, 2-5 s)
- Initial proposal from a topic.
- Re-proposal when density changes (
intent_density). - New node suggestion (backlog).
- Field autocomplete (backlog).
UI pattern:
- The admin takes an action (click, slider).
- Subtle loading indicator (never a blocking modal, never a full-page spinner).
- The UI remains interactive — the admin can edit other nodes while the AI works.
- The result appears inline, like the runtime’s click-to-explain (Curio): click → fast call → the result appears in place.
5. Unified flow for document-based and topic-based courses
Both paths converge on the same schema proposal:
From document: From topic:
upload PDF title + description
→ parse to Markdown |
→ extract themes → extract themes
| |
└──────────────┬─────────────────────────┘
▼
propose schema (same call)
▼
schema editor (same UI)
5.1 Differences
| Aspect | From document | From topic |
|---|---|---|
| Input to the proposal | Themes extracted from the Markdown | Themes extracted from the title/description |
| Source document | Associated with the course for RAG at runtime | No document; content is generated without RAG |
| Proposal quality | More precise (concrete themes from the material) | More generic (depends on the description’s quality) |
5.2 Invariant
The schema proposal endpoint works from extracted themes, not from raw documents.
Theme extraction is a prior step (already implemented in build_schema_graph() as the
extract_themes_schema node). The original document, if it exists, is used later for
RAG when node content is generated at runtime.
6. Backlog: fine-tuning for large courses
For organizations with large document bases or specific domain needs. None of this is implemented or planned in the short term.
| Line | Description |
|---|---|
| Embedding fine-tuning | Improve RAG in specific domains (medicine, legal, engineering) |
| Design model fine-tuning | Learn from schemas admins accept vs. reject |
| Generation model fine-tuning | Learn from validated renders (OpenUI Lang) |
| Adaptive chunking | For very large documents (>100 pages), structure-based chunking strategy |
| Parallel node generation | For courses with 20+ nodes, generate content in parallel instead of sequentially |
Common prerequisite: sufficient data volume. An organization with 5 courses does not have enough data for fine-tuning. This becomes relevant once there are dozens of organizations with hundreds of validated courses.