feat: brain service — self-contained second brain knowledge manager

Full backend service with:
- FastAPI REST API with CRUD, search, reprocess endpoints
- PostgreSQL + pgvector for items and semantic search
- Redis + RQ for background job processing
- Meilisearch for fast keyword/filter search
- Browserless/Chrome for JS rendering and screenshots
- OpenAI structured output for AI classification
- Local file storage with S3-ready abstraction
- Gateway auth via X-Gateway-User-Id header
- Own docker-compose stack (6 containers)

Classification: fixed folders (Home/Family/Work/Travel/Knowledge/Faith/Projects)
and fixed tags (28 predefined). AI assigns exactly 1 folder, 2-3 tags, title,
summary, and confidence score per item.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yusuf Suleman
2026-04-01 11:48:29 -05:00
parent 51a8157fd4
commit 8275f3a71b
73 changed files with 24081 additions and 4209 deletions

View File

@@ -0,0 +1,56 @@
-- Brain service schema — PostgreSQL + pgvector
-- This is a reference migration. Tables are auto-created by SQLAlchemy on startup.
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE IF NOT EXISTS items (
id UUID PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
type VARCHAR(32) NOT NULL DEFAULT 'link',
title TEXT,
url TEXT,
raw_content TEXT,
extracted_text TEXT,
folder VARCHAR(64),
tags TEXT[],
summary TEXT,
confidence FLOAT,
metadata_json JSONB DEFAULT '{}',
processing_status VARCHAR(32) NOT NULL DEFAULT 'pending',
processing_error TEXT,
embedding vector(1536),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_items_user_status ON items(user_id, processing_status);
CREATE INDEX IF NOT EXISTS ix_items_user_folder ON items(user_id, folder);
CREATE INDEX IF NOT EXISTS ix_items_created ON items(created_at);
-- HNSW index for fast approximate nearest neighbor search
CREATE INDEX IF NOT EXISTS ix_items_embedding ON items
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
CREATE TABLE IF NOT EXISTS item_assets (
id UUID PRIMARY KEY,
item_id UUID NOT NULL REFERENCES items(id) ON DELETE CASCADE,
asset_type VARCHAR(32) NOT NULL,
filename VARCHAR(512) NOT NULL,
content_type VARCHAR(128),
size_bytes INTEGER,
storage_path VARCHAR(1024) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_item_assets_item ON item_assets(item_id);
CREATE TABLE IF NOT EXISTS app_links (
id UUID PRIMARY KEY,
item_id UUID NOT NULL REFERENCES items(id) ON DELETE CASCADE,
app VARCHAR(64) NOT NULL,
app_entity_id VARCHAR(128) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_app_links_item ON app_links(item_id);