# Codex Structure Plan

This document plans a future evolution of LoreLoom's flat codex into a nested codex structure. It is a specification pass only. It does not change current app behavior.

## Goals

- support nested codex organization inside a project
- keep the current local-first model understandable
- preserve existing codex content safely during migration
- make room for different worldbuilding shapes without forcing one taxonomy
- keep Focus Mode lookup lightweight

## Non-Goals

This pass does not propose:

- graph views
- AI linking or extraction
- relationship maps
- backend schema changes yet
- collaboration features

## Current State Review

### Current Codex Model

The current frontend model is a flat `CodexEntry` array stored inside the local persisted state.

Current `CodexEntry` fields in [apps/web/src/lib/types.ts](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/lib/types.ts):

- `id`
- `projectId`
- `title`
- `type`
- `content`
- `tags`
- `createdAt`
- `updatedAt`

`type` currently supports:

- `character`
- `location`
- `object`
- `faction`
- `lore`
- `timeline`
- `custom`

### Where Codex Entries Are Stored

Frontend state currently stores codex data as:

- `codexEntries: CodexEntry[]`

inside `LoreLoomState` in [apps/web/src/lib/types.ts](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/lib/types.ts).

The Zustand store in [apps/web/src/store/useLoreLoomStore.ts](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/store/useLoreLoomStore.ts) owns:

- create
- update
- delete
- per-project reads
- bundle export/import participation

Entries are project-scoped only. There is no codex tree, folder, parent, or node attachment yet.

### Current UI Shape

The main codex UI lives in [apps/web/src/components/project/CodexPanel.tsx](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/components/project/CodexPanel.tsx).

Current behavior:

- left column: flat list of codex entries
- right column: create/edit form
- select entry to edit
- create new entry
- delete selected entry
- tags are comma-separated text input

Project page state for codex selection and form ownership currently lives in [apps/web/src/pages/ProjectPage.tsx](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/pages/ProjectPage.tsx).

### Backup / Import Handling

Project backup logic in [apps/web/src/lib/backup.ts](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/lib/backup.ts) currently:

- exports `codexEntries` directly as a flat array
- includes codex entries in project backup JSON
- imports older backup versions with codex normalization already in place
- preserves codex entry IDs unless collision remapping is required during import

Current backup format in [apps/web/src/lib/types.ts](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/lib/types.ts):

- `version: 4`

### Focus Mode Codex Lookup

Focus Mode codex lookup currently lives in [apps/web/src/pages/ScenePage.tsx](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/pages/ScenePage.tsx).

Current behavior:

- filters project codex entries only
- searches by title and tags
- ranks matches with lightweight local fuzzy matching
- shows:
  - entry title
  - entry type
  - entry tags
  - content preview
- expands inline without leaving Focus Mode

This lookup assumes one flat project-level entry list.

### Diagnostics

Diagnostics currently count codex entries only, not categories or nodes.

Relevant files:

- [apps/web/src/pages/DiagnosticsPage.tsx](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/pages/DiagnosticsPage.tsx)
- [apps/web/src/lib/diagnostics.ts](/Users/zennondeboer/Documents/LoreLoom/apps/web/src/lib/diagnostics.ts)

Current diagnostics include:

- total codex entry count
- per-project codex entry counts

Diagnostics intentionally exclude:

- codex content
- codex titles

## Proposed Data Model

The proposed model introduces a codex tree plus node-attached entries.

### CodexNode

Recommended new type:

```ts
type CodexNode = {
  id: ID;
  projectId: ID;
  parentId: ID | null;
  type: CodexNodeType;
  customTypeLabel?: string | null;
  title: string;
  tags: string[];
  orderIndex: number;
  createdAt: string;
  updatedAt: string;
};
```

Recommended built-in `CodexNodeType` values:

- `codex`
- `group`
- `characters`
- `places`
- `factions`
- `objects`
- `timeline`
- `research`
- `custom`

Why this shape:

- it matches the current writing structure tree mental model
- it supports parent/child nesting cleanly
- it allows custom labels without forcing a fixed taxonomy
- tags on nodes let users describe categories or collections, not just entries

### CodexEntry

Recommended evolved entry type:

```ts
type CodexEntry = {
  id: ID;
  projectId: ID;
  codexNodeId: ID;
  title: string;
  type: CodexEntryType;
  content: string;
  tags: string[];
  createdAt: string;
  updatedAt: string;
};
```

Key change:

- add `codexNodeId`

Keep the rest stable where possible to reduce migration risk and preserve import behavior.

### State Shape

Recommended frontend state addition:

```ts
type LoreLoomState = {
  projects: Project[];
  structureNodes: StructureNode[];
  scenes: Scene[];
  codexNodes: CodexNode[];
  codexEntries: CodexEntry[];
  revisionSnapshots: RevisionSnapshot[];
};
```

This keeps codex nodes parallel to writing structure nodes instead of embedding a second tree shape inside entries.

## Desired Behavior

The nested codex should support:

- parent/child codex nodes
- custom node labels
- node tags
- entries inside nodes
- entry tags
- future category shapes such as:
  - characters
  - places
  - factions
  - timeline notes
  - research
  - custom lore collections

The model should stay flexible enough that a user can build:

- one simple grouped codex
- a deep hierarchy
- a mixed taxonomy with custom labels

## Migration Strategy

### Local Persisted State Migration

Existing flat codex entries should migrate into a default root codex node per project.

Recommended migration behavior:

1. add `codexNodes`
2. for each project with at least one codex entry, create one default root node if none exists
3. assign all existing entries in that project to the default node
4. preserve existing entry IDs
5. preserve titles, types, tags, content, timestamps

Recommended default node:

- `type: 'codex'`
- `title: 'Codex'`
- `parentId: null`
- `tags: []`

