Skip to content

ERD_DIAGRAM

spuentesp edited this page Dec 27, 2025 · 1 revision

MONITOR ERD Diagrams

Entity-Relationship diagrams for the complete MONITOR data model across Neo4j, MongoDB, and Qdrant.


1. Neo4j Canonical Layer (Graph)

This is the canonical truth layer - what is objectively true in the universe.

erDiagram
    OMNIVERSE {
        uuid id PK
        string name
        string description
        timestamp created_at
    }

    MULTIVERSE {
        uuid id PK
        uuid omniverse_id FK
        string name
        string system_name
        string description
        timestamp created_at
    }

    UNIVERSE {
        uuid id PK
        uuid multiverse_id FK
        string name
        string description
        string genre
        string tone
        string tech_level
        enum canon_level
        timestamp created_at
    }

    SOURCE {
        uuid id PK
        uuid universe_id FK
        string doc_id
        string title
        string edition
        string provenance
        enum source_type
        enum canon_level
        timestamp created_at
    }

    AXIOM {
        uuid id PK
        uuid universe_id FK
        string statement
        string domain
        float confidence
        enum canon_level
        enum authority
        timestamp created_at
    }

    ENTITY_AXIOMATICA {
        uuid id PK
        uuid universe_id FK
        string name
        enum entity_type
        string description
        map properties
        enum canon_level
        float confidence
        timestamp created_at
    }

    ENTITY_CONCRETA {
        uuid id PK
        uuid universe_id FK
        string name
        enum entity_type
        string description
        map properties
        list state_tags
        enum canon_level
        float confidence
        timestamp created_at
        timestamp updated_at
    }

    STORY {
        uuid id PK
        uuid universe_id FK
        string title
        enum story_type
        string theme
        string premise
        enum status
        timestamp start_time_ref
        timestamp end_time_ref
        timestamp created_at
        timestamp completed_at
    }

    SCENE {
        uuid id PK
        uuid story_id FK
        string title
        string purpose
        int order
        timestamp time_ref
        timestamp created_at
    }

    FACT {
        uuid id PK
        uuid universe_id FK
        string statement
        timestamp time_ref
        int duration
        float confidence
        enum canon_level
        enum authority
        uuid replaces FK
        timestamp created_at
    }

    EVENT {
        uuid id PK
        uuid scene_id FK
        string title
        string description
        timestamp time_ref
        int severity
        float confidence
        enum canon_level
        enum authority
        timestamp created_at
    }

    PLOTTHREAD {
        uuid id PK
        uuid story_id FK
        string title
        enum thread_type
        enum status
        timestamp created_at
    }

    %% Containment hierarchy
    OMNIVERSE ||--o{ MULTIVERSE : CONTAINS
    MULTIVERSE ||--o{ UNIVERSE : CONTAINS
    UNIVERSE ||--o{ SOURCE : HAS_SOURCE
    UNIVERSE ||--o{ AXIOM : HAS_AXIOM
    UNIVERSE ||--o{ ENTITY_AXIOMATICA : HAS_ENTITY
    UNIVERSE ||--o{ ENTITY_CONCRETA : HAS_ENTITY
    UNIVERSE ||--o{ STORY : HAS_STORY

    %% Story structure
    STORY ||--o{ STORY : PARENT_STORY
    STORY ||--o{ SCENE : HAS_SCENE
    STORY ||--o{ PLOTTHREAD : HAS_THREAD
    SCENE ||--o{ SCENE : NEXT

    %% Events
    SCENE ||--o{ EVENT : HAS_EVENT
    EVENT }o--o{ EVENT : CAUSES

    %% Entity derivation
    ENTITY_CONCRETA }o--o| ENTITY_AXIOMATICA : DERIVES_FROM

    %% Entity relationships
    ENTITY_CONCRETA }o--o{ ENTITY_CONCRETA : LOCATED_IN
    ENTITY_CONCRETA }o--o{ ENTITY_CONCRETA : MEMBER_OF
    ENTITY_CONCRETA }o--o{ ENTITY_CONCRETA : ALLY_OF
    ENTITY_CONCRETA }o--o{ ENTITY_CONCRETA : ENEMY_OF
    ENTITY_CONCRETA }o--o{ ENTITY_CONCRETA : OWNS

    %% Participation
    ENTITY_CONCRETA }o--o{ SCENE : PARTICIPATED_IN
    ENTITY_CONCRETA }o--o{ EVENT : INVOLVED_IN
    ENTITY_CONCRETA }o--o{ FACT : INVOLVED_IN

    %% Plot threads
    PLOTTHREAD }o--o{ SCENE : ADVANCED_BY
    PLOTTHREAD }o--o{ ENTITY_CONCRETA : INVOLVES

    %% Provenance (evidence)
    FACT }o--o{ SOURCE : SUPPORTED_BY
    FACT }o--o{ SCENE : SUPPORTED_BY
    EVENT }o--o{ SOURCE : SUPPORTED_BY
    EVENT }o--o{ SCENE : SUPPORTED_BY
    AXIOM }o--o{ SOURCE : SUPPORTED_BY

    %% Retcon
    FACT }o--o| FACT : REPLACES
Loading

Key Notes:

  • All nodes have canon_level and confidence for graduated canonization
  • SUPPORTED_BY edges provide evidence/provenance
  • REPLACES allows safe retcons
  • Scene nodes are optional (only created if needed for continuity)

2. MongoDB Narrative Layer (Documents)

This is the narrative artifacts layer - scenes, turns, proposals, memories.

erDiagram
    SCENES {
        objectid _id PK
        uuid scene_id UK
        uuid story_id FK
        uuid universe_id FK
        string title
        string purpose
        enum status
        uuid location_ref FK
        array participating_entities FK
        array turns
        array proposed_changes FK
        array canonical_outcomes FK
        string summary
        timestamp created_at
        timestamp updated_at
        timestamp completed_at
    }

    TURNS {
        objectid _id PK
        uuid turn_id UK
        uuid scene_id FK
        enum speaker
        uuid entity_id FK
        string text
        array proposed_changes FK
        uuid resolution_ref FK
        timestamp timestamp
    }

    PROPOSED_CHANGES {
        objectid _id PK
        uuid proposal_id UK
        uuid scene_id FK
        uuid turn_id FK
        enum type
        map content
        array evidence
        float confidence
        enum authority
        enum status
        string rationale
        uuid canonical_id
        timestamp created_at
        timestamp evaluated_at
    }

    RESOLUTIONS {
        objectid _id PK
        uuid resolution_id UK
        uuid turn_id FK
        uuid scene_id FK
        string action
        enum resolution_type
        map mechanics
        enum success_level
        array effects
        timestamp created_at
    }

    CHARACTER_MEMORIES {
        objectid _id PK
        uuid memory_id UK
        uuid entity_id FK
        string text
        uuid linked_fact_id FK
        uuid scene_id FK
        float emotional_valence
        float importance
        float certainty
        timestamp created_at
        timestamp last_accessed
        int access_count
    }

    DOCUMENTS {
        objectid _id PK
        uuid doc_id UK
        uuid source_id FK
        uuid universe_id FK
        string minio_ref
        string title
        string filename
        string file_type
        enum extraction_status
        timestamp created_at
        timestamp extracted_at
    }

    SNIPPETS {
        objectid _id PK
        uuid snippet_id UK
        uuid doc_id FK
        uuid source_id FK
        string text
        int page
        string section
        int chunk_index
        timestamp created_at
    }

    CHARACTER_SHEETS {
        objectid _id PK
        uuid character_sheet_id UK
        uuid entity_id FK
        map stats
        map resources
        array history_log
        timestamp created_at
        timestamp updated_at
    }

    STORY_OUTLINES {
        objectid _id PK
        uuid story_id FK
        string theme
        string premise
        array constraints
        array beats
        array open_threads
        timestamp created_at
        timestamp updated_at
    }

    %% Scene relationships
    SCENES ||--o{ TURNS : contains
    SCENES ||--o{ PROPOSED_CHANGES : has_proposals
    TURNS ||--o{ PROPOSED_CHANGES : proposes
    TURNS }o--o| RESOLUTIONS : has_resolution

    %% Document structure
    DOCUMENTS ||--o{ SNIPPETS : contains

    %% References to Neo4j (shown as FK)
    SCENES }o--|| STORY_OUTLINES : belongs_to
    CHARACTER_MEMORIES }o--|| CHARACTER_SHEETS : entity_memory
Loading

Key Notes:

  • scene_id, story_id, entity_id etc. are references to Neo4j UUIDs
  • proposed_changes array stores proposal_ids
  • canonical_outcomes stores Neo4j Fact/Event IDs
  • status tracks workflow (active → finalizing → completed)

3. Qdrant Semantic Index Layer (Vectors)

This is the derived index layer - embeddings for retrieval.

Collection: scene_chunks
  ├─ id: uuid
  ├─ vector: [1536 floats]
  └─ payload:
       ├─ scene_id → references MongoDB scenes.scene_id
       ├─ story_id → references Neo4j Story.id
       ├─ universe_id → references Neo4j Universe.id
       ├─ text: string
       ├─ type: "scene_summary" | "turn"
       └─ timestamp: iso8601

Collection: memory_chunks
  ├─ id: uuid
  ├─ vector: [1536 floats]
  └─ payload:
       ├─ memory_id → references MongoDB character_memories.memory_id
       ├─ entity_id → references Neo4j EntityInstance.id
       ├─ text: string
       ├─ importance: float
       └─ timestamp: iso8601

Collection: snippet_chunks
  ├─ id: uuid
  ├─ vector: [1536 floats]
  └─ payload:
       ├─ snippet_id → references MongoDB snippets.snippet_id
       ├─ doc_id → references MongoDB documents.doc_id
       ├─ source_id → references Neo4j Source.id
       ├─ universe_id → references Neo4j Universe.id
       ├─ text: string
       ├─ page: int
       └─ section: string

Key Notes:

  • Qdrant is never authoritative - always points to Neo4j or MongoDB
  • Indices can be rebuilt from source data
  • Filters use payload metadata (universe_id, importance, etc.)

4. Cross-Layer Reference Flow

┌─────────────────────────────────────────────────────────┐
│                      USER INPUT                         │
└────────────────────────┬────────────────────────────────┘
                         │
                         ▼
              ┌──────────────────────┐
              │   MONGODB: Turn      │
              │   (narrative log)    │
              └──────────┬───────────┘
                         │
                         ▼
              ┌──────────────────────┐
              │ MONGODB: Proposed    │
              │ Change (staging)     │
              └──────────┬───────────┘
                         │
                    [canonization gate]
                         │
                         ▼
              ┌──────────────────────┐
              │   NEO4J: Fact/Event  │
              │   (canonical truth)  │
              └──────────┬───────────┘
                         │
                         ▼
              ┌──────────────────────┐
              │ QDRANT: Embedding    │
              │ (semantic index)     │
              └──────────────────────┘

Key principle: Data flows MongoDB → Neo4j → Qdrant. Never Neo4j → MongoDB.


5. Entity-Type Specific Properties

EntityInstance.properties by entity_type

character:

{
  "role": "PC | NPC | antagonist | ally",
  "archetype": "wizard | warrior | ...",
  "tags": ["alive", "wounded", "hostile"]
}

faction:

{
  "faction_kind": "political | military | religious",
  "scope": "local | regional | global"
}

location:

{
  "location_type": "city | building | region | planet",
  "is_exterior": true
}

object:

{
  "object_kind": "weapon | artifact | tool",
  "is_magical": true,
  "is_unique": true
}

concept:

{
  "concept_kind": "belief | law | force",
  "is_abstract": true
}

organization:

{
  "org_kind": "guild | company | cult",
  "is_hierarchical": true
}

6. Enumerations

canon_level (Standard)

Used by: Axiom, EntityArchetype, EntityInstance, Fact, Event, Universe

  • proposed - suggested but not accepted
  • canon - accepted as truth
  • retconned - superseded by newer version

canon_level (Source)

Used by: Source nodes only

  • proposed - source uploaded but not verified
  • canon - source accepted as valid reference
  • authoritative - official/primary source (highest trust, e.g., D&D PHB)

Note: Sources use authoritative instead of retconned because source documents themselves don't get revised—only facts derived from them can be retconned.

authority (Standard)

Used by: Fact, Event, EntityArchetype, EntityInstance

  • source - from manual/document
  • gm - explicit GM declaration
  • player - from player action via resolution
  • system - inferred by system

authority (Axiom)

Used by: Axiom only

  • source - from manual/document
  • gm - explicit GM declaration
  • system - inferred by system

Note: Axioms exclude player because world rules (physics, magic systems) cannot be created by player actions—only by GM declaration or authoritative sources.

story_type

  • campaign - long-form multi-arc
  • arc - story arc within campaign
  • episode - single episode
  • one_shot - standalone session

status (Story)

  • planned - not yet started
  • active - currently running
  • completed - finished
  • abandoned - discontinued

status (Scene - MongoDB)

  • active - currently running, turns being added
  • finalizing - canonization in progress
  • completed - canonized and closed

status (ProposedChange)

  • pending - awaiting evaluation
  • accepted - canonized to Neo4j
  • rejected - not canonized

entity_type

  • character
  • faction
  • location
  • object
  • concept
  • organization

speaker (Turn)

  • user - player out-of-character
  • gm - game master
  • entity - in-character (entity_id required)

7. Index Strategy

Neo4j Constraints

CREATE CONSTRAINT entity_concreta_id ON (n:EntityInstance) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT entity_axiomatica_id ON (n:EntityArchetype) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT universe_id ON (n:Universe) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT story_id ON (n:Story) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT fact_id ON (n:Fact) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT event_id ON (n:Event) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT source_id ON (n:Source) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT axiom_id ON (n:Axiom) ASSERT n.id IS UNIQUE;

Neo4j Indexes

CREATE INDEX entity_universe ON :EntityInstance(universe_id);
CREATE INDEX fact_universe ON :Fact(universe_id);
CREATE INDEX fact_canon_level ON :Fact(canon_level);
CREATE INDEX story_universe ON :Story(universe_id);

MongoDB Indexes

// scenes
db.scenes.createIndex({ scene_id: 1 }, { unique: true });
db.scenes.createIndex({ story_id: 1, order: 1 });
db.scenes.createIndex({ status: 1 });

// proposed_changes
db.proposed_changes.createIndex({ proposal_id: 1 }, { unique: true });
db.proposed_changes.createIndex({ scene_id: 1, status: 1 });
db.proposed_changes.createIndex({ status: 1 });

// turns (if separate collection)
db.turns.createIndex({ turn_id: 1 }, { unique: true });
db.turns.createIndex({ scene_id: 1, timestamp: 1 });

// character_memories
db.character_memories.createIndex({ memory_id: 1 }, { unique: true });
db.character_memories.createIndex({ entity_id: 1, importance: -1 });

// snippets
db.snippets.createIndex({ snippet_id: 1 }, { unique: true });
db.snippets.createIndex({ doc_id: 1, chunk_index: 1 });

Qdrant Indexes

# Payload indexes for filtering
client.create_payload_index(
    collection_name="scene_chunks",
    field_name="universe_id",
    field_schema="keyword"
)

client.create_payload_index(
    collection_name="memory_chunks",
    field_name="entity_id",
    field_schema="keyword"
)

client.create_payload_index(
    collection_name="snippet_chunks",
    field_name="source_id",
    field_schema="keyword"
)

References

Clone this wiki locally