domain capa

domain-curriculum

Generic 'party learns skills' curriculum engine: versioned curricula, skills, prerequisites (DAG), assignments, explicit progress, and event history

Generic 'party learns skills' curriculum engine: versioned curricula, skills, prerequisites (DAG), assignments, explicit progress, and event history

Tierdomain
Roleunclassified (baselined)
Pathcrates/domain/curriculum
Edition2021
Targetsdomain_curriculum, pg_repository, pg_service
Public items121 across 7 modules
Tests27

What it is for

domain-curriculum — a generic "party learns skills" engine.

Owns curriculum structure, immutable published versions, skills, prerequisites (a DAG), assignments (keyed by learner_party_id — Animal / Person / any Party), explicit skill progress, and an append-only event history. Deliberately generic: domain specifics (dog-training cues/objects, dive skills, onboarding steps) ride in skill_type + metadata/ mastery_policy jsonb + event metadata — never in this crate. Media, comments, encounters, reservations, notifications stay outside and attach by reference (see Sprint 0.67 plan).

This crate is tenant-agnostic inside a tenant DB (one DB per tenant via infrastructure-tenant-pool); no cross-tenant references.

Capabilities

CurriculumError

Curriculum error type.

Item
pub enum CurriculumError

AssignmentStatus

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub enum AssignmentStatus
AssignmentStatus :: fn as_str(self) -> & 'static str
AssignmentStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>

CurriculumAssignment

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct CurriculumAssignment
CurriculumAssignment :: fn new(curriculum_version_id : Uuid, learner_party_id : Uuid) -> Self
CurriculumAssignment :: fn id(& self) -> Uuid
CurriculumAssignment :: fn created_at(& self) -> DateTime <Utc>
CurriculumAssignment :: fn updated_at(& self) -> DateTime <Utc>

CurriculumEvent

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct CurriculumEvent
CurriculumEvent :: fn new(assignment_id : Uuid, event_type : impl Into <String>, source : EventSource) -> Self
CurriculumEvent :: fn for_skill(mut self, skill_id : Uuid) -> Self
CurriculumEvent :: fn id(& self) -> Uuid

CurriculumStatus

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub enum CurriculumStatus
CurriculumStatus :: fn as_str(self) -> & 'static str
CurriculumStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>

CurriculumTemplate

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct CurriculumTemplate
CurriculumTemplate :: fn new(code : impl Into <String>, title : impl Into <String>) -> Self
CurriculumTemplate :: fn id(& self) -> Uuid
CurriculumTemplate :: fn created_at(& self) -> DateTime <Utc>
CurriculumTemplate :: fn updated_at(& self) -> DateTime <Utc>
CurriculumTemplate :: fn deleted_at(& self) -> Option <DateTime <Utc>>

CurriculumVersion

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct CurriculumVersion
CurriculumVersion :: fn new(curriculum_id : Uuid, version_no : i32) -> Self
CurriculumVersion :: fn id(& self) -> Uuid
CurriculumVersion :: fn created_at(& self) -> DateTime <Utc>
CurriculumVersion :: fn updated_at(& self) -> DateTime <Utc>

CurriculumVersionSkill

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct CurriculumVersionSkill
CurriculumVersionSkill :: fn new(curriculum_version_id : Uuid, skill_id : Uuid, sort_order : i32) -> Self
CurriculumVersionSkill :: fn id(& self) -> Uuid
CurriculumVersionSkill :: fn created_at(& self) -> DateTime <Utc>
CurriculumVersionSkill :: fn updated_at(& self) -> DateTime <Utc>

EventSource

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub enum EventSource
EventSource :: fn as_str(self) -> & 'static str
EventSource :: fn from_str(s : & str) -> Result <Self, Self::Err>

ParseStatusError

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct ParseStatusError
ParseStatusError :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result

PrerequisiteKind

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub enum PrerequisiteKind
PrerequisiteKind :: fn is_blocking(self) -> bool
PrerequisiteKind :: fn as_str(self) -> & 'static str
PrerequisiteKind :: fn from_str(s : & str) -> Result <Self, Self::Err>

