Platform concepts
This is Cursare's mental model: a small set of concepts that combine to describe any learning experience, from a standalone piece of text to a complete program. Understanding how they connect prevents you from duplicating material and creating conflicting rules.
Content is the central unit
A content is the platform's only publishable unit. It owns identity (route segment, tags, theme) and the editorial body; access, format, and commercial terms live on explicit offers (see Offers & checkout). Everything else in Cursare — enrollments, purchases, reviews, quiz history, and references — points to a content's stable id.
Each content is a single row in the database, updated in place. It holds two states:
| State | What it is | Who reads it |
|---|---|---|
Draft (draftDocument) | The editable working version | The team, in the editor |
Published (publishedDocument) | The frozen copy from the last publish | Learners |
Publishing copies draftDocument into publishedDocument, records the date, and recomputes derived facts. There are no version rows: the learner always reads the latest published document, and progress survives because it is anchored to stable section identifiers, not to version numbers.
Roles emerge from relationships
Content has no persisted kind. The same object can play several roles at once:
- Standalone — published and read directly, with or without an offer.
- Root — the content linked to an offer and therefore the single enrollment boundary.
- Reusable child — referenced from one or many roots, at any depth.
- Listed — discoverable in the public catalog independently of whether it is referenced elsewhere.
Adding or archiving an offer changes commercial entry, not the content's identity, document, route, or graph. Referencing content changes composition, not enrollment ownership.
Composition through references
A reference is an edge that links a parent content to a child content. You insert it in the editor, and it carries three pieces of information:
| Reference field | Meaning |
|---|---|
targetContentId | The stable id of the referenced content |
blockId | The stable identity of this exact placement |
routeSegment | The local URL segment owned by the placement |
afterHours, dripAnchor | The placement's release timing |
requires | Explicit prerequisite placement ids |
A content's references form a directed graph. On publish, the learner manifest and graph projection are recomputed and every reference must target a published content from the same organization. Publication is refused for three dangerous cases:
- Targets from another organization — prevents an enrolled learner from reading someone else's paid or unlisted material for free.
- Targets with no published version — prevents a card that could never be completed, leaving the course forever incomplete.
- Deleted targets — prevents dangling edges.
In addition, cycles and self-references block publication. The previous published document and graph remain unchanged. Publishes within the same organization are serialized so two simultaneous publishes cannot jointly form a cycle.
Continuous navigation under a single enrollment
A composition can have any depth of nesting, but the learner enrolls only once, in the root content connected to the selected offer. There is no separate enrollment for each referenced content.
From the root, the learner navigates continuously across the entire referenced tree. The platform resolves each URL segment against the enrolled tree (the shallowest match wins) and builds the breadcrumb along the shortest path from the root to the open module. A module is only accessible if it belongs to that person's active enrollment tree.
Access and progression
Access determines who can get in. Progression determines what becomes available after someone is already in. The two rules are independent: a learner can have access to the entire course and still find modules released over time (drip) or by prerequisite.
| Concept | Responsibility |
|---|---|
| Publishing | Defines the version visible to the learner |
| Listing | Defines whether the content appears in the catalog |
| Access | Defines who can get in (price, approval, seat limit) |
| Offer | The sellable package of a content — price, format, entry terms |
| Enrollment | Links a person to a root content (the learner row) |
| Progress | Records completed sections by stable id |
| Drip | Releases steps after an interval |
| Prerequisite | Requires completing another step before releasing |
When an offer exists, access derives above all from its price: a free offer allows direct enrollment; with a price, access goes through checkout. Additional layers can require approval and impose a seat limit. A content can carry multiple offers with different prices and terms for the same graph; campaigns can discount them. Progress is keyed by root, stable content id, and stable section or placement id, so reused content stays individually measurable without creating extra enrollments.
Completing a tree
A root is only considered complete when all of its own required sections and every required referenced placement at any depth are complete. This whole-graph completion unlocks the certificate.
Learners and members
Two distinct populations coexist in an organization, and the distinction must always stay clear:
| Role | Who they are | Link |
|---|---|---|
| Learner | A student enrolled in a course through an offer | learner row (person + course + current offer) |
| Member | Someone on the team who runs the operation | Organization member |
The same user can be a learner in one organization and a member in another — they are independent links. There is at most one enrollment per person and course, and it points to exactly one offer of that course. Alternative offers are entry choices before enrollment, not parallel entitlements: while the enrollment is active or past due, the learner cannot switch offers or buy another offer for the same course. Enrollment is idempotent: enrolling through the same offer returns the existing row. Only an active enrollment grants access; refunded or past-due enrollments keep the row (for history) but do not open the course. A paid learner also points to its exact current purchase, while free/comped learners keep that pointer null.
Member roles and the content's four functions
At the organization level, owner and admin hold structural authority and pass any content check. Below that, authority over a content is assigned by function, and each function corresponds to a member's role on the content's owning team (content.teamId):
| Function (domain) | Team role | What it authorizes |
|---|---|---|
draftDocument | editor | Edit the body, publish, tags, theme, format |
finance | finance | Price, currency, installments, refunds, listing |
cohort | cohort | Manage cohorts, moderate, act as tutor |
learners | learners | Manage enrollment, progress, intake answers, and attachments |
Campaigns (coupons) are not covered by any of these functions: creating and editing them is an organization surface, restricted to owner and admin.
A content can be owned by a person (personal content) or a team — never both at the same time. The owning person holds all functions over their content. Owner-level actions (transferring ownership, deleting), however, require the owning person or an organization admin — no team role reaches that level.
Organizational structure
The organization is the operation's main space; it is the source of the public catalog and the producer pages. Within it:
- Teams are the organization's curriculum areas: they slice the staff by subject (Programming, Backend), not by company function, and each team owns the contents of its area. The team that owns a content is the authority over it, and the per-member roles (editor, finance, cohort, learners) provide the granularity described above.
- Cohorts are delivery groups for one offer: they keep dates, seats, one tutor, and discussion together. An enrollment points directly to at most one cohort of its own offer.
Self-paced or cohort delivery
Format belongs to the offer, not the content. The same course may have a self-paced offer and a cohort-delivered offer:
deliveryMode | How it works |
|---|---|
self_paced | The learner advances at their own pace; drip counts from enrollment. A cohort is optional and can exist only for discussion. |
cohort | Enrollment points to a dated cohort of the same offer; drip counts from that cohort's start. |
Cohort-delivered offers can create cohorts automatically, with configurable duration, seat limit, and tutor. The tutor can be fixed or selected by least load among eligible owning-team members.