Architecture notes
On configuration semantics
Mycel uses two distinct levels of configuration, each with a clear semantic scope:
User configuration holds global behavior settings that apply regardless of which collection is activen things like undo age, deletion policy, reconnection frequency, or navigation behavior. These are user preferences about how mycel/implementation works.
Collection configuration (CollectionConf, AlgoConf) holds settings scoped to a specific collection: the visual theme, the spaced repetition algorithm parameters, etc. These are intentionally per-collection because a user may want different retention targets or aesthetics across collections.
When adding a new setting, ask: does this apply to the user's entire experience, or only within a specific collection? That determines where it belongs.
On resource ownership and safety
To verify whether a user has the right to access a specific resource (e.g., nodes, reviews), certain functions enforce authorization by querying the repository and filtering by user_id.
Every REST endpoint must route through at least one of these ownership-verification functions at the very beginning of any data access or modification lifecycle.
(Note: These functions are not explicitly listed here as they may change; please refer to the endpoint implementations for direct references.)
Node vs Learning Unit
In Mycel, spores and fragments are represented through two layers of data:
- Node holds the content data: fields, parent_id, template, etc.
- Learning unit holds the learning data (due date, position, FSRS state...). This allows a single node to have multiple learning units, for example, a cloze note like {{c1::Capital of France}} {{c2::Paris}} generates multiple questions from the same content without duplicating it.
This comes with a cost: in the codebase, the two must be carefully distinguished. When fragment_id or spore_id are passed as arguments, they refer to learning unit ids, not node ids. A node is not itself a fragment or spore: it is a base_for fragment or spore (hence the field in the DB).
This complexity is hidden from clients: the REST API never exposes learning_unit_id. Clients always speak in terms of node_id + slot (int). If slot is not specified, it defaults to 0, allowing clients to ignore multi-spore logic entirely if they choose not to implement it.