Skill

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct Skill
Skill :: fn new(code : impl Into <String>, title : impl Into <String>, skill_type : impl Into <String>,) -> Self
Skill :: fn id(& self) -> Uuid
Skill :: fn created_at(& self) -> DateTime <Utc>
Skill :: fn updated_at(& self) -> DateTime <Utc>
Skill :: fn deleted_at(& self) -> Option <DateTime <Utc>>

SkillPrerequisite

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct SkillPrerequisite
SkillPrerequisite :: fn new(curriculum_version_id : Uuid, skill_id : Uuid, prerequisite_skill_id : Uuid, kind : PrerequisiteKind,) -> Self

SkillProgress

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub struct SkillProgress
SkillProgress :: fn new(assignment_id : Uuid, skill_id : Uuid) -> Self
SkillProgress :: fn id(& self) -> Uuid
SkillProgress :: fn created_at(& self) -> DateTime <Utc>
SkillProgress :: fn updated_at(& self) -> DateTime <Utc>

SkillProgressStatus

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub enum SkillProgressStatus
SkillProgressStatus :: fn is_mastered(self) -> bool
SkillProgressStatus :: fn as_str(self) -> & 'static str
SkillProgressStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>

VersionStatus

Curriculum state vocabularies (controlled enums) and row structs.

Item
pub enum VersionStatus
VersionStatus :: fn is_editable(self) -> bool
VersionStatus :: fn label(self) -> & 'static str
VersionStatus :: fn as_str(self) -> & 'static str
VersionStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>

progression (other)

Pure progression logic: prerequisite-DAG validation + unlocked/next-step

Item
fn validate_no_cycles(edges : & (Uuid, Uuid)) -> Result <(), CurriculumError>
fn unlocked_skills(all_skills : & Uuid, hard_prereqs : & (Uuid, Uuid), mastered : & HashSet <Uuid>,) -> Vec <Uuid>
fn recommended_next(all_skills : & Uuid, hard_prereqs : & (Uuid, Uuid), mastered : & HashSet <Uuid>,) -> Vec <Uuid>

AssignedCurriculum

Read model for "the curriculum a learner is assigned, with progress".

Item
pub struct AssignedCurriculum
fn assemble_assigned_curriculum(assignment : CurriculumAssignment, version : CurriculumVersion, placements : Vec <CurriculumVersionSkill>, skills_by_id : & HashMap <Uuid, Skill>, progress_by_skill : & HashMap <Uuid, SkillProgress>, hard_prereqs : & (Uuid, Uuid),) -> AssignedCurriculum

SkillView

Read model for "the curriculum a learner is assigned, with progress".

Item
pub struct SkillView

CurriculumRepository:CurriculumRepository

Postgres persistence for the curriculum tables.

Item
pub struct CurriculumRepository

CurriculumRepository:add

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn add_version_skill(& self, cvs : & CurriculumVersionSkill) -> Result <()>
CurriculumRepository :: async fn add_prerequisite(& self, p : & SkillPrerequisite) -> Result <()>

CurriculumRepository:append

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn append_event(& self, e : & CurriculumEvent) -> Result <()>

CurriculumRepository:count

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn count_version_skills(& self, version_id : Uuid) -> Result <i64>

CurriculumRepository:create

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn create_template(& self, t : & CurriculumTemplate) -> Result <()>
CurriculumRepository :: async fn create_version(& self, v : & CurriculumVersion) -> Result <()>
CurriculumRepository :: async fn create_skill(& self, s : & Skill) -> Result <()>
CurriculumRepository :: async fn create_assignment(& self, a : & CurriculumAssignment) -> Result <()>

CurriculumRepository:get

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn get_template(& self, id : Uuid) -> Result <Option <CurriculumTemplate>>
CurriculumRepository :: async fn get_version(& self, id : Uuid) -> Result <Option <CurriculumVersion>>
CurriculumRepository :: async fn get_skill(& self, id : Uuid) -> Result <Option <Skill>>
CurriculumRepository :: async fn get_skill_by_code(& self, code : & str) -> Result <Option <Skill>>
CurriculumRepository :: async fn get_assignment(& self, id : Uuid) -> Result <Option <CurriculumAssignment>>
CurriculumRepository :: async fn get_skill_progress(& self, assignment_id : Uuid, skill_id : Uuid,) -> Result <Option <SkillProgress>>

