Skip to content

Data models

The 25 SQLAlchemy models in backend/app/models/__init__.py, with their wire-shape Pydantic schemas. Sync surface includes 28 tables (the 25 models + 3 association tables: project_subjects, project_tags, user_badges).

The original 14 models from v0.7.0 are documented in detail below; the 11 added since (Phase 12+ imports, Phase 22 subjects/tags, Phase 29-30 gamification + anki, Phase 32 notebooklm) are listed at the bottom by name + table. See the OpenAPI spec at /api/openapi.json for every field of every model.

User

Field Type Notes
id string (UUID) Primary key
name string Required
email string | null Unique when set, optional
language string Default "de"
created_at datetime (ISO 8601) Auto-set
updated_at datetime (ISO 8601) Auto-updated

Relationships: projects, curriculums, profiles, settings (1:1).

UserSettings

Field Type Notes
id string (UUID) Primary key
user_id string (UUID) FK → User, unique
language string Default "de"
active_provider enum AIProvider anthropic / openai / gemini, default anthropic
api_key_anthropic string | null Fernet-encrypted; backend-only
api_key_openai string | null Fernet-encrypted; backend-only
api_key_gemini string | null Fernet-encrypted; backend-only
model_override_anthropic string | null Default null (use plugin default)
model_override_openai string | null Default null
model_override_gemini string | null Default null

The wire schema (UserSettingsOut) replaces the three api_key_* fields with has_<provider>_key: bool booleans — cleartext never travels back to the client. Since v1.20.0 / Phase 34, the wire schema also carries key_source_<provider>: ApiKeySource (enum: env | secrets_yaml | settings | none) reporting which layer the resolver picked.

LearningProject

Field Type Notes
id string (UUID) Primary key
user_id string (UUID) FK → User
topic string Max 500 chars
goal string Text, unlimited
timeframe string Max 100 chars
daily_minutes integer Required
current_problem string | null Text, optional
active boolean Default true
created_at datetime
updated_at datetime

LearningProfile

Field Type Notes
id string (UUID) Primary key
user_id string (UUID) FK → User
project_id string (UUID) FK → LearningProject
deductive float 0.0-1.0
inductive float 0.0-1.0
error_based float 0.0-1.0
dialogic float 0.0-1.0
contextual float 0.0-1.0
ai_adaptive float 0.0-1.0
assessed_at datetime
version integer Bumps on re-evaluate

Wire schema adds dominant_method (computed property, argmax over the 6 weights, alphabetical tie-break).

LearningSession

Field Type Notes
id string (UUID) Primary key
project_id string (UUID) FK → LearningProject
method enum LearningMethod One of the six
started_at datetime Auto-set on create
ended_at datetime | null Set on /end
cycle_step integer 1-7, default 1
status enum SessionStatus active / completed / abandoned

SessionMessage

Field Type Notes
id string (UUID) Primary key
session_id string (UUID) FK → LearningSession
role enum MessageRole user / assistant / system
content string Text, unlimited
created_at datetime

SessionRating

Field Type Notes
id string (UUID) Primary key
session_id string (UUID) FK → LearningSession
understanding integer 1-5
stress integer 1-5
method_fit integer 1-5
notes string | null Optional
created_at datetime

SessionNote

Field Type Notes
id string (UUID) Primary key
session_id string (UUID) FK → LearningSession
content string Required
created_at datetime

Currently unused by the v0.7.0 UI; reserved for an inline notepad feature in a future phase.

ProgressCommit

Field Type Notes
id string (UUID) Primary key
project_id string (UUID) FK → LearningProject
session_id string (UUID) FK → LearningSession
method enum LearningMethod
understanding float 0.0-1.0 (rescaled from 1-5)
stress float 0.0-1.0
error_rate float 0.0-1.0, currently always 0.0
duration_minutes integer Computed from ended_at - started_at
committed_at datetime

Written by the tracking plugin's on_session_complete hookimpl when a session is ended with a rating.

StepEvaluation

Field Type Notes
id string (UUID) Primary key
session_id string (UUID) FK → LearningSession
from_step integer Cycle step BEFORE evaluation
to_step integer Cycle step AFTER (= from_step if not applied)
advance boolean The AI said advance?
confidence float 0.0-1.0
applied boolean Was the suggestion actually applied?
fallback_used boolean True iff JSON parse failed
reason string AI's human-readable explanation
evaluated_at datetime

MethodSwitch

Field Type Notes
id string (UUID) Primary key
project_id string (UUID) FK → LearningProject
from_method enum LearningMethod
to_method enum LearningMethod
reason string Why the user accepted the switch
switched_at datetime

Curriculum, LearningTopic, Lesson

Curriculum Type Notes
id UUID
user_id UUID FK
title, description, language string, string|null, string
LearningTopic Type Notes
id UUID
curriculum_id UUID FK
parent_id UUID | null Self-FK for tree
title, description, order_index
Lesson Type Notes
id UUID
curriculum_id UUID FK
title, content, order_index

Enums

class LearningMethod(str, Enum):
    DEDUCTIVE = "deductive"
    INDUCTIVE = "inductive"
    ERROR_BASED = "error_based"
    DIALOGIC = "dialogic"
    CONTEXTUAL = "contextual"
    AI_ADAPTIVE = "ai_adaptive"

class SessionStatus(str, Enum):
    ACTIVE = "active"
    COMPLETED = "completed"
    ABANDONED = "abandoned"

class MessageRole(str, Enum):
    USER = "user"
    ASSISTANT = "assistant"
    SYSTEM = "system"

class AIProvider(str, Enum):
    ANTHROPIC = "anthropic"
    OPENAI = "openai"
    GEMINI = "gemini"

# Since v1.20.0 / Phase 34
class ApiKeySource(str, Enum):
    ENV = "env"
    SECRETS_YAML = "secrets_yaml"
    SETTINGS = "settings"
    NONE = "none"

# Since v0.9.0 / Phase 12
class ImportedConversationSource(str, Enum):
    CHATGPT = "chatgpt"
    CLAUDE = "claude"
    GEMINI = "gemini"
    MANUAL = "manual"
    UNKNOWN = "unknown"

The wire form is the lowercase string value (e.g. "deductive", not "DEDUCTIVE").

Models added since the v0.7.0 baseline (11)

Model Table Since Purpose
ImportedConversation imported_conversations v0.9.0 One imported chat (source, title, analysis_result JSON)
ImportedMessage imported_messages v0.9.0 One turn in an imported chat
Subject subjects v1.9.0 Global hierarchical taxonomy node
Tag tags v1.9.0 Per-user free-text label
ProjectSubject project_subjects v1.9.0 M:N (LearningProject, Subject)
ProjectTag project_tags v1.9.0 M:N (LearningProject, Tag)
UserXP user_xp v1.16.0 XP + level singleton per user
Badge badges v1.16.0 Badge catalog (seeded from YAML)
UserBadge user_badges v1.16.0 Earned-badge record (append-only)
UserStreak user_streaks v1.16.0 Streak state + freezes + weekend mode
AnkiCardSuggestion anki_card_suggestions v1.17.0 AI-extracted flashcard candidate
StudyQuestion study_questions v1.19.0 AI-generated active-recall question