The Problem With Flat Document Storage
You've got 200 documents scattered across your workspace. Some are contracts. Some are meeting notes. Some reference other documents. When you search for "Q4 budget," you get a list of files—but the system doesn't understand that the budget document relates to the stakeholder memo from last month, which references the finance policy, which was authored by Sarah.
Most document systems treat files as islands. They index text, they tag metadata, but they don't capture the relationships that actually matter. That's where your knowledge lives: not in individual documents, but in the connections between them.
AiFiler's knowledge graph solves this by treating relationships as first-class citizens. Instead of storing documents and hoping search finds them, we store the connections between documents, people, projects, and concepts. Then we query those connections.
The 8-Edge-Type System
At the core of AiFiler's knowledge graph are eight relationship types—edges—that describe how entities connect:
- AUTHORED_BY: Document → Person. "This contract was written by Sarah."
- REFERENCES: Document → Document. "This memo references the Q3 budget."
- TAGS: Document → Concept/Tag. "This file is tagged 'confidential.'"
- BELONGS_TO: Document → Project/Workspace. "This file belongs to the Q4 Initiative."
- RELATED_TO: Document → Document. "This is related to that analysis."
- MENTIONS: Document → Person/Entity. "This document mentions the CEO."
- DEPENDS_ON: Document → Document. "This deliverable depends on that research."
- VERSION_OF: Document → Document. "This is version 2 of that proposal."
Each edge is directional and weighted. A document that heavily references another gets a higher weight than a passing mention. This matters because when you search, AiFiler doesn't just find exact matches—it traverses the graph and ranks results by connection strength.
How Data Flows Through the System
Here's the architecture in practice:
Ingestion → Parsing → Extraction → Graph Construction → Indexing → Query
When you upload a document to AiFiler, it doesn't just land in a bucket. The system:
-
Parses the file using skill modules (
lib/ingest/parseFile.ts). For DOCX, XLSX, PPTX, the parser extracts text, metadata, and structure. -
Extracts entities and relationships using Claude's vision and reasoning. The AI identifies people, projects, dates, and implicit connections. "This memo discusses the budget" becomes a REFERENCES edge.
-
Constructs graph nodes in Supabase. Each document gets a node. Each person mentioned gets a node. Each project gets a node.
-
Creates edges between nodes based on extracted relationships. The weight is determined by confidence scores from the AI extraction.
-
Indexes for search using Supabase's full-text search, but with graph-aware ranking. When you search "budget," the system finds documents tagged with budget, documents that reference budget documents, and documents authored by people who work on budget projects.
The key architectural decision: we separate the graph structure from the search index. The graph lives in Supabase as relational data. The search index is a denormalized view optimized for fast retrieval. This lets us update relationships without rebuilding the entire search index.
Why Separate Graph Storage From Search Index?
Early iterations of AiFiler tried to do everything in one layer. We'd update a relationship and immediately re-index. It worked for small workspaces but broke at scale.
The problem: relationship updates are frequent, but search queries are even more frequent. If every relationship change triggers a full re-index, you're constantly blocking read operations.
The solution: write to the graph, eventually propagate to the index.
Document Upload
↓
Parse & Extract (AI)
↓
Write Nodes & Edges to Graph (Supabase)
↓
Async: Update Search Index (eventual consistency)
↓
Query can read from Index immediately
↓
Graph remains source of truth for relationships
This means there's a small window where the search index might be slightly stale, but queries remain fast. For most use cases—finding documents, exploring connections—eventual consistency is fine. For critical operations (like deleting a document), we query the graph directly.
The Traversal Algorithm
When you use Universal Command (Ctrl+Shift+A) to ask "show me all documents related to the Q4 budget," AiFiler doesn't just search for "Q4 budget." It:
- Finds the Q4 budget document (or project node).
- Traverses outgoing edges: what documents reference it? What documents does it reference?
- Traverses one level deeper: what documents reference those documents?
- Ranks results by edge weight and traversal depth.
- Returns the top N results, sorted by relevance.
The traversal stops at a configurable depth (typically 2-3 hops) to avoid returning the entire graph. This keeps query time predictable even in large workspaces.
Budget Document (node)
├─ REFERENCED_BY: Memo A, Memo B, Report C
├─ REFERENCES: Policy X, Historical Budget Y
└─ BELONGS_TO: Q4 Initiative (node)
├─ AUTHORED_BY: Sarah, James
└─ TAGS: Confidential, Finance
From this single traversal, you get context: not just the budget document, but everything connected to it, organized by relationship type.
Why This Matters for You
The knowledge graph changes how you work with documents. Instead of searching, you explore.
Before: You search "stakeholder feedback." You get 47 results. You click through them one by one.
After: You search "stakeholder feedback." AiFiler shows you the primary feedback document, the documents it references, the people who authored it, and the projects it belongs to. You see the context immediately.
This is especially powerful for teams managing client deliverables. When you open a proposal, you don't just see the proposal. You see the research that informed it, the stakeholder conversations that shaped it, the previous versions, and the related proposals. All without leaving the document.
The architecture also makes AI assistance smarter. When you ask the Universal Command to "summarize everything related to this contract," Claude can traverse the graph, pull in related documents, and generate a summary that reflects the full context—not just the contract itself.
The Cost of This Approach
Storing relationships explicitly is more expensive than storing documents alone. Each edge requires a database row. A document with 50 relationships creates 50 rows. At scale, that's a lot of data.
We mitigate this by:
- Pruning low-weight edges: Relationships below a confidence threshold are dropped.
- Compressing old relationships: Historical edges are archived after 90 days.
- Batch-writing edges: We don't write one edge at a time; we batch them in groups of 100+.
The trade-off is worth it. Query speed matters more than storage cost, especially for knowledge workers who search dozens of times per day.
What's Next
The current system handles 8 edge types well. We're exploring ways to add custom edge types—letting teams define their own relationships. Imagine a legal team adding an "INDEMNIFIES" edge type, or a product team adding a "BLOCKS" edge type.
We're also working on real-time graph updates. Right now, relationship extraction happens asynchronously after upload. Soon, you'll see relationships populate as you edit documents, giving you live context as you work.
The knowledge graph isn't just infrastructure. It's the foundation for how AiFiler understands your work. Every feature we build—search, recommendations, AI assistance—flows through this architecture. Understanding it helps you understand why AiFiler works the way it does.
Enjoyed this article?
Get more articles like this delivered to your inbox. No spam, unsubscribe anytime.