CurriculumRepository:list

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn list_templates(& self) -> Result <Vec <CurriculumTemplate>>
CurriculumRepository :: async fn list_versions(& self, curriculum_id : Uuid) -> Result <Vec <CurriculumVersion>>
CurriculumRepository :: async fn list_version_skills(& self, version_id : Uuid,) -> Result <Vec <CurriculumVersionSkill>>
CurriculumRepository :: async fn list_prerequisites(& self, version_id : Uuid) -> Result <Vec <SkillPrerequisite>>
CurriculumRepository :: async fn list_assignments_for_learner(& self, learner_party_id : Uuid,) -> Result <Vec <CurriculumAssignment>>
CurriculumRepository :: async fn list_skill_progress(& self, assignment_id : Uuid) -> Result <Vec <SkillProgress>>
CurriculumRepository :: async fn list_events(& self, assignment_id : Uuid) -> Result <Vec <CurriculumEvent>>

CurriculumRepository:max

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn max_version_no(& self, curriculum_id : Uuid) -> Result <Option <i32>>

CurriculumRepository:new

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: fn new(pool : PgPool) -> Self

CurriculumRepository:pool

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: fn pool(& self) -> & PgPool

CurriculumRepository:remove

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn remove_version_skill(& self, version_id : Uuid, skill_id : Uuid) -> Result <()>
CurriculumRepository :: async fn remove_prerequisite(& self, version_id : Uuid, skill_id : Uuid, prerequisite_skill_id : Uuid,) -> Result <()>

CurriculumRepository:set

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn set_template_status(& self, id : Uuid, status : CurriculumStatus) -> Result <()>
CurriculumRepository :: async fn set_version_status(& self, id : Uuid, status : VersionStatus, published_at : Option <DateTime <Utc>>,) -> Result <()>
CurriculumRepository :: async fn set_version_skill_order(& self, version_id : Uuid, skill_id : Uuid, sort_order : i32,) -> Result <()>
CurriculumRepository :: async fn set_assignment_status(& self, id : Uuid, status : AssignmentStatus, completed_at : Option <DateTime <Utc>>,) -> Result <()>

CurriculumRepository:upsert

Postgres persistence for the curriculum tables.

Item
CurriculumRepository :: async fn upsert_skill_progress(& self, p : & SkillProgress) -> Result <()>

rules (other)

Pure service-layer rules: version numbering + publish/assign gates.

Item
fn next_version_no(current_max : Option <i32>) -> i32
fn can_publish_version(status : VersionStatus, skill_count : usize,) -> Result <(), CurriculumError>
fn can_assign_version(status : VersionStatus) -> Result <(), CurriculumError>

CurriculumService:CurriculumService

Curriculum service — the minimal API, orchestrating the pure rules

Item
pub struct CurriculumService

CurriculumService:add

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn add_skill(& self, version_id : Uuid, skill_id : Uuid, sort_order : i32,) -> Result <CurriculumVersionSkill>
CurriculumService :: async fn add_prerequisite(& self, version_id : Uuid, skill_id : Uuid, prerequisite_skill_id : Uuid, kind : PrerequisiteKind,) -> Result <SkillPrerequisite>

CurriculumService:append

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn append_event(& self, assignment_id : Uuid, skill_id : Option <Uuid>, event_type : impl Into <String>, source : EventSource, actor_party_id : Option <Uuid>,) -> Result <CurriculumEvent>

CurriculumService:archive

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn archive(& self, curriculum_id : Uuid) -> Result <()>

CurriculumService:assign

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn assign(& self, version_id : Uuid, learner_party_id : Uuid, assigned_by_party_id : Option <Uuid>,) -> Result <CurriculumAssignment>

CurriculumService:create

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn create_draft(& self, code : impl Into <String>, title : impl Into <String>,) -> Result <(CurriculumTemplate, CurriculumVersion)>
CurriculumService :: async fn create_draft_version(& self, curriculum_id : Uuid) -> Result <CurriculumVersion>
CurriculumService :: async fn create_skill(& self, code : impl Into <String>, title : impl Into <String>, skill_type : impl Into <String>,) -> Result <Skill>

