Add specifications for gamification, generation, and R42 chat services

- Introduced gamification service spec detailing responsibilities, API surface, XP calculation, levels, streaks, badges, milestone cards, and heatmap data.
- Added generation service spec outlining the process for generating micro learning content, including API endpoints, AI call configuration, prompt strategies, and error handling.
- Created R42 chat service spec covering chatbot interactions, retrieval pipeline, prompt construction, response generation, and stateless design principles.
This commit is contained in:
RaymondVerhoef
2026-05-23 18:13:08 +02:00
parent dda20612e9
commit 472685f0d7
62 changed files with 11552 additions and 21 deletions

407
docs/curriculum-spec.md Normal file
View File

@@ -0,0 +1,407 @@
# Curriculum service spec
## Responsibility
Generates a versioned 26-week learning schedule from the published knowledge
base. Manages perpetual cycling, version transitions, and employee curriculum
state. Handles regeneration when the KB changes.
---
## Service location
```
app/services/curriculum/
├── src/
│ ├── index.ts entry point, Fastify server
│ ├── routes/
│ │ ├── curriculum.ts POST /generate, GET /current, GET /preview
│ │ └── employee.ts GET /state/:userId, POST /advance/:userId
│ ├── generator/
│ │ ├── build.ts KB graph → 26-week schedule (AI call)
│ │ ├── sequence.ts prerequisite + complexity ordering
│ │ └── cycle.ts cycle 2+ variation logic
│ ├── versioning/
│ │ ├── apply.ts apply new version to active employees
│ │ └── freeze.ts protect completed weeks
│ └── lib/
│ ├── pocketbase.ts
│ └── anthropic.ts
├── package.json
├── tsconfig.json
└── .env.example
```
---
## API surface
### POST /generate
Triggers curriculum generation from current published KB.
Called by admin app after confirming regeneration.
Request:
```json
{
"triggeredBy": "string",
"reason": "new_topics" | "manual"
}
```
Response (202 Accepted):
```json
{
"jobId": "string",
"status": "queued"
}
```
---
### GET /preview
Returns proposed new curriculum before admin confirms.
Called by admin app to show preview before regeneration is applied.
Response:
```json
{
"version": 3,
"weeks": [
{
"weekNumber": 1,
"theme": { "id": "string", "title": "string" },
"topics": [
{ "id": "string", "title": "string", "complexityWeight": 2 }
],
"estimatedDurationMinutes": 25
}
],
"coverageStats": {
"themesTotal": 8,
"themesCovered": 8,
"topicsTotal": 42,
"topicsCovered": 42
}
}
```
---
### GET /current
Returns the currently active curriculum version with all week slots.
---
### GET /state/:userId
Returns an employee's current curriculum state.
Response:
```json
{
"userId": "string",
"currentCycle": 1,
"currentWeek": 7,
"startDate": "2026-01-15T00:00:00Z",
"activeVersionId": "string",
"nextSessionTheme": { "id": "string", "title": "string" },
"nextSessionTopics": []
}
```
---
### POST /advance/:userId
Called by progress service when an employee completes a week.
Increments currentWeek, handles cycle transition at week 26.
Request:
```json
{
"completedWeek": 7
}
```
---
## Curriculum generation
### Input
All published Themes and Topics retrieved from PocketBase:
```typescript
type KBSnapshot = {
themes: {
id: string
title: string
description: string
topics: {
id: string
title: string
complexityWeight: number // 15
difficulty: string
prerequisiteTopics: string[] // topic IDs
relatedTopics: string[]
contrastTopics: string[]
}[]
}[]
}
```
---
### Pre-processing: sequence topics within themes
Before the AI call, the service resolves topic ordering within each Theme
using a topological sort on prerequisite relationships.
```
For each Theme:
Build directed graph: prerequisite_topics edges
Topological sort → ordered topic list
If cycle detected (should not occur but handle): log warning, fall back to
complexity_weight ascending order
```
This pre-processing means the AI does not need to reason about prerequisites —
it receives already-ordered topic lists and focuses on Theme sequencing.
---
### AI call: Theme sequencing across 26 weeks
System prompt:
```
You are a curriculum designer. Your task is to distribute a set of learning
Themes across 26 weekly sessions to create an effective learning journey.
Output ONLY valid JSON matching the schema provided. No preamble, no
explanation, no markdown fences.
Rules:
- Every Theme must appear at least once across 26 weeks
- Themes with more Topics (higher topic count) may span multiple weeks or
appear in multiple cycles within the 26 weeks
- Sequence Themes so foundational concepts precede dependent ones
- Distribute complexity progressively: introductory Themes early, advanced
Themes in the second half
- If total Topics across all Themes exceeds what 26 weeks can cover in depth,
prioritise breadth in cycle 1 — every Theme covered, key Topics per Theme
- Assign an estimated duration in minutes per week (1545 minutes per session)
- Return exactly 26 week slots
```
User prompt:
```
Knowledge base snapshot:
{KBSnapshot as JSON}
Generate a 26-week curriculum schedule.
```
Output schema:
```typescript
type CurriculumDraft = {
weeks: {
weekNumber: number // 126
themeId: string
topicIds: string[] // ordered subset of theme's topics
estimatedDurationMinutes: number
rationale: string // one sentence — shown to admin in preview
}[]
}
```
AI call configuration:
```typescript
{
model: 'claude-sonnet-4-20250514',
max_tokens: 4000,
temperature: 0
}
```
Validation: Zod schema on output. Check all themeIds and topicIds exist in
the KB snapshot before writing. Reject and retry once on validation failure.
---
### Write to PocketBase
```
Create curriculum_versions record {
version: latest + 1,
status: 'draft',
generated_at: now,
generation_notes: reason
}
For each week in CurriculumDraft:
Create curriculum_weeks record {
curriculum_version: versionId,
week_number: weekNumber,
theme: themeId,
topics: topicIds,
topic_order: [0, 1, 2, ...],
estimated_duration_minutes: value,
admin_notes: ''
}
Set curriculum_versions.status → 'draft'
Notify admin: preview available at GET /preview
```
Draft version is not applied until admin confirms via POST /generate confirm.
---
## Versioning and regeneration
### Applying a new version
When admin confirms, `apply.ts` runs:
```
Get all employees from employee_curriculum_state
For each employee:
frozenWeek = employee.current_week
Update employee_curriculum_state:
active_version = new version ID
Note: completed weeks are protected by current_week value
The frontend only renders weeks >= current_week from active_version
Weeks < current_week are rendered from session_completions history
(immutable records — not from curriculum_weeks)
Set old curriculum_versions.status → 'superseded'
Set new curriculum_versions.status → 'active'
```
Completed weeks are never stored against a curriculum version — they live
in session_completions. The version only determines future week content.
---
## Perpetual cycling
### Week 26 completion → cycle transition
When progress service calls POST /advance/:userId with completedWeek: 26:
```
employee.currentCycle += 1
employee.currentWeek = 1
employee.startDate = now
employee.activeVersion = current active version
Generate cycle variant (see below)
```
### Cycle variant generation
Cycle 2+ is not identical to cycle 1. The AI call receives additional context:
Additional fields in user prompt for cycle 2+:
```json
{
"cycleNumber": 2,
"employeeHistory": {
"typesUsed": ["concept_explainer", "scenario_quiz", "how_to"],
"typesNotUsed": ["case_study", "myth_vs_evidence", "comparison_card"],
"lowEngagementTopics": ["topic-id-1", "topic-id-2"]
}
}
```
Additional rules added to system prompt for cycle 2+:
```
- Vary the Theme sequence from the previous cycle
- Topics identified as low engagement should appear earlier in this cycle
- The rationale field should note what is different from cycle 1
```
Low engagement is determined by: topics where the employee completed only
one micro learning type (minimum engagement). Retrieved from session_completions
by progress service and passed to curriculum service on cycle transition.
---
## Admin curriculum editor
The curriculum editor in the admin app (built in frontend phase) calls:
- GET /preview to display the proposed schedule
- PATCH /weeks/:weekId to update theme or topic assignment
- POST /confirm to apply the version
The PATCH route allows admin to:
- Reassign a Theme to a different week (swap two weeks)
- Add or remove Topics from a week's topic list
- Edit admin_notes per week
Changes made via PATCH update the draft curriculum_weeks records before
the version is confirmed and applied.
---
## Environment variables
```
ANTHROPIC_API_KEY=
POCKETBASE_URL=
POCKETBASE_ADMIN_EMAIL=
POCKETBASE_ADMIN_PASSWORD=
CURRICULUM_PORT=3003
```
---
## Dependencies
```json
{
"dependencies": {
"fastify": "^4",
"@anthropic-ai/sdk": "^0.24",
"pocketbase": "^0.21",
"zod": "^3",
"uuid": "^9"
}
}
```
---
## TypeScript strict mode requirements
- No `any` types
- KBSnapshot typed explicitly — validated against PocketBase response
- CurriculumDraft validated through Zod before any PocketBase writes
- Topological sort implemented with explicit typed graph structure
---
## What this service does NOT do
- Does not generate micro learnings → generation service
- Does not record completions → progress service
- Does not serve KB content → frontend reads PocketBase directly
- Does not handle auth → PocketBase + frontend
---
## Testing checkpoints
1. Generate curriculum from a KB with 5+ themes → confirm 26 weeks produced
2. Confirm all themes appear at least once
3. Confirm topic order within a week respects prerequisites
4. Add a new theme to KB → trigger regeneration → confirm employee at week 5
sees weeks 15 unchanged, weeks 626 updated
5. Advance employee through week 26 → confirm cycle 2 starts with varied sequence
6. Admin edits week 3 theme → confirm patch updates draft before confirmation