Why this is the safest first migration:

- no codex content needs to be reclassified automatically
- no guessing based on entry type
- users keep all existing entries
- later UI can offer manual reorganizing into nested nodes

### Import Compatibility

Older backups should remain importable.

Recommended behavior for older backups:

- if backup has no `codexNodes`, create one default root codex node
- place all imported flat codex entries into that node
- preserve imported codex entry IDs unless collision remapping is needed

### Backend Bundle Compatibility

The current backend bundle already includes `codexEntries` only.

When backend support is added later, bundle format should grow to include:

- `codexNodes`
- `codexEntries` with `codexNodeId`

This plan does not require backend schema work yet, but the model should be designed so it can be added in a later bundle revision without changing the high-level shape again.

## UI Plan

### Main Codex Workspace

Recommended layout:

- left: nested codex tree
- center or right: selected node contents and entries list
- detail/editor pane: create/edit node or entry

The current two-column Codex panel can evolve rather than be replaced outright.

Suggested structure:

- tree column
  - nested nodes
  - expand/collapse
  - clear indentation
  - node type/custom label display
  - entry count per node
- content column
  - selected node summary
  - child nodes
  - entries attached to selected node
- edit pane or inline forms
  - create/edit node
  - create/edit entry

### Node Operations

Nodes should support:

- create child node
- edit title
- edit built-in/custom type
- edit custom label
- edit tags
- delete node

Delete behavior should be explicit in the UI because nested content creates real consequences.

Recommended delete rules for v1:

- deleting a node should require it to be empty first
- or offer a deliberate "move children and entries to parent" flow later

For the first implementation, "empty only" deletion is simpler and safer.

### Entry Operations

Entries should support:

- create entry inside selected node
- edit entry
- delete entry
- move entry to another node

Recommended v1 simplification:

- create/edit/delete first
- add move later if needed

### Search / Filter

Codex search should work across:

- node titles
- node tags
- entry titles
- entry tags
- optionally entry content previews later

Recommended search result types:

- node result
- entry result

Each result should show enough path context to place it inside the hierarchy.

### Visual Hierarchy

The UI should make these distinctions clear:

- node vs entry
- selected node vs selected entry
- path depth
- custom node label vs title

Recommended visual cues:

- indentation for hierarchy
- lighter metadata for node type/custom label
- tags as secondary chips
- breadcrumb path when inspecting entries

## Focus Mode Lookup Plan

Focus Mode lookup should stay lightweight and writing-first.

Recommended behavior with nested codex:

- search across all nodes and entries in the current project
- rank entry title/tag matches most strongly
- include node title/tag matches as context
- show breadcrumb path for each entry

Example result shape:

- `Captain Iri`
- `Characters / Pirates / Blackwake Crew`
- `character`
- short preview

If nodes themselves become searchable results, they should expand to reveal a short node summary or child/entry counts rather than taking the user away from writing.

Recommended Focus Mode result display:

- title
- type
- breadcrumb path
- preview/snippet

This preserves the current lightweight lookup feel while making deeper organization understandable at a glance.

## Export / Import Plan

### Backup Format

Project backup JSON should eventually include:

- `codexNodes`
- `codexEntries`

Recommended backup version bump:

- current: `4`
- proposed codex-tree version: `5`

### Compatibility Rules

Version `5` import should:

- validate `codexNodes`
- validate `codexEntries`
- ensure all `codexNodeId` values belong to imported nodes in the same project

Older versions should still import:

- `v1-v4` backups with flat codex entries

Migration on import:

- create default root codex node
- attach imported flat entries there

### Story Export / Preview

Story TXT export should remain codex-free.

Book Preview should continue showing only writing content, not codex data.

## Phased Implementation Plan

### Phase 1: Data Model

- add `CodexNode`
- add `codexNodes` to frontend state
- add `codexNodeId` to `CodexEntry`
- add persisted-state migration for current local data

### Phase 2: Backup Compatibility

- bump backup format to `5`
- export `codexNodes`
- import both `v5` nested codex and older flat backups

### Phase 3: Store API

- add codex node CRUD in Zustand
- update codex entry CRUD to work through node attachment
- add tree selectors and sorting helpers

### Phase 4: Main Codex UI

- replace flat entry list with nested codex tree
- support node creation/edit/delete
- support entry creation/edit/delete inside nodes
- support custom node labels and node tags

### Phase 5: Search and Focus Mode Lookup

- search across nodes and entries
- add breadcrumb paths to lookup results
- keep inline expand behavior in Focus Mode

### Phase 6: Diagnostics and Bundle Evolution

- count codex nodes as well as codex entries
- keep diagnostics content-safe
- later extend backend bundle contracts to include codex nodes

## Risks

- codex deletion semantics become more complex once entries can live inside nested nodes
- a tree plus entry list can make the current compact Codex panel feel crowded if not decomposed carefully
- backup/import logic becomes more nuanced because node graphs need validation
- Focus Mode lookup ranking may need tuning once breadcrumb context is introduced
- current command palette codex jump actions are flat-entry based and will need path-aware upgrades later

## Open Questions

- Should codex node tags be shown as a primary filter surface, or mainly as metadata?
- Should entries be movable between nodes in the first nested-codex release, or deferred?
- Should node types stay freeform-light with a few defaults, or mirror the writing structure model more closely?
- Should some built-in top-level nodes be created automatically for new projects, or should new projects still begin with a single default root?

## Recommended Defaults

For the first nested-codex implementation, the safest defaults are:

- one root `Codex` node per project
- manual organization by the user
- preserve current codex entry types
- keep Focus Mode lookup entry-first
- keep deletion rules conservative

This keeps the migration calm and preserves the current project behavior while making room for a much richer codex later.