CurriculumService:get

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn get_assigned_curriculum(& self, assignment_id : Uuid) -> Result <AssignedCurriculum>

CurriculumService:new

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: fn new(repo : CurriculumRepository) -> Self

CurriculumService:publish

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn publish_version(& self, version_id : Uuid) -> Result <CurriculumVersion>

CurriculumService:recommended

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn recommended_next_skills(& self, assignment_id : Uuid) -> Result <Vec <Uuid>>

CurriculumService:remove

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn remove_skill(& self, version_id : Uuid, skill_id : Uuid) -> Result <()>

CurriculumService:reorder

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn reorder_skills(& self, version_id : Uuid, ordered_skill_ids : & Uuid) -> Result <()>

CurriculumService:repo

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: fn repo(& self) -> & CurriculumRepository

CurriculumService:update

Curriculum service — the minimal API, orchestrating the pure rules

Item
CurriculumService :: async fn update_skill_progress(& self, assignment_id : Uuid, skill_id : Uuid, status : SkillProgressStatus, score : Option <i32>, manually_overridden : bool,) -> Result <SkillProgress>

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

domain_curriculum

flowchart TD
  n_domain_curriculum["domain_curriculum"]
  n_domain_curriculum --> n_error["error"]
  n_domain_curriculum --> n_models["models"]
  n_domain_curriculum --> n_progression["progression"]
  n_domain_curriculum --> n_read_model["read_model"]
  n_domain_curriculum --> n_repository["repository"]
  n_domain_curriculum --> n_rules["rules"]
  n_domain_curriculum --> n_service["service"]

Public surface

`error`

ItemWhat it is
pub enum CurriculumError

`models`

