@twelvehart/supermemory-runtime 1.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +57 -0
- package/README.md +374 -0
- package/dist/index.js +189 -0
- package/dist/mcp/index.js +1132 -0
- package/docker-compose.prod.yml +91 -0
- package/docker-compose.yml +358 -0
- package/drizzle/0000_dapper_the_professor.sql +159 -0
- package/drizzle/0001_api_keys.sql +51 -0
- package/drizzle/meta/0000_snapshot.json +1532 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +20 -0
- package/package.json +114 -0
- package/scripts/add-extraction-job.ts +122 -0
- package/scripts/benchmark-pgvector.ts +122 -0
- package/scripts/bootstrap.sh +209 -0
- package/scripts/check-runtime-pack.ts +111 -0
- package/scripts/claude-mcp-config.ts +336 -0
- package/scripts/docker-entrypoint.sh +183 -0
- package/scripts/doctor.ts +377 -0
- package/scripts/init-db.sql +33 -0
- package/scripts/install.sh +1110 -0
- package/scripts/mcp-setup.ts +271 -0
- package/scripts/migrations/001_create_pgvector_extension.sql +31 -0
- package/scripts/migrations/002_create_memory_embeddings_table.sql +75 -0
- package/scripts/migrations/003_create_hnsw_index.sql +94 -0
- package/scripts/migrations/004_create_memory_embeddings_standalone.sql +70 -0
- package/scripts/migrations/005_create_chunks_table.sql +95 -0
- package/scripts/migrations/006_create_processing_queue.sql +45 -0
- package/scripts/migrations/generate_test_data.sql +42 -0
- package/scripts/migrations/phase1_comprehensive_test.sql +204 -0
- package/scripts/migrations/run_migrations.sh +286 -0
- package/scripts/migrations/test_hnsw_index.sql +255 -0
- package/scripts/pre-commit-secrets +282 -0
- package/scripts/run-extraction-worker.ts +46 -0
- package/scripts/run-phase1-tests.sh +291 -0
- package/scripts/setup.ts +222 -0
- package/scripts/smoke-install.sh +12 -0
- package/scripts/test-health-endpoint.sh +328 -0
- package/src/api/index.ts +2 -0
- package/src/api/middleware/auth.ts +80 -0
- package/src/api/middleware/csrf.ts +308 -0
- package/src/api/middleware/errorHandler.ts +166 -0
- package/src/api/middleware/rateLimit.ts +360 -0
- package/src/api/middleware/validation.ts +514 -0
- package/src/api/routes/documents.ts +286 -0
- package/src/api/routes/profiles.ts +237 -0
- package/src/api/routes/search.ts +71 -0
- package/src/api/stores/index.ts +58 -0
- package/src/config/bootstrap-env.ts +3 -0
- package/src/config/env.ts +71 -0
- package/src/config/feature-flags.ts +25 -0
- package/src/config/index.ts +140 -0
- package/src/config/secrets.config.ts +291 -0
- package/src/db/client.ts +92 -0
- package/src/db/index.ts +73 -0
- package/src/db/postgres.ts +72 -0
- package/src/db/schema/chunks.schema.ts +31 -0
- package/src/db/schema/containers.schema.ts +46 -0
- package/src/db/schema/documents.schema.ts +49 -0
- package/src/db/schema/embeddings.schema.ts +32 -0
- package/src/db/schema/index.ts +11 -0
- package/src/db/schema/memories.schema.ts +72 -0
- package/src/db/schema/profiles.schema.ts +34 -0
- package/src/db/schema/queue.schema.ts +59 -0
- package/src/db/schema/relationships.schema.ts +42 -0
- package/src/db/schema.ts +223 -0
- package/src/db/worker-connection.ts +47 -0
- package/src/index.ts +235 -0
- package/src/mcp/CLAUDE.md +1 -0
- package/src/mcp/index.ts +1380 -0
- package/src/mcp/legacyState.ts +22 -0
- package/src/mcp/rateLimit.ts +358 -0
- package/src/mcp/resources.ts +309 -0
- package/src/mcp/results.ts +104 -0
- package/src/mcp/tools.ts +401 -0
- package/src/queues/config.ts +119 -0
- package/src/queues/index.ts +289 -0
- package/src/sdk/client.ts +225 -0
- package/src/sdk/errors.ts +266 -0
- package/src/sdk/http.ts +560 -0
- package/src/sdk/index.ts +244 -0
- package/src/sdk/resources/base.ts +65 -0
- package/src/sdk/resources/connections.ts +204 -0
- package/src/sdk/resources/documents.ts +163 -0
- package/src/sdk/resources/index.ts +10 -0
- package/src/sdk/resources/memories.ts +150 -0
- package/src/sdk/resources/search.ts +60 -0
- package/src/sdk/resources/settings.ts +36 -0
- package/src/sdk/types.ts +674 -0
- package/src/services/chunking/index.ts +451 -0
- package/src/services/chunking.service.ts +650 -0
- package/src/services/csrf.service.ts +252 -0
- package/src/services/documents.repository.ts +219 -0
- package/src/services/documents.service.ts +191 -0
- package/src/services/embedding.service.ts +404 -0
- package/src/services/extraction.service.ts +300 -0
- package/src/services/extractors/code.extractor.ts +451 -0
- package/src/services/extractors/index.ts +9 -0
- package/src/services/extractors/markdown.extractor.ts +461 -0
- package/src/services/extractors/pdf.extractor.ts +315 -0
- package/src/services/extractors/text.extractor.ts +118 -0
- package/src/services/extractors/url.extractor.ts +243 -0
- package/src/services/index.ts +235 -0
- package/src/services/ingestion.service.ts +177 -0
- package/src/services/llm/anthropic.ts +400 -0
- package/src/services/llm/base.ts +460 -0
- package/src/services/llm/contradiction-detector.service.ts +526 -0
- package/src/services/llm/heuristics.ts +148 -0
- package/src/services/llm/index.ts +309 -0
- package/src/services/llm/memory-classifier.service.ts +383 -0
- package/src/services/llm/memory-extension-detector.service.ts +523 -0
- package/src/services/llm/mock.ts +470 -0
- package/src/services/llm/openai.ts +398 -0
- package/src/services/llm/prompts.ts +438 -0
- package/src/services/llm/types.ts +373 -0
- package/src/services/memory.repository.ts +1769 -0
- package/src/services/memory.service.ts +1338 -0
- package/src/services/memory.types.ts +234 -0
- package/src/services/persistence/index.ts +295 -0
- package/src/services/pipeline.service.ts +509 -0
- package/src/services/profile.repository.ts +436 -0
- package/src/services/profile.service.ts +560 -0
- package/src/services/profile.types.ts +270 -0
- package/src/services/relationships/detector.ts +1128 -0
- package/src/services/relationships/index.ts +268 -0
- package/src/services/relationships/memory-integration.ts +459 -0
- package/src/services/relationships/strategies.ts +132 -0
- package/src/services/relationships/types.ts +370 -0
- package/src/services/search.service.ts +761 -0
- package/src/services/search.types.ts +220 -0
- package/src/services/secrets.service.ts +384 -0
- package/src/services/vectorstore/base.ts +327 -0
- package/src/services/vectorstore/index.ts +444 -0
- package/src/services/vectorstore/memory.ts +286 -0
- package/src/services/vectorstore/migration.ts +295 -0
- package/src/services/vectorstore/mock.ts +403 -0
- package/src/services/vectorstore/pgvector.ts +695 -0
- package/src/services/vectorstore/types.ts +247 -0
- package/src/startup.ts +389 -0
- package/src/types/api.types.ts +193 -0
- package/src/types/document.types.ts +103 -0
- package/src/types/index.ts +241 -0
- package/src/types/profile.base.ts +133 -0
- package/src/utils/errors.ts +447 -0
- package/src/utils/id.ts +15 -0
- package/src/utils/index.ts +101 -0
- package/src/utils/logger.ts +313 -0
- package/src/utils/sanitization.ts +501 -0
- package/src/utils/secret-validation.ts +273 -0
- package/src/utils/synonyms.ts +188 -0
- package/src/utils/validation.ts +581 -0
- package/src/workers/chunking.worker.ts +242 -0
- package/src/workers/embedding.worker.ts +358 -0
- package/src/workers/extraction.worker.ts +346 -0
- package/src/workers/indexing.worker.ts +505 -0
- package/tsconfig.json +38 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# SuperMemory Clone - Docker Compose Production Override
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# This file extends docker-compose.yml for production deployment:
|
|
5
|
+
# - PostgreSQL with pgvector for vector search
|
|
6
|
+
# - Redis for caching and job queues (BullMQ)
|
|
7
|
+
# - ChromaDB for scalable vector search (optional)
|
|
8
|
+
# - Full resource limits enabled
|
|
9
|
+
# - Persistent volumes
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# # Full production stack (API + PostgreSQL + Redis):
|
|
13
|
+
# docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile production up -d
|
|
14
|
+
#
|
|
15
|
+
# # With ChromaDB vector store:
|
|
16
|
+
# docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile production --profile chroma up -d
|
|
17
|
+
#
|
|
18
|
+
# # With worker:
|
|
19
|
+
# docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile production --profile worker up -d
|
|
20
|
+
#
|
|
21
|
+
# # View logs:
|
|
22
|
+
# docker compose -f docker-compose.yml -f docker-compose.prod.yml logs -f api
|
|
23
|
+
#
|
|
24
|
+
# # Stop all services:
|
|
25
|
+
# docker compose -f docker-compose.yml -f docker-compose.prod.yml down
|
|
26
|
+
#
|
|
27
|
+
# # Stop and remove volumes (WARNING: deletes data):
|
|
28
|
+
# docker compose -f docker-compose.yml -f docker-compose.prod.yml down -v
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
services:
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
# API Service - Production configuration
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
api:
|
|
36
|
+
environment:
|
|
37
|
+
- NODE_ENV=production
|
|
38
|
+
- API_HOST=0.0.0.0
|
|
39
|
+
- API_PORT=3000
|
|
40
|
+
# Database connection (PostgreSQL)
|
|
41
|
+
- DATABASE_URL=postgresql://supermemory:supermemory_secret@postgres:5432/supermemory
|
|
42
|
+
# Redis connection
|
|
43
|
+
- REDIS_URL=redis://redis:6379
|
|
44
|
+
# These should be provided via .env file or secrets
|
|
45
|
+
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
|
46
|
+
- AUTH_ENABLED=${AUTH_ENABLED:-false}
|
|
47
|
+
- AUTH_TOKEN=${AUTH_TOKEN:-}
|
|
48
|
+
- EMBEDDING_MODEL=${EMBEDDING_MODEL:-text-embedding-3-small}
|
|
49
|
+
- EMBEDDING_DIMENSIONS=${EMBEDDING_DIMENSIONS:-1536}
|
|
50
|
+
# Vector Store Configuration
|
|
51
|
+
- VECTOR_STORE_PROVIDER=${VECTOR_STORE_PROVIDER:-memory}
|
|
52
|
+
- VECTOR_DIMENSIONS=${VECTOR_DIMENSIONS:-1536}
|
|
53
|
+
- CHROMA_URL=${CHROMA_URL:-http://chromadb:8000}
|
|
54
|
+
- CHROMA_COLLECTION=${CHROMA_COLLECTION:-supermemory_vectors}
|
|
55
|
+
# LLM Provider Configuration
|
|
56
|
+
- LLM_PROVIDER=${LLM_PROVIDER:-}
|
|
57
|
+
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
|
58
|
+
- LLM_MODEL=${LLM_MODEL:-}
|
|
59
|
+
- LLM_MAX_TOKENS=${LLM_MAX_TOKENS:-2000}
|
|
60
|
+
- LLM_CACHE_ENABLED=${LLM_CACHE_ENABLED:-true}
|
|
61
|
+
- LLM_CACHE_TTL_MS=${LLM_CACHE_TTL_MS:-900000}
|
|
62
|
+
- LOG_LEVEL=${LOG_LEVEL:-info}
|
|
63
|
+
- RATE_LIMIT_REQUESTS=${RATE_LIMIT_REQUESTS:-100}
|
|
64
|
+
- RATE_LIMIT_WINDOW_MS=${RATE_LIMIT_WINDOW_MS:-60000}
|
|
65
|
+
|
|
66
|
+
# In production, API depends on postgres and redis being healthy
|
|
67
|
+
depends_on:
|
|
68
|
+
postgres:
|
|
69
|
+
condition: service_healthy
|
|
70
|
+
redis:
|
|
71
|
+
condition: service_healthy
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
# Worker - Production configuration
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
worker:
|
|
77
|
+
environment:
|
|
78
|
+
- NODE_ENV=production
|
|
79
|
+
- DATABASE_URL=postgresql://supermemory:supermemory_secret@postgres:5432/supermemory
|
|
80
|
+
- REDIS_URL=redis://redis:6379
|
|
81
|
+
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
|
82
|
+
- AUTH_ENABLED=${AUTH_ENABLED:-false}
|
|
83
|
+
- AUTH_TOKEN=${AUTH_TOKEN:-}
|
|
84
|
+
- LOG_LEVEL=${LOG_LEVEL:-info}
|
|
85
|
+
|
|
86
|
+
# In production, worker depends on postgres and redis being healthy
|
|
87
|
+
depends_on:
|
|
88
|
+
postgres:
|
|
89
|
+
condition: service_healthy
|
|
90
|
+
redis:
|
|
91
|
+
condition: service_healthy
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# SuperMemory Clone - Docker Compose Base Configuration
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# This file defines the base service configurations.
|
|
5
|
+
# Services use profiles for flexible deployment:
|
|
6
|
+
#
|
|
7
|
+
# Development (SQLite only):
|
|
8
|
+
# docker compose -f docker-compose.yml -f docker-compose.dev.yml up
|
|
9
|
+
#
|
|
10
|
+
# Development with Redis:
|
|
11
|
+
# docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile redis up
|
|
12
|
+
#
|
|
13
|
+
# Production (requires docker-compose.prod.yml):
|
|
14
|
+
# docker compose -f docker-compose.yml -f docker-compose.prod.yml up
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
17
|
+
services:
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# API Service - Main SuperMemory Clone API
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
api:
|
|
22
|
+
build:
|
|
23
|
+
context: .
|
|
24
|
+
dockerfile: Dockerfile
|
|
25
|
+
container_name: supermemory-api
|
|
26
|
+
restart: unless-stopped
|
|
27
|
+
|
|
28
|
+
# Environment variables - base configuration
|
|
29
|
+
# Override in dev/prod compose files as needed
|
|
30
|
+
environment:
|
|
31
|
+
- NODE_ENV=production
|
|
32
|
+
- API_HOST=0.0.0.0
|
|
33
|
+
- API_PORT=3000
|
|
34
|
+
# These should be provided via .env file or secrets
|
|
35
|
+
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
|
36
|
+
- AUTH_ENABLED=${AUTH_ENABLED:-false}
|
|
37
|
+
- AUTH_TOKEN=${AUTH_TOKEN:-}
|
|
38
|
+
- CSRF_SECRET=${CSRF_SECRET:-}
|
|
39
|
+
- SUPERMEMORY_ALLOW_GENERATED_LOCAL_SECRETS=${SUPERMEMORY_ALLOW_GENERATED_LOCAL_SECRETS:-true}
|
|
40
|
+
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-http://localhost:13000,http://localhost:15173}
|
|
41
|
+
- EMBEDDING_MODEL=${EMBEDDING_MODEL:-text-embedding-3-small}
|
|
42
|
+
- EMBEDDING_DIMENSIONS=${EMBEDDING_DIMENSIONS:-1536}
|
|
43
|
+
# Vector Store Configuration
|
|
44
|
+
- VECTOR_STORE_PROVIDER=${VECTOR_STORE_PROVIDER:-memory}
|
|
45
|
+
- VECTOR_DIMENSIONS=${VECTOR_DIMENSIONS:-1536}
|
|
46
|
+
- VECTOR_SQLITE_PATH=${VECTOR_SQLITE_PATH:-./data/vectors.db}
|
|
47
|
+
- CHROMA_URL=${CHROMA_URL:-http://chromadb:8000}
|
|
48
|
+
- CHROMA_COLLECTION=${CHROMA_COLLECTION:-supermemory_vectors}
|
|
49
|
+
# Redis Configuration
|
|
50
|
+
- REDIS_HOST=${REDIS_HOST:-redis}
|
|
51
|
+
- REDIS_PORT=${REDIS_PORT:-6379}
|
|
52
|
+
# BullMQ Queue Configuration
|
|
53
|
+
- BULLMQ_CONCURRENCY_EXTRACTION=${BULLMQ_CONCURRENCY_EXTRACTION:-5}
|
|
54
|
+
- BULLMQ_CONCURRENCY_CHUNKING=${BULLMQ_CONCURRENCY_CHUNKING:-3}
|
|
55
|
+
- BULLMQ_CONCURRENCY_EMBEDDING=${BULLMQ_CONCURRENCY_EMBEDDING:-2}
|
|
56
|
+
- BULLMQ_CONCURRENCY_INDEXING=${BULLMQ_CONCURRENCY_INDEXING:-1}
|
|
57
|
+
# LLM Provider Configuration (optional - for memory extraction)
|
|
58
|
+
- LLM_PROVIDER=${LLM_PROVIDER:-}
|
|
59
|
+
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
|
60
|
+
- LLM_MODEL=${LLM_MODEL:-}
|
|
61
|
+
- LLM_MAX_TOKENS=${LLM_MAX_TOKENS:-2000}
|
|
62
|
+
- LLM_TEMPERATURE=${LLM_TEMPERATURE:-0.1}
|
|
63
|
+
- LLM_TIMEOUT_MS=${LLM_TIMEOUT_MS:-30000}
|
|
64
|
+
- LLM_MAX_RETRIES=${LLM_MAX_RETRIES:-3}
|
|
65
|
+
- LLM_CACHE_ENABLED=${LLM_CACHE_ENABLED:-true}
|
|
66
|
+
- LLM_CACHE_TTL_MS=${LLM_CACHE_TTL_MS:-900000}
|
|
67
|
+
- LOG_LEVEL=${LOG_LEVEL:-info}
|
|
68
|
+
- RATE_LIMIT_REQUESTS=${RATE_LIMIT_REQUESTS:-100}
|
|
69
|
+
- RATE_LIMIT_WINDOW_MS=${RATE_LIMIT_WINDOW_MS:-60000}
|
|
70
|
+
|
|
71
|
+
ports:
|
|
72
|
+
- "${API_HOST_PORT:-13000}:3000"
|
|
73
|
+
|
|
74
|
+
# No depends_on in base - override in prod compose file
|
|
75
|
+
# This allows dev mode to work without postgres/redis
|
|
76
|
+
|
|
77
|
+
# Health check configuration
|
|
78
|
+
healthcheck:
|
|
79
|
+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/health"]
|
|
80
|
+
interval: 30s
|
|
81
|
+
timeout: 10s
|
|
82
|
+
retries: 3
|
|
83
|
+
start_period: 10s
|
|
84
|
+
|
|
85
|
+
# Resource limits to prevent runaway processes
|
|
86
|
+
deploy:
|
|
87
|
+
resources:
|
|
88
|
+
limits:
|
|
89
|
+
cpus: '2'
|
|
90
|
+
memory: 1G
|
|
91
|
+
reservations:
|
|
92
|
+
cpus: '0.5'
|
|
93
|
+
memory: 256M
|
|
94
|
+
|
|
95
|
+
networks:
|
|
96
|
+
- supermemory-network
|
|
97
|
+
|
|
98
|
+
# Logging configuration
|
|
99
|
+
logging:
|
|
100
|
+
driver: "json-file"
|
|
101
|
+
options:
|
|
102
|
+
max-size: "10m"
|
|
103
|
+
max-file: "3"
|
|
104
|
+
|
|
105
|
+
# ---------------------------------------------------------------------------
|
|
106
|
+
# PostgreSQL with pgvector - Vector database for embeddings
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
# Only started when postgres profile is active or via prod compose
|
|
109
|
+
postgres:
|
|
110
|
+
image: pgvector/pgvector:pg16
|
|
111
|
+
container_name: supermemory-postgres
|
|
112
|
+
restart: unless-stopped
|
|
113
|
+
|
|
114
|
+
environment:
|
|
115
|
+
- POSTGRES_USER=supermemory
|
|
116
|
+
- POSTGRES_PASSWORD=supermemory_secret
|
|
117
|
+
- POSTGRES_DB=supermemory
|
|
118
|
+
# Performance tuning
|
|
119
|
+
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
|
|
120
|
+
|
|
121
|
+
ports:
|
|
122
|
+
- "${POSTGRES_HOST_PORT:-15432}:5432"
|
|
123
|
+
|
|
124
|
+
# Persistent storage for database
|
|
125
|
+
volumes:
|
|
126
|
+
- postgres_data:/var/lib/postgresql/data
|
|
127
|
+
# Mount initialization script for pgvector extension setup
|
|
128
|
+
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
|
|
129
|
+
# Mount migration scripts for easy access
|
|
130
|
+
- ./scripts/migrations:/migrations:ro
|
|
131
|
+
|
|
132
|
+
# Health check to verify PostgreSQL is ready
|
|
133
|
+
healthcheck:
|
|
134
|
+
test: ["CMD-SHELL", "pg_isready -U supermemory -d supermemory"]
|
|
135
|
+
interval: 10s
|
|
136
|
+
timeout: 5s
|
|
137
|
+
retries: 5
|
|
138
|
+
start_period: 10s
|
|
139
|
+
|
|
140
|
+
# Resource limits
|
|
141
|
+
deploy:
|
|
142
|
+
resources:
|
|
143
|
+
limits:
|
|
144
|
+
cpus: '2'
|
|
145
|
+
memory: 2G
|
|
146
|
+
reservations:
|
|
147
|
+
cpus: '0.25'
|
|
148
|
+
memory: 256M
|
|
149
|
+
|
|
150
|
+
networks:
|
|
151
|
+
- supermemory-network
|
|
152
|
+
|
|
153
|
+
logging:
|
|
154
|
+
driver: "json-file"
|
|
155
|
+
options:
|
|
156
|
+
max-size: "10m"
|
|
157
|
+
max-file: "3"
|
|
158
|
+
|
|
159
|
+
# PostgreSQL is optional - use profile to enable
|
|
160
|
+
profiles:
|
|
161
|
+
- postgres
|
|
162
|
+
- production
|
|
163
|
+
|
|
164
|
+
# ---------------------------------------------------------------------------
|
|
165
|
+
# Redis - Caching and job queue (BullMQ)
|
|
166
|
+
# ---------------------------------------------------------------------------
|
|
167
|
+
# Only started when redis profile is active or via prod compose
|
|
168
|
+
redis:
|
|
169
|
+
image: redis:7-alpine
|
|
170
|
+
container_name: supermemory-redis
|
|
171
|
+
restart: unless-stopped
|
|
172
|
+
|
|
173
|
+
# Redis configuration for persistence and memory management
|
|
174
|
+
command: >
|
|
175
|
+
redis-server
|
|
176
|
+
--appendonly yes
|
|
177
|
+
--appendfsync everysec
|
|
178
|
+
--maxmemory 256mb
|
|
179
|
+
--maxmemory-policy allkeys-lru
|
|
180
|
+
|
|
181
|
+
ports:
|
|
182
|
+
- "${REDIS_HOST_PORT:-16379}:6379"
|
|
183
|
+
|
|
184
|
+
# Persistent storage for Redis
|
|
185
|
+
volumes:
|
|
186
|
+
- redis_data:/data
|
|
187
|
+
|
|
188
|
+
# Health check to verify Redis is ready
|
|
189
|
+
healthcheck:
|
|
190
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
191
|
+
interval: 10s
|
|
192
|
+
timeout: 5s
|
|
193
|
+
retries: 5
|
|
194
|
+
start_period: 5s
|
|
195
|
+
|
|
196
|
+
# Resource limits
|
|
197
|
+
deploy:
|
|
198
|
+
resources:
|
|
199
|
+
limits:
|
|
200
|
+
cpus: '1'
|
|
201
|
+
memory: 512M
|
|
202
|
+
reservations:
|
|
203
|
+
cpus: '0.1'
|
|
204
|
+
memory: 64M
|
|
205
|
+
|
|
206
|
+
networks:
|
|
207
|
+
- supermemory-network
|
|
208
|
+
|
|
209
|
+
logging:
|
|
210
|
+
driver: "json-file"
|
|
211
|
+
options:
|
|
212
|
+
max-size: "10m"
|
|
213
|
+
max-file: "3"
|
|
214
|
+
|
|
215
|
+
# Redis is optional - use profile to enable
|
|
216
|
+
profiles:
|
|
217
|
+
- redis
|
|
218
|
+
- production
|
|
219
|
+
|
|
220
|
+
# ---------------------------------------------------------------------------
|
|
221
|
+
# ChromaDB - Vector database for embeddings (optional)
|
|
222
|
+
# ---------------------------------------------------------------------------
|
|
223
|
+
# Started when chroma profile is active or via prod compose with chroma
|
|
224
|
+
chromadb:
|
|
225
|
+
image: chromadb/chroma:latest
|
|
226
|
+
container_name: supermemory-chromadb
|
|
227
|
+
restart: unless-stopped
|
|
228
|
+
|
|
229
|
+
environment:
|
|
230
|
+
- IS_PERSISTENT=TRUE
|
|
231
|
+
- PERSIST_DIRECTORY=/chroma/chroma
|
|
232
|
+
- ANONYMIZED_TELEMETRY=FALSE
|
|
233
|
+
# Optional authentication (uncomment to enable)
|
|
234
|
+
# - CHROMA_SERVER_AUTH_PROVIDER=token
|
|
235
|
+
# - CHROMA_SERVER_AUTH_CREDENTIALS=${CHROMA_AUTH_TOKEN}
|
|
236
|
+
# - CHROMA_SERVER_AUTH_TOKEN_TRANSPORT_HEADER=Authorization
|
|
237
|
+
|
|
238
|
+
ports:
|
|
239
|
+
- "8000:8000"
|
|
240
|
+
|
|
241
|
+
# Persistent storage for vector data
|
|
242
|
+
volumes:
|
|
243
|
+
- chromadb_data:/chroma/chroma
|
|
244
|
+
|
|
245
|
+
# Health check to verify ChromaDB is ready
|
|
246
|
+
healthcheck:
|
|
247
|
+
test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/heartbeat"]
|
|
248
|
+
interval: 10s
|
|
249
|
+
timeout: 5s
|
|
250
|
+
retries: 5
|
|
251
|
+
start_period: 10s
|
|
252
|
+
|
|
253
|
+
# Resource limits
|
|
254
|
+
deploy:
|
|
255
|
+
resources:
|
|
256
|
+
limits:
|
|
257
|
+
cpus: '2'
|
|
258
|
+
memory: 2G
|
|
259
|
+
reservations:
|
|
260
|
+
cpus: '0.25'
|
|
261
|
+
memory: 256M
|
|
262
|
+
|
|
263
|
+
networks:
|
|
264
|
+
- supermemory-network
|
|
265
|
+
|
|
266
|
+
logging:
|
|
267
|
+
driver: "json-file"
|
|
268
|
+
options:
|
|
269
|
+
max-size: "10m"
|
|
270
|
+
max-file: "3"
|
|
271
|
+
|
|
272
|
+
# ChromaDB is optional - use profile to enable
|
|
273
|
+
profiles:
|
|
274
|
+
- chroma
|
|
275
|
+
- production
|
|
276
|
+
|
|
277
|
+
# ---------------------------------------------------------------------------
|
|
278
|
+
# Worker Service - Background job processor
|
|
279
|
+
# ---------------------------------------------------------------------------
|
|
280
|
+
# Handles asynchronous tasks like:
|
|
281
|
+
# - Document processing and chunking
|
|
282
|
+
# - Embedding generation
|
|
283
|
+
# - Batch imports
|
|
284
|
+
# ---------------------------------------------------------------------------
|
|
285
|
+
worker:
|
|
286
|
+
build:
|
|
287
|
+
context: .
|
|
288
|
+
dockerfile: Dockerfile
|
|
289
|
+
container_name: supermemory-worker
|
|
290
|
+
restart: unless-stopped
|
|
291
|
+
|
|
292
|
+
# Override command to run worker instead of API
|
|
293
|
+
command: ["node", "dist/worker.js"]
|
|
294
|
+
|
|
295
|
+
environment:
|
|
296
|
+
- NODE_ENV=production
|
|
297
|
+
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
|
298
|
+
- AUTH_ENABLED=${AUTH_ENABLED:-false}
|
|
299
|
+
- AUTH_TOKEN=${AUTH_TOKEN:-}
|
|
300
|
+
- LOG_LEVEL=${LOG_LEVEL:-info}
|
|
301
|
+
# Redis Configuration
|
|
302
|
+
- REDIS_HOST=${REDIS_HOST:-redis}
|
|
303
|
+
- REDIS_PORT=${REDIS_PORT:-6379}
|
|
304
|
+
# BullMQ Queue Configuration
|
|
305
|
+
- BULLMQ_CONCURRENCY_EXTRACTION=${BULLMQ_CONCURRENCY_EXTRACTION:-5}
|
|
306
|
+
- BULLMQ_CONCURRENCY_CHUNKING=${BULLMQ_CONCURRENCY_CHUNKING:-3}
|
|
307
|
+
- BULLMQ_CONCURRENCY_EMBEDDING=${BULLMQ_CONCURRENCY_EMBEDDING:-2}
|
|
308
|
+
- BULLMQ_CONCURRENCY_INDEXING=${BULLMQ_CONCURRENCY_INDEXING:-1}
|
|
309
|
+
|
|
310
|
+
# No depends_on in base - override in prod compose file
|
|
311
|
+
|
|
312
|
+
# No health check for worker - it doesn't expose HTTP
|
|
313
|
+
# You could add a custom health check script if needed
|
|
314
|
+
|
|
315
|
+
# Resource limits
|
|
316
|
+
deploy:
|
|
317
|
+
resources:
|
|
318
|
+
limits:
|
|
319
|
+
cpus: '2'
|
|
320
|
+
memory: 1G
|
|
321
|
+
reservations:
|
|
322
|
+
cpus: '0.25'
|
|
323
|
+
memory: 128M
|
|
324
|
+
|
|
325
|
+
networks:
|
|
326
|
+
- supermemory-network
|
|
327
|
+
|
|
328
|
+
logging:
|
|
329
|
+
driver: "json-file"
|
|
330
|
+
options:
|
|
331
|
+
max-size: "10m"
|
|
332
|
+
max-file: "3"
|
|
333
|
+
|
|
334
|
+
# Worker is optional - use profile to enable
|
|
335
|
+
profiles:
|
|
336
|
+
- worker
|
|
337
|
+
|
|
338
|
+
# =============================================================================
|
|
339
|
+
# Volumes - Persistent storage
|
|
340
|
+
# =============================================================================
|
|
341
|
+
volumes:
|
|
342
|
+
postgres_data:
|
|
343
|
+
driver: local
|
|
344
|
+
name: supermemory_postgres_data
|
|
345
|
+
redis_data:
|
|
346
|
+
driver: local
|
|
347
|
+
name: supermemory_redis_data
|
|
348
|
+
chromadb_data:
|
|
349
|
+
driver: local
|
|
350
|
+
name: supermemory_chromadb_data
|
|
351
|
+
|
|
352
|
+
# =============================================================================
|
|
353
|
+
# Networks - Container networking
|
|
354
|
+
# =============================================================================
|
|
355
|
+
networks:
|
|
356
|
+
supermemory-network:
|
|
357
|
+
driver: bridge
|
|
358
|
+
name: supermemory-network
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
CREATE TABLE "container_tags" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
3
|
+
"tag" varchar(255) NOT NULL,
|
|
4
|
+
"parent_tag" varchar(255),
|
|
5
|
+
"display_name" varchar(255),
|
|
6
|
+
"description" text,
|
|
7
|
+
"metadata" jsonb DEFAULT '{}'::jsonb,
|
|
8
|
+
"settings" jsonb DEFAULT '{}'::jsonb,
|
|
9
|
+
"is_active" boolean DEFAULT true NOT NULL,
|
|
10
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
11
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
12
|
+
CONSTRAINT "container_tags_tag_unique" UNIQUE("tag"),
|
|
13
|
+
CONSTRAINT "container_tags_no_self_parent" CHECK ("container_tags"."tag" != "container_tags"."parent_tag"),
|
|
14
|
+
CONSTRAINT "container_tags_tag_format" CHECK ("container_tags"."tag" ~ '^[a-zA-Z0-9_-]+$')
|
|
15
|
+
);
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
CREATE TABLE "documents" (
|
|
18
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
19
|
+
"custom_id" varchar(255),
|
|
20
|
+
"content" text NOT NULL,
|
|
21
|
+
"content_type" varchar(50) DEFAULT 'text/plain' NOT NULL,
|
|
22
|
+
"status" varchar(20) DEFAULT 'pending' NOT NULL,
|
|
23
|
+
"container_tag" varchar(255) NOT NULL,
|
|
24
|
+
"metadata" jsonb DEFAULT '{}'::jsonb,
|
|
25
|
+
"content_hash" varchar(64) GENERATED ALWAYS AS (encode(sha256(content::bytea), 'hex')) STORED NOT NULL,
|
|
26
|
+
"word_count" integer GENERATED ALWAYS AS (array_length(regexp_split_to_array(content, '\s+'), 1)) STORED NOT NULL,
|
|
27
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
28
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
29
|
+
CONSTRAINT "documents_status_check" CHECK ("documents"."status" IN ('pending', 'processing', 'processed', 'failed', 'archived')),
|
|
30
|
+
CONSTRAINT "documents_content_type_check" CHECK ("documents"."content_type" IN ('text/plain', 'text/markdown', 'text/html', 'application/pdf', 'application/json', 'image/png', 'image/jpeg', 'audio/mp3', 'video/mp4'))
|
|
31
|
+
);
|
|
32
|
+
--> statement-breakpoint
|
|
33
|
+
CREATE TABLE "memories" (
|
|
34
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
35
|
+
"document_id" uuid,
|
|
36
|
+
"content" text NOT NULL,
|
|
37
|
+
"memory_type" varchar(20) DEFAULT 'fact' NOT NULL,
|
|
38
|
+
"is_latest" boolean DEFAULT true NOT NULL,
|
|
39
|
+
"similarity_hash" varchar(64) NOT NULL,
|
|
40
|
+
"version" integer DEFAULT 1 NOT NULL,
|
|
41
|
+
"supersedes_id" uuid,
|
|
42
|
+
"container_tag" varchar(255) NOT NULL,
|
|
43
|
+
"confidence_score" numeric(4, 3) DEFAULT '1.000',
|
|
44
|
+
"metadata" jsonb DEFAULT '{}'::jsonb,
|
|
45
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
46
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
47
|
+
CONSTRAINT "memories_type_check" CHECK ("memories"."memory_type" IN ('fact', 'preference', 'episode', 'belief', 'skill', 'context')),
|
|
48
|
+
CONSTRAINT "memories_confidence_check" CHECK ("memories"."confidence_score" >= 0 AND "memories"."confidence_score" <= 1)
|
|
49
|
+
);
|
|
50
|
+
--> statement-breakpoint
|
|
51
|
+
CREATE TABLE "memory_embeddings" (
|
|
52
|
+
"memory_id" uuid PRIMARY KEY NOT NULL,
|
|
53
|
+
"embedding" vector(1536) NOT NULL,
|
|
54
|
+
"model" varchar(100) DEFAULT 'text-embedding-3-small' NOT NULL,
|
|
55
|
+
"model_version" varchar(50),
|
|
56
|
+
"normalized" boolean DEFAULT true,
|
|
57
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
58
|
+
CONSTRAINT "memory_embeddings_model_check" CHECK ("memory_embeddings"."model" IN ('text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002', 'voyage-large-2', 'voyage-code-2', 'cohere-embed-v3', 'bge-large-en-v1.5', 'custom'))
|
|
59
|
+
);
|
|
60
|
+
--> statement-breakpoint
|
|
61
|
+
CREATE TABLE "memory_relationships" (
|
|
62
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
63
|
+
"source_memory_id" uuid NOT NULL,
|
|
64
|
+
"target_memory_id" uuid NOT NULL,
|
|
65
|
+
"relationship_type" varchar(30) NOT NULL,
|
|
66
|
+
"weight" numeric(4, 3) DEFAULT '1.000',
|
|
67
|
+
"bidirectional" boolean DEFAULT false,
|
|
68
|
+
"metadata" jsonb DEFAULT '{}'::jsonb,
|
|
69
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
70
|
+
CONSTRAINT "memory_relationships_unique_edge" UNIQUE("source_memory_id","target_memory_id","relationship_type"),
|
|
71
|
+
CONSTRAINT "memory_relationships_type_check" CHECK ("memory_relationships"."relationship_type" IN ('updates', 'extends', 'derives', 'contradicts', 'supports', 'relates', 'temporal', 'causal', 'part_of', 'similar')),
|
|
72
|
+
CONSTRAINT "memory_relationships_weight_check" CHECK ("memory_relationships"."weight" >= 0 AND "memory_relationships"."weight" <= 1),
|
|
73
|
+
CONSTRAINT "memory_relationships_no_self_loop" CHECK ("memory_relationships"."source_memory_id" != "memory_relationships"."target_memory_id")
|
|
74
|
+
);
|
|
75
|
+
--> statement-breakpoint
|
|
76
|
+
CREATE TABLE "user_profiles" (
|
|
77
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
78
|
+
"container_tag" varchar(255) NOT NULL,
|
|
79
|
+
"static_facts" jsonb DEFAULT '[]'::jsonb,
|
|
80
|
+
"dynamic_facts" jsonb DEFAULT '[]'::jsonb,
|
|
81
|
+
"preferences" jsonb DEFAULT '{}'::jsonb,
|
|
82
|
+
"computed_traits" jsonb DEFAULT '{}'::jsonb,
|
|
83
|
+
"last_interaction_at" timestamp with time zone,
|
|
84
|
+
"memory_count" integer DEFAULT 0,
|
|
85
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
86
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
87
|
+
CONSTRAINT "user_profiles_container_tag_unique" UNIQUE("container_tag")
|
|
88
|
+
);
|
|
89
|
+
--> statement-breakpoint
|
|
90
|
+
CREATE TABLE "processing_queue" (
|
|
91
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
92
|
+
"document_id" uuid NOT NULL,
|
|
93
|
+
"stage" varchar(30) DEFAULT 'extraction' NOT NULL,
|
|
94
|
+
"status" varchar(20) DEFAULT 'pending' NOT NULL,
|
|
95
|
+
"priority" integer DEFAULT 0,
|
|
96
|
+
"error" text,
|
|
97
|
+
"error_code" varchar(50),
|
|
98
|
+
"attempts" integer DEFAULT 0,
|
|
99
|
+
"max_attempts" integer DEFAULT 3,
|
|
100
|
+
"worker_id" varchar(100),
|
|
101
|
+
"metadata" jsonb DEFAULT '{}'::jsonb,
|
|
102
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
103
|
+
"started_at" timestamp with time zone,
|
|
104
|
+
"completed_at" timestamp with time zone,
|
|
105
|
+
"scheduled_at" timestamp with time zone DEFAULT now(),
|
|
106
|
+
CONSTRAINT "processing_queue_stage_check" CHECK ("processing_queue"."stage" IN ('extraction', 'embedding', 'deduplication', 'relationship', 'profile_update', 'cleanup')),
|
|
107
|
+
CONSTRAINT "processing_queue_status_check" CHECK ("processing_queue"."status" IN ('pending', 'processing', 'completed', 'failed', 'cancelled', 'retry')),
|
|
108
|
+
CONSTRAINT "processing_queue_attempts_check" CHECK ("processing_queue"."attempts" <= "processing_queue"."max_attempts")
|
|
109
|
+
);
|
|
110
|
+
--> statement-breakpoint
|
|
111
|
+
ALTER TABLE "container_tags" ADD CONSTRAINT "container_tags_parent_tag_container_tags_tag_fk" FOREIGN KEY ("parent_tag") REFERENCES "public"."container_tags"("tag") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
|
112
|
+
ALTER TABLE "memories" ADD CONSTRAINT "memories_document_id_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."documents"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
|
113
|
+
ALTER TABLE "memories" ADD CONSTRAINT "memories_supersedes_id_memories_id_fk" FOREIGN KEY ("supersedes_id") REFERENCES "public"."memories"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
|
114
|
+
ALTER TABLE "memory_embeddings" ADD CONSTRAINT "memory_embeddings_memory_id_memories_id_fk" FOREIGN KEY ("memory_id") REFERENCES "public"."memories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
115
|
+
ALTER TABLE "memory_relationships" ADD CONSTRAINT "memory_relationships_source_memory_id_memories_id_fk" FOREIGN KEY ("source_memory_id") REFERENCES "public"."memories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
116
|
+
ALTER TABLE "memory_relationships" ADD CONSTRAINT "memory_relationships_target_memory_id_memories_id_fk" FOREIGN KEY ("target_memory_id") REFERENCES "public"."memories"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
117
|
+
ALTER TABLE "user_profiles" ADD CONSTRAINT "user_profiles_container_tag_container_tags_tag_fk" FOREIGN KEY ("container_tag") REFERENCES "public"."container_tags"("tag") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
118
|
+
ALTER TABLE "processing_queue" ADD CONSTRAINT "processing_queue_document_id_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
119
|
+
CREATE INDEX "idx_container_tags_parent" ON "container_tags" USING btree ("parent_tag");--> statement-breakpoint
|
|
120
|
+
CREATE INDEX "idx_container_tags_active" ON "container_tags" USING btree ("is_active") WHERE "container_tags"."is_active" = TRUE;--> statement-breakpoint
|
|
121
|
+
CREATE INDEX "idx_container_tags_metadata" ON "container_tags" USING gin ("metadata");--> statement-breakpoint
|
|
122
|
+
CREATE INDEX "idx_container_tags_hierarchy" ON "container_tags" USING btree ("tag","parent_tag");--> statement-breakpoint
|
|
123
|
+
CREATE INDEX "idx_documents_container_tag" ON "documents" USING btree ("container_tag");--> statement-breakpoint
|
|
124
|
+
CREATE INDEX "idx_documents_status" ON "documents" USING btree ("status") WHERE "documents"."status" != 'processed';--> statement-breakpoint
|
|
125
|
+
CREATE INDEX "idx_documents_custom_id" ON "documents" USING btree ("custom_id") WHERE "documents"."custom_id" IS NOT NULL;--> statement-breakpoint
|
|
126
|
+
CREATE INDEX "idx_documents_content_hash" ON "documents" USING btree ("content_hash");--> statement-breakpoint
|
|
127
|
+
CREATE INDEX "idx_documents_created_at" ON "documents" USING btree ("created_at" DESC NULLS LAST);--> statement-breakpoint
|
|
128
|
+
CREATE INDEX "idx_documents_metadata" ON "documents" USING gin ("metadata" jsonb_path_ops);--> statement-breakpoint
|
|
129
|
+
CREATE INDEX "idx_documents_container_status" ON "documents" USING btree ("container_tag","status","created_at");--> statement-breakpoint
|
|
130
|
+
CREATE INDEX "idx_memories_document_id" ON "memories" USING btree ("document_id") WHERE "memories"."document_id" IS NOT NULL;--> statement-breakpoint
|
|
131
|
+
CREATE INDEX "idx_memories_container_tag" ON "memories" USING btree ("container_tag");--> statement-breakpoint
|
|
132
|
+
CREATE INDEX "idx_memories_type" ON "memories" USING btree ("memory_type");--> statement-breakpoint
|
|
133
|
+
CREATE INDEX "idx_memories_is_latest" ON "memories" USING btree ("is_latest") WHERE "memories"."is_latest" = TRUE;--> statement-breakpoint
|
|
134
|
+
CREATE INDEX "idx_memories_similarity_hash" ON "memories" USING btree ("similarity_hash");--> statement-breakpoint
|
|
135
|
+
CREATE INDEX "idx_memories_supersedes" ON "memories" USING btree ("supersedes_id") WHERE "memories"."supersedes_id" IS NOT NULL;--> statement-breakpoint
|
|
136
|
+
CREATE INDEX "idx_memories_metadata" ON "memories" USING gin ("metadata" jsonb_path_ops);--> statement-breakpoint
|
|
137
|
+
CREATE INDEX "idx_memories_created_at" ON "memories" USING btree ("created_at" DESC NULLS LAST);--> statement-breakpoint
|
|
138
|
+
CREATE INDEX "idx_memories_container_latest" ON "memories" USING btree ("container_tag","is_latest","created_at") WHERE "memories"."is_latest" = TRUE;--> statement-breakpoint
|
|
139
|
+
CREATE INDEX "idx_memories_container_type_latest" ON "memories" USING btree ("container_tag","memory_type","is_latest") WHERE "memories"."is_latest" = TRUE;--> statement-breakpoint
|
|
140
|
+
CREATE INDEX "idx_memories_version_chain" ON "memories" USING btree ("supersedes_id","version") WHERE "memories"."supersedes_id" IS NOT NULL;--> statement-breakpoint
|
|
141
|
+
CREATE INDEX "idx_memory_embeddings_hnsw" ON "memory_embeddings" USING hnsw ("embedding" vector_cosine_ops) WITH (m=16,ef_construction=64);--> statement-breakpoint
|
|
142
|
+
CREATE INDEX "idx_memory_embeddings_model" ON "memory_embeddings" USING btree ("model");--> statement-breakpoint
|
|
143
|
+
CREATE INDEX "idx_memory_rel_source" ON "memory_relationships" USING btree ("source_memory_id");--> statement-breakpoint
|
|
144
|
+
CREATE INDEX "idx_memory_rel_target" ON "memory_relationships" USING btree ("target_memory_id");--> statement-breakpoint
|
|
145
|
+
CREATE INDEX "idx_memory_rel_type" ON "memory_relationships" USING btree ("relationship_type");--> statement-breakpoint
|
|
146
|
+
CREATE INDEX "idx_memory_rel_bidirectional" ON "memory_relationships" USING btree ("source_memory_id","target_memory_id") WHERE "memory_relationships"."bidirectional" = TRUE;--> statement-breakpoint
|
|
147
|
+
CREATE INDEX "idx_memory_rel_graph" ON "memory_relationships" USING btree ("source_memory_id","target_memory_id","relationship_type","weight");--> statement-breakpoint
|
|
148
|
+
CREATE INDEX "idx_user_profiles_container" ON "user_profiles" USING btree ("container_tag");--> statement-breakpoint
|
|
149
|
+
CREATE INDEX "idx_user_profiles_static_facts" ON "user_profiles" USING gin ("static_facts");--> statement-breakpoint
|
|
150
|
+
CREATE INDEX "idx_user_profiles_dynamic_facts" ON "user_profiles" USING gin ("dynamic_facts");--> statement-breakpoint
|
|
151
|
+
CREATE INDEX "idx_user_profiles_preferences" ON "user_profiles" USING gin ("preferences");--> statement-breakpoint
|
|
152
|
+
CREATE INDEX "idx_user_profiles_updated" ON "user_profiles" USING btree ("updated_at" DESC NULLS LAST);--> statement-breakpoint
|
|
153
|
+
CREATE INDEX "idx_processing_queue_document" ON "processing_queue" USING btree ("document_id");--> statement-breakpoint
|
|
154
|
+
CREATE INDEX "idx_processing_queue_status" ON "processing_queue" USING btree ("status") WHERE "processing_queue"."status" IN ('pending', 'retry');--> statement-breakpoint
|
|
155
|
+
CREATE INDEX "idx_processing_queue_stage" ON "processing_queue" USING btree ("stage");--> statement-breakpoint
|
|
156
|
+
CREATE INDEX "idx_processing_queue_worker" ON "processing_queue" USING btree ("worker_id") WHERE "processing_queue"."worker_id" IS NOT NULL;--> statement-breakpoint
|
|
157
|
+
CREATE INDEX "idx_processing_queue_priority" ON "processing_queue" USING btree ("priority" DESC NULLS LAST,"scheduled_at") WHERE "processing_queue"."status" IN ('pending', 'retry');--> statement-breakpoint
|
|
158
|
+
CREATE INDEX "idx_processing_queue_stale" ON "processing_queue" USING btree ("started_at") WHERE "processing_queue"."status" = 'processing';--> statement-breakpoint
|
|
159
|
+
CREATE INDEX "idx_processing_queue_worker_select" ON "processing_queue" USING btree ("status","stage","priority","scheduled_at") WHERE "processing_queue"."status" IN ('pending', 'retry');
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-- API Keys table for MCP authentication
|
|
2
|
+
-- Migration: Add API key authentication support
|
|
3
|
+
|
|
4
|
+
CREATE TABLE "api_keys" (
|
|
5
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
6
|
+
"key_hash" varchar(255) NOT NULL,
|
|
7
|
+
"name" varchar(255) NOT NULL,
|
|
8
|
+
"scopes" jsonb DEFAULT '["read"]'::jsonb NOT NULL,
|
|
9
|
+
"expires_at" timestamp with time zone,
|
|
10
|
+
"last_used_at" timestamp with time zone,
|
|
11
|
+
"revoked" timestamp with time zone,
|
|
12
|
+
"metadata" jsonb DEFAULT '{}'::jsonb,
|
|
13
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
14
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
15
|
+
);
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
|
|
18
|
+
-- Index for fast key lookup during authentication
|
|
19
|
+
CREATE INDEX "idx_api_keys_hash" ON "api_keys" USING btree ("key_hash");
|
|
20
|
+
--> statement-breakpoint
|
|
21
|
+
|
|
22
|
+
-- Index for listing active keys (not expired, not revoked)
|
|
23
|
+
CREATE INDEX "idx_api_keys_active" ON "api_keys" USING btree ("expires_at", "revoked") WHERE ("revoked" IS NULL);
|
|
24
|
+
--> statement-breakpoint
|
|
25
|
+
|
|
26
|
+
-- Index for usage tracking and security audits
|
|
27
|
+
CREATE INDEX "idx_api_keys_last_used" ON "api_keys" USING btree ("last_used_at" DESC);
|
|
28
|
+
--> statement-breakpoint
|
|
29
|
+
|
|
30
|
+
-- Index for scopes filtering
|
|
31
|
+
CREATE INDEX "idx_api_keys_scopes" ON "api_keys" USING gin ("scopes");
|
|
32
|
+
--> statement-breakpoint
|
|
33
|
+
|
|
34
|
+
-- Index for metadata search
|
|
35
|
+
CREATE INDEX "idx_api_keys_metadata" ON "api_keys" USING gin ("metadata" jsonb_path_ops);
|
|
36
|
+
--> statement-breakpoint
|
|
37
|
+
|
|
38
|
+
-- Index for name lookup
|
|
39
|
+
CREATE INDEX "idx_api_keys_name" ON "api_keys" USING btree ("name");
|
|
40
|
+
--> statement-breakpoint
|
|
41
|
+
|
|
42
|
+
-- Index for expiration checks
|
|
43
|
+
CREATE INDEX "idx_api_keys_expires" ON "api_keys" USING btree ("expires_at") WHERE ("expires_at" IS NOT NULL);
|
|
44
|
+
--> statement-breakpoint
|
|
45
|
+
|
|
46
|
+
-- Add comment explaining the security model
|
|
47
|
+
COMMENT ON TABLE "api_keys" IS 'API keys for MCP authentication. Keys are hashed with bcrypt (cost factor 10). Never store plaintext keys.';
|
|
48
|
+
COMMENT ON COLUMN "api_keys"."key_hash" IS 'Bcrypt hash of the API key (never store plaintext)';
|
|
49
|
+
COMMENT ON COLUMN "api_keys"."scopes" IS 'Permissions granted to this key: read, write, admin';
|
|
50
|
+
COMMENT ON COLUMN "api_keys"."revoked" IS 'Timestamp when the key was revoked (NULL = active)';
|
|
51
|
+
COMMENT ON COLUMN "api_keys"."last_used_at" IS 'Last time this key was used for authentication';
|