# Core Data Model

## Project
A writing project that groups structure nodes, text blocks, codex nodes, and codex entries.

Fields:
- `id`
- `name`
- `createdAt`
- `updatedAt`

## StructureNode
A hierarchical unit that organizes a project into books, parts, acts, chapters, sequences, sections, or custom groups.

In the current UI, structure nodes are the primary organizing surface for the draft. Writers create child nodes and text blocks directly inside the structure tree rather than treating writing content as a separate top-level list.

Fields:
- `id`
- `projectId`
- `parentId`
- `type`
- `customTypeLabel` optional, used when `type` is `custom`
- `title`
- `orderIndex`
- `createdAt`
- `updatedAt`

Supported `type` values:
- `book`
- `part`
- `act`
- `chapter`
- `sequence`
- `section`
- `custom`

If `type` is `custom`, LoreLoom can store a user-facing custom node label such as `Interlude` or `Appendix`. Older custom nodes without a saved label fall back to `Custom`.

## Text Block
Text Block is the user-facing writing content unit in LoreLoom. Each text block belongs to a `StructureNode`, so writing can live under any supported node type.

Text blocks are intended to be created and managed in the context of their owning structure node, which keeps the outline and the manuscript flow spatially connected.

During early development, the internal code and backup shape may still refer to this entity as `Scene` to avoid risky migrations while the model is still settling.

Fields:
- `id`
- `projectId`
- `structureNodeId`
- `title`
- `content`
- `createdAt`
- `updatedAt`

Autosave remains the live current state for the text block. LoreLoom updates the current title and content continuously while the writer is typing.

## Revision Snapshot
Revision snapshots are local recovery points for a text block. They are separate from autosave and are intended to preserve earlier versions when a writer leaves an editing session after meaningful changes.

Fields:
- `id`
- `sceneId` internal text block reference
- `projectId`
- `title`
- `content`
- `createdAt`

Automatic snapshot behavior:
- LoreLoom evaluates snapshot creation when the writer leaves the editor session, not on every keystroke.
- A snapshot is created if the title changed, or the content changed with at least 25 characters of plain text, or there is no earlier snapshot and the current text has at least 25 characters.
- Snapshots are not created for effectively empty content.
- If the latest snapshot already matches the current title and content exactly, no duplicate snapshot is created.
- LoreLoom keeps at most 25 snapshots per text block and discards the oldest ones beyond that limit.

## Persistence
For the first prototype, projects, structure nodes, text blocks, codex nodes, and codex entries are stored together in `localStorage` as one browser-owned document.

When backend persistence is enabled, the same project graph is also mirrored durably through the project bundle API, including `codexNodes` and `codexEntry.codexNodeId`.

## Project Backup JSON
LoreLoom project backups are human-readable JSON files intended for restoring or migrating a single project.

Shape:
- `format`: `"LoreLoom Project Backup"`
- `version`: `5`
- `exportedAt`: ISO timestamp
- `project`: project metadata
- `structureNodes`: structure node array
- `scenes`: ordered text block array using the legacy internal `Scene` key
- `codexNodes`: codex node array
- `codexEntries`: codex entry array
- `revisionSnapshots`: revision snapshot array

Compatibility:
- Backups exported before structure nodes were added are still accepted on import.
- Older backup versions are normalized so legacy text blocks land in a default `Chapter 1` node.
- Older flat codex backups are normalized into a default top-level `Codex` node on import.
- Older backup versions before snapshots were added are still accepted and import with an empty snapshot list.

## CodexNode
A hierarchical codex container that organizes codex entries inside a project.

Fields:
- `id`
- `projectId`
- `parentId`
- `type`
- `customTypeLabel`
- `title`
- `tags`
- `orderIndex`
- `createdAt`
- `updatedAt`

Supported `type` values:
- `codex`
- `group`
- `characters`
- `places`
- `factions`
- `objects`
- `timeline`
- `research`
- `custom`

Migration notes:
- Existing flat codex entries migrate into a default top-level `Codex` node.
- LoreLoom preserves codex entry ids during this migration unless an import id collision requires remapping.
- Backend bundle normalization uses the same safe default-node approach for older flat codex projects.

## CodexEntry
A project-scoped lore note used for characters, locations, objects, factions, and other worldbuilding details. Each entry belongs to a `CodexNode`.

Fields:
- `id`
- `projectId`
- `codexNodeId`
- `title`
- `type`
- `content`
- `tags`
- `createdAt`
- `updatedAt`

Supported `type` values:
- `character`
- `location`
- `object`
- `faction`
- `lore`
- `timeline`
- `custom`

Import rules:
- Backups are validated before import.
- Importing never overwrites existing projects.
- If imported project, structure node, text block, codex node, or codex entry ids collide with existing ids, new ids are generated.

## Story TXT Export
Story export is a plain text manuscript file.

It includes:
- the project title
- structure node titles in hierarchy order
- text block titles in order
- readable plain text from rich text text block content

## Notes
- The app derives project and text block lists directly from the stored collections.
- Content is stored as TipTap HTML for the vertical slice.
- Revision snapshots store rich text HTML content for restore safety, even when snapshot rules compare plain text to decide whether a new snapshot is needed.
- Final wiki PDF export is planned after codex entries exist.
- Spell checking in the text block editor uses the browser or system spellchecker only, with no external service involvement.