ItemWhat it is
pub struct ParseStatusErrorParse error for the controlled-vocabulary enums.
ParseStatusError :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
pub enum CurriculumStatusLifecycle of a curriculum template.
CurriculumStatus :: fn as_str(self) -> & 'static strsnake_case label (matches the serde representation and the SQL value).
CurriculumStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub enum VersionStatusLifecycle of a concrete curriculum version
VersionStatus :: fn is_editable(self) -> boolWhether this version may still be structurally edited.
VersionStatus :: fn label(self) -> & 'static strsnake_case label (matches the serde representation and the SQL value).
VersionStatus :: fn as_str(self) -> & 'static strsnake_case label (matches the serde representation and the SQL value).
VersionStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub enum AssignmentStatusLifecycle of a learner's assignment to a curriculum version.
AssignmentStatus :: fn as_str(self) -> & 'static strsnake_case label (matches the serde representation and the SQL value).
AssignmentStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub enum SkillProgressStatusExplicit, stored mastery state of one skill for one assignment (principle #4).
SkillProgressStatus :: fn is_mastered(self) -> bool
SkillProgressStatus :: fn as_str(self) -> & 'static strsnake_case label (matches the serde representation and the SQL value).
SkillProgressStatus :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub enum PrerequisiteKindStrength of a prerequisite edge (principle #5).
PrerequisiteKind :: fn is_blocking(self) -> boolOnly Hard prerequisites block unlocking (principle #5).
PrerequisiteKind :: fn as_str(self) -> & 'static strsnake_case label (matches the serde representation and the SQL value).
PrerequisiteKind :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub enum EventSourceWhere a curriculum event originated (principle #9).
EventSource :: fn as_str(self) -> & 'static strsnake_case label (matches the serde representation and the SQL value).
EventSource :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub struct CurriculumTemplateA curriculum template: the authoring root
CurriculumTemplate :: fn new(code : impl Into <String>, title : impl Into <String>) -> SelfA new draft template with the given code + title.
CurriculumTemplate :: fn id(& self) -> Uuid
CurriculumTemplate :: fn created_at(& self) -> DateTime <Utc>
CurriculumTemplate :: fn updated_at(& self) -> DateTime <Utc>
CurriculumTemplate :: fn deleted_at(& self) -> Option <DateTime <Utc>>
pub struct CurriculumVersionA concrete, numbered version of a curriculum
CurriculumVersion :: fn new(curriculum_id : Uuid, version_no : i32) -> SelfA new draft version version_no of curriculum_id.
CurriculumVersion :: fn id(& self) -> Uuid
CurriculumVersion :: fn created_at(& self) -> DateTime <Utc>
CurriculumVersion :: fn updated_at(& self) -> DateTime <Utc>
pub struct SkillA reusable skill
Skill :: fn new(code : impl Into <String>, title : impl Into <String>, skill_type : impl Into <String>,) -> SelfA new skill with the given code, title and domain skill_type.
Skill :: fn id(& self) -> Uuid
Skill :: fn created_at(& self) -> DateTime <Utc>
Skill :: fn updated_at(& self) -> DateTime <Utc>
Skill :: fn deleted_at(& self) -> Option <DateTime <Utc>>
pub struct CurriculumVersionSkillPlacement of a skill inside a curriculum version (principle #2).
CurriculumVersionSkill :: fn new(curriculum_version_id : Uuid, skill_id : Uuid, sort_order : i32) -> SelfPlace skill_id in curriculum_version_id at sort_order (required by default).
CurriculumVersionSkill :: fn id(& self) -> Uuid
CurriculumVersionSkill :: fn created_at(& self) -> DateTime <Utc>
CurriculumVersionSkill :: fn updated_at(& self) -> DateTime <Utc>
pub struct SkillPrerequisiteA prerequisite edge within a version: skill_id requires prerequisite_skill_id (principle #5)
SkillPrerequisite :: fn new(curriculum_version_id : Uuid, skill_id : Uuid, prerequisite_skill_id : Uuid, kind : PrerequisiteKind,) -> Self
pub struct CurriculumAssignmentA learner's assignment to a curriculum version, keyed by learner_party_id (any Party — Animal / Person), principle #3.
CurriculumAssignment :: fn new(curriculum_version_id : Uuid, learner_party_id : Uuid) -> SelfAssign learner_party_id to curriculum_version_id (active).
CurriculumAssignment :: fn id(& self) -> Uuid
CurriculumAssignment :: fn created_at(& self) -> DateTime <Utc>
CurriculumAssignment :: fn updated_at(& self) -> DateTime <Utc>
pub struct SkillProgressCurrent, explicit mastery state of one skill for one assignment (principle #4).
SkillProgress :: fn new(assignment_id : Uuid, skill_id : Uuid) -> SelfA fresh not_started progress row for skill_id under assignment_id.
SkillProgress :: fn id(& self) -> Uuid
SkillProgress :: fn created_at(& self) -> DateTime <Utc>
SkillProgress :: fn updated_at(& self) -> DateTime <Utc>
pub struct CurriculumEventAn append-only curriculum event — the audit trail behind SkillProgress (principle #9)
CurriculumEvent :: fn new(assignment_id : Uuid, event_type : impl Into <String>, source : EventSource) -> SelfA new event of event_type from source for assignment_id.
CurriculumEvent :: fn for_skill(mut self, skill_id : Uuid) -> SelfAttach the event to a specific skill.
CurriculumEvent :: fn id(& self) -> Uuid

`progression`

ItemWhat it is
fn validate_no_cycles(edges : & (Uuid, Uuid)) -> Result <(), CurriculumError>Validate that prerequisite edges form a DAG (no cycles, principle #5).
fn unlocked_skills(all_skills : & Uuid, hard_prereqs : & (Uuid, Uuid), mastered : & HashSet <Uuid>,) -> Vec <Uuid>Skills whose hard prerequisites are all in mastered (i.e
fn recommended_next(all_skills : & Uuid, hard_prereqs : & (Uuid, Uuid), mastered : & HashSet <Uuid>,) -> Vec <Uuid>Unlocked skills that are not yet mastered — the recommended next steps.

`read_model`

ItemWhat it is
pub struct SkillViewOne skill within an assigned curriculum: its definition, its placement in the version, the learner's explicit progress, and whether its hard prerequisites are all mastered (unlocked).
pub struct AssignedCurriculumThe full read model: a learner's assignment + the (frozen) version, the ordered skills with progress, and the recommended next skill ids.
fn assemble_assigned_curriculum(assignment : CurriculumAssignment, version : CurriculumVersion, placements : Vec <CurriculumVersionSkill>, skills_by_id : & HashMap <Uuid, Skill>, progress_by_skill : & HashMap <Uuid, SkillProgress>, hard_prereqs : & (Uuid, Uuid),) -> AssignedCurriculumAssemble the read model from already-fetched rows

`repository`

ItemWhat it is
pub struct CurriculumRepositoryThin Postgres repository over the eight curriculum tables
CurriculumRepository :: fn new(pool : PgPool) -> SelfWrap a connection pool.
CurriculumRepository :: fn pool(& self) -> & PgPoolBorrow the underlying pool (for transactions / advanced callers).
CurriculumRepository :: async fn create_template(& self, t : & CurriculumTemplate) -> Result <()>
CurriculumRepository :: async fn get_template(& self, id : Uuid) -> Result <Option <CurriculumTemplate>>
CurriculumRepository :: async fn list_templates(& self) -> Result <Vec <CurriculumTemplate>>List non-deleted templates, newest first.
CurriculumRepository :: async fn set_template_status(& self, id : Uuid, status : CurriculumStatus) -> Result <()>Set a template's lifecycle status (draft → published → archived).
CurriculumRepository :: async fn create_version(& self, v : & CurriculumVersion) -> Result <()>
CurriculumRepository :: async fn get_version(& self, id : Uuid) -> Result <Option <CurriculumVersion>>
CurriculumRepository :: async fn list_versions(& self, curriculum_id : Uuid) -> Result <Vec <CurriculumVersion>>All versions of a curriculum, lowest version number first.
CurriculumRepository :: async fn max_version_no(& self, curriculum_id : Uuid) -> Result <Option <i32>>Highest existing version number for a curriculum (for next_version_no).
CurriculumRepository :: async fn set_version_status(& self, id : Uuid, status : VersionStatus, published_at : Option <DateTime <Utc>>,) -> Result <()>Update a version's status, stamping published_at when supplied.
CurriculumRepository :: async fn create_skill(& self, s : & Skill) -> Result <()>
CurriculumRepository :: async fn get_skill(& self, id : Uuid) -> Result <Option <Skill>>
CurriculumRepository :: async fn get_skill_by_code(& self, code : & str) -> Result <Option <Skill>>
CurriculumRepository :: async fn add_version_skill(& self, cvs : & CurriculumVersionSkill) -> Result <()>
CurriculumRepository :: async fn remove_version_skill(& self, version_id : Uuid, skill_id : Uuid) -> Result <()>
CurriculumRepository :: async fn list_version_skills(& self, version_id : Uuid,) -> Result <Vec <CurriculumVersionSkill>>Skills placed in a version, ordered by sort_order then placement time.
CurriculumRepository :: async fn count_version_skills(& self, version_id : Uuid) -> Result <i64>
CurriculumRepository :: async fn set_version_skill_order(& self, version_id : Uuid, skill_id : Uuid, sort_order : i32,) -> Result <()>Reset a placement's sort order (used by reorder).
CurriculumRepository :: async fn add_prerequisite(& self, p : & SkillPrerequisite) -> Result <()>Insert (or update the kind of) a prerequisite edge.
CurriculumRepository :: async fn remove_prerequisite(& self, version_id : Uuid, skill_id : Uuid, prerequisite_skill_id : Uuid,) -> Result <()>
CurriculumRepository :: async fn list_prerequisites(& self, version_id : Uuid) -> Result <Vec <SkillPrerequisite>>All prerequisite edges in a version.
CurriculumRepository :: async fn create_assignment(& self, a : & CurriculumAssignment) -> Result <()>
CurriculumRepository :: async fn get_assignment(& self, id : Uuid) -> Result <Option <CurriculumAssignment>>
CurriculumRepository :: async fn list_assignments_for_learner(& self, learner_party_id : Uuid,) -> Result <Vec <CurriculumAssignment>>All assignments for a learner (newest first).
CurriculumRepository :: async fn set_assignment_status(& self, id : Uuid, status : AssignmentStatus, completed_at : Option <DateTime <Utc>>,) -> Result <()>
CurriculumRepository :: async fn upsert_skill_progress(& self, p : & SkillProgress) -> Result <()>Insert or replace the progress row for (assignment_id, skill_id).
CurriculumRepository :: async fn get_skill_progress(& self, assignment_id : Uuid, skill_id : Uuid,) -> Result <Option <SkillProgress>>
CurriculumRepository :: async fn list_skill_progress(& self, assignment_id : Uuid) -> Result <Vec <SkillProgress>>All progress rows for an assignment.
CurriculumRepository :: async fn append_event(& self, e : & CurriculumEvent) -> Result <()>
CurriculumRepository :: async fn list_events(& self, assignment_id : Uuid) -> Result <Vec <CurriculumEvent>>Event history for an assignment, oldest first (audit order).

`rules`

ItemWhat it is
fn next_version_no(current_max : Option <i32>) -> i32Next version number for a curriculum (1-based; first version = 1).
fn can_publish_version(status : VersionStatus, skill_count : usize,) -> Result <(), CurriculumError>A version may be published only if it is a Draft with at least one skill.
fn can_assign_version(status : VersionStatus) -> Result <(), CurriculumError>A learner may be assigned only to a Published version (principle #8).

`service`

ItemWhat it is
pub struct CurriculumServiceHigh-level curriculum operations.
CurriculumService :: fn new(repo : CurriculumRepository) -> SelfBuild a service over a repository.
CurriculumService :: fn repo(& self) -> & CurriculumRepositoryBorrow the underlying repository (for callers needing raw reads).
CurriculumService :: async fn create_draft(& self, code : impl Into <String>, title : impl Into <String>,) -> Result <(CurriculumTemplate, CurriculumVersion)>Create a new draft curriculum: a template plus its draft version 1.
CurriculumService :: async fn create_draft_version(& self, curriculum_id : Uuid) -> Result <CurriculumVersion>Start a new draft version of an existing curriculum (empty placement — the explicit migration of skills from a prior version is a separate op, principle #11)
CurriculumService :: async fn create_skill(& self, code : impl Into <String>, title : impl Into <String>, skill_type : impl Into <String>,) -> Result <Skill>Create a reusable skill.
CurriculumService :: async fn add_skill(& self, version_id : Uuid, skill_id : Uuid, sort_order : i32,) -> Result <CurriculumVersionSkill>Place a skill into a draft version at sort_order.
CurriculumService :: async fn remove_skill(& self, version_id : Uuid, skill_id : Uuid) -> Result <()>Remove a skill placement from a draft version.
CurriculumService :: async fn reorder_skills(& self, version_id : Uuid, ordered_skill_ids : & Uuid) -> Result <()>Reorder a draft version's skills: ordered_skill_idsi gets sort_order = i.
CurriculumService :: async fn add_prerequisite(& self, version_id : Uuid, skill_id : Uuid, prerequisite_skill_id : Uuid, kind : PrerequisiteKind,) -> Result <SkillPrerequisite>Add a prerequisite edge to a draft version, validating the whole edge set stays a DAG before persisting (principle #5).
CurriculumService :: async fn publish_version(& self, version_id : Uuid) -> Result <CurriculumVersion>Publish a draft version (requires ≥1 skill)
CurriculumService :: async fn archive(& self, curriculum_id : Uuid) -> Result <()>Archive a curriculum template (published versions remain readable but the template is no longer offered, principle #8).
CurriculumService :: async fn assign(& self, version_id : Uuid, learner_party_id : Uuid, assigned_by_party_id : Option <Uuid>,) -> Result <CurriculumAssignment>Assign a learner (a Party) to a published version, seeding a not_started progress row for every placed skill (principle #3/#4/#8).
CurriculumService :: async fn update_skill_progress(& self, assignment_id : Uuid, skill_id : Uuid, status : SkillProgressStatus, score : Option <i32>, manually_overridden : bool,) -> Result <SkillProgress>Update a learner's explicit progress on one skill
CurriculumService :: async fn append_event(& self, assignment_id : Uuid, skill_id : Option <Uuid>, event_type : impl Into <String>, source : EventSource, actor_party_id : Option <Uuid>,) -> Result <CurriculumEvent>Append an immutable event to an assignment's history (principle #9).
CurriculumService :: async fn get_assigned_curriculum(& self, assignment_id : Uuid) -> Result <AssignedCurriculum>The full assigned-curriculum read model: assignment + frozen version + ordered skills with progress + recommended next skills.
CurriculumService :: async fn recommended_next_skills(& self, assignment_id : Uuid) -> Result <Vec <Uuid>>The learner's recommended next skills for an assignment (unlocked and not yet mastered).

Re-exports. Exported here, defined elsewhere.

ExportDefined in
CurriculumErrorerror::CurriculumError
CurriculumRepositoryrepository::CurriculumRepository
CurriculumServiceservice::CurriculumService
{AssignmentStatus,CurriculumAssignment,CurriculumEvent,CurriculumStatus,CurriculumTemplate,CurriculumVersion,CurriculumVersionSkill,EventSource,ParseStatusError,PrerequisiteKind,Skill,SkillPrerequisite,SkillProgress,SkillProgressStatus,VersionStatus,}models::{AssignmentStatus,CurriculumAssignment,CurriculumEvent,CurriculumStatus,CurriculumTemplate,CurriculumVersion,CurriculumVersionSkill,EventSource,ParseStatusError,PrerequisiteKind,Skill,SkillPrerequisite,SkillProgress,SkillProgressStatus,VersionStatus,}
{assemble_assigned_curriculum,AssignedCurriculum,SkillView}read_model::{assemble_assigned_curriculum,AssignedCurriculum,SkillView}
{can_assign_version,can_publish_version,next_version_no}rules::{can_assign_version,can_publish_version,next_version_no}
{recommended_next,unlocked_skills,validate_no_cycles}progression::{recommended_next,unlocked_skills,validate_no_cycles}

Boundary

Reaches into foundation.

Shares tier domain with 41 other crates: domain-agreements, domain-ai-report, domain-billing, domain-catalog, domain-classify, domain-comments, domain-competitive-intel, domain-contact, … (41 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)domain
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/domain/curriculum
Vocabulary in force (lexicon)current

Tier flow. Which tiers this crate's own edges cross.

flowchart LR
  n_domain["domain"] --> n_foundation["foundation"]

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`foundation-basemodels`foundationnoalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
async-trait^0.1noalways
chrono^0.4serdenoalways
serde^1derivenoalways
serde_json^1noalways
sqlx^0.8runtime-tokio, postgres, chrono, uuid, jsonnoalways
thiserror^2noalways
uuid^1v4, serdenoalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
tokio^1full, test-utilnoalways

Build. None.

Depended on by. Nothing in this workspace.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  SELF["domain-curriculum"]
  SELF -->|runtime| n_foundation_basemodels["foundation-basemodels"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

FeatureEnablesOn by default
postgresno
flowchart LR
  n_postgres["postgres"]

Targets

KindNameSource
libdomain_curriculum`src/lib.rs`
testpg_repository`tests/pg_repository.rs`
testpg_service`tests/pg_service.rs`

Error model

Error typeNamed by
CurriculumErrorcan_assign_version, can_publish_version, validate_no_cycles
ParseStatusErrordeclared, no public signature returns it

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimenone detected
database accessyes
network I/Onone detected
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

No workspace crate depends on this one.

Verification

KindCount
Unit tests21
Integration tests6
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
error100
models1500
progression300
read_model300
repository100
rules300
service100

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc74121
Public modules with a //! block77
pie showData
    title Public items with rustdoc
    "Documented" : 74
    "No rustdoc detected" : 47

Metrics

MetricValue
Rust source files8
Source lines2233
Code lines1806
Public API items121
Public modules7
Tests27
Examples0
Cargo features1
Direct runtime dependencies8
Workspace reverse dependencies0
pie showData
    title Public API by kind
    "enum" : 7
    "function" : 7
    "method" : 94
    "struct" : 13
pie showData
    title Rust source composition
    "Code" : 1806
    "Blank or comment" : 427

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

Todas las domain · Manual