Skip to content

Commit e357e75

Browse files
MementoRCclaude
andcommitted
feat: implement Task 17 - Design and Implement Centralized Database Architecture
- Added PostgreSQL connector with SQLAlchemy ORM support - Created unified database architecture combining PostgreSQL and ChromaDB - Implemented database schema with projects, patterns, error_solutions, team_access, and compatibility_matrix tables - Added Alembic migration system for schema evolution - Updated KnowledgeManager to use new unified database architecture - Enhanced storage layer with connection pooling and query optimization - Created comprehensive test suite for centralized architecture ✅ Quality: All critical lint checks passing, zero F,E9 violations ✅ Tests: Core database architecture functionality verified 📋 TaskMaster: Task 17 marked complete (16/25 tasks done - 64% progress) 🎯 Next: Task 18 - Build MCP Server with API Endpoints 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9c24334 commit e357e75

18 files changed

+2610
-379
lines changed

pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ dependencies = [
3737
"jinja2>=3.0.0",
3838
"redis>=4.0.0",
3939
"psutil>=5.9.0",
40+
"SQLAlchemy>=2.0.0", # Added for PostgreSQL ORM
41+
"psycopg[binary]>=3.1.0", # Added for PostgreSQL driver
4042
]
4143

4244
[project.optional-dependencies]
@@ -60,6 +62,7 @@ dev = [
6062
"mypy>=1.0.0",
6163
"pre-commit>=3.0.0",
6264
"aider-chat>=0.30.0",
65+
"alembic>=1.12.0", # Added for database migrations
6366
]
6467
loadtest = [
6568
"locust>=2.22.0",
@@ -127,6 +130,7 @@ ruff = "*"
127130
black = "*"
128131
mypy = "*"
129132
pre-commit = "*"
133+
alembic = "*" # Added for database migrations
130134

131135
[tool.pixi.feature.mcp.dependencies]
132136
nodejs = ">=18"
@@ -136,6 +140,8 @@ npm = "*"
136140
pytorch = "*"
137141
sentence-transformers = "*"
138142
chromadb = "*"
143+
SQLAlchemy = "*" # Added for PostgreSQL ORM
144+
psycopg = "*" # Added for PostgreSQL driver
139145

140146
[tool.pixi.environments]
141147
default = {features = ["ml"], solve-group = "default"}
@@ -170,6 +176,7 @@ start-server = "python -m uckn.server"
170176
analyze-project = "uckn analyze ."
171177
migrate-patterns = "uckn migrate --source .claude/knowledge"
172178
init-project = "uckn init"
179+
db-migrate = "alembic -c src/uckn/storage/migrations/alembic.ini upgrade head" # Added for DB migrations
173180

174181
# Documentation
175182
docs-serve = "mkdocs serve"

src/uckn/core/molecules/error_solution_manager.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
import logging
1010

1111
from ..atoms.semantic_search import SemanticSearch
12-
from ...storage import ChromaDBConnector
12+
from ...storage import UnifiedDatabase # Changed from ChromaDBConnector
1313

1414

1515
class ErrorSolutionManager:
16-
"""Manages error solutions with ChromaDB storage and semantic search"""
16+
"""Manages error solutions with UnifiedDatabase storage and semantic search"""
1717

18-
def __init__(self, chroma_connector: ChromaDBConnector, semantic_search: SemanticSearch):
19-
self.chroma_connector = chroma_connector
18+
def __init__(self, unified_db: UnifiedDatabase, semantic_search: SemanticSearch):
19+
self.unified_db = unified_db # Changed from chroma_connector
2020
self.semantic_search = semantic_search
2121
self._logger = logging.getLogger(__name__)
2222

@@ -28,12 +28,13 @@ def add_error_solution(self, solution_data: Dict[str, Any]) -> Optional[str]:
2828
solution_data: Dictionary containing solution details.
2929
Must include 'document' (error message/description) and 'metadata'.
3030
Metadata must conform to 'error_solutions' schema.
31+
Can optionally include 'project_id'.
3132
3233
Returns:
3334
The solution_id if added successfully, None otherwise.
3435
"""
35-
if not self.chroma_connector.is_available():
36-
self._logger.error("ChromaDB not available, cannot add error solution.")
36+
if not self.unified_db.is_available():
37+
self._logger.error("Unified Database not available, cannot add error solution.")
3738
return None
3839
if not self.semantic_search.is_available():
3940
self._logger.error("Semantic search not available, cannot generate embeddings for error solution.")
@@ -42,6 +43,7 @@ def add_error_solution(self, solution_data: Dict[str, Any]) -> Optional[str]:
4243
solution_id = solution_data.get("solution_id", str(uuid.uuid4()))
4344
document_text = solution_data.get("document")
4445
metadata = solution_data.get("metadata", {})
46+
project_id = solution_data.get("project_id")
4547

4648
if not document_text:
4749
self._logger.error("Solution data must include 'document' text for embedding.")
@@ -53,35 +55,36 @@ def add_error_solution(self, solution_data: Dict[str, Any]) -> Optional[str]:
5355
self._logger.error(f"Failed to generate embedding for solution {solution_id}.")
5456
return None
5557

56-
# Add/update timestamps in metadata
58+
# Add/update timestamps in metadata (these will be stored in PG metadata_json and specific columns)
5759
now_iso = datetime.now().isoformat()
58-
metadata["solution_id"] = solution_id
60+
metadata["solution_id"] = solution_id # Ensure ID is in metadata for ChromaDB
5961
metadata["created_at"] = metadata.get("created_at", now_iso)
6062
metadata["updated_at"] = now_iso
6163

62-
success = self.chroma_connector.add_document(
63-
collection_name="error_solutions",
64-
doc_id=solution_id,
65-
document=document_text,
64+
# UnifiedDatabase handles splitting data to PG and Chroma
65+
success = self.unified_db.add_error_solution(
66+
document_text=document_text,
6667
embedding=embedding,
67-
metadata=metadata
68+
metadata=metadata,
69+
solution_id=solution_id,
70+
project_id=project_id
6871
)
6972
return solution_id if success else None
7073

7174
def get_error_solution(self, solution_id: str) -> Optional[Dict[str, Any]]:
7275
"""
73-
Retrieve a specific error solution from the 'error_solutions' collection.
76+
Retrieve a specific error solution from the Unified Database.
7477
7578
Args:
7679
solution_id: The ID of the solution to retrieve.
7780
7881
Returns:
7982
A dictionary containing the solution details, or None if not found.
8083
"""
81-
if not self.chroma_connector.is_available():
82-
self._logger.warning("ChromaDB not available, cannot retrieve error solution.")
84+
if not self.unified_db.is_available():
85+
self._logger.warning("Unified Database not available, cannot retrieve error solution.")
8386
return None
84-
return self.chroma_connector.get_document(collection_name="error_solutions", doc_id=solution_id)
87+
return self.unified_db.get_error_solution(solution_id)
8588

8689
def search_error_solutions(
8790
self,
@@ -102,8 +105,8 @@ def search_error_solutions(
102105
Returns:
103106
List of relevant solution records with similarity scores.
104107
"""
105-
if not self.chroma_connector.is_available():
106-
self._logger.warning("ChromaDB not available, cannot search error solutions.")
108+
if not self.unified_db.is_available():
109+
self._logger.warning("Unified Database not available, cannot search error solutions.")
107110
return []
108111
if not self.semantic_search.is_available():
109112
self._logger.warning("Semantic search not available, cannot generate query embedding.")
@@ -114,32 +117,33 @@ def search_error_solutions(
114117
self._logger.error("Failed to generate query embedding for error search.")
115118
return []
116119

117-
results = self.chroma_connector.search_documents(
118-
collection_name="error_solutions",
120+
# UnifiedDatabase handles searching ChromaDB and fetching metadata from PG
121+
results = self.unified_db.search_error_solutions(
119122
query_embedding=query_embedding,
120123
n_results=limit,
121124
min_similarity=min_similarity,
122-
where_clause=metadata_filter
125+
metadata_filter=metadata_filter
123126
)
124127
return results
125128

126129
def update_error_solution(self, solution_id: str, updates: Dict[str, Any]) -> bool:
127130
"""
128-
Update an existing error solution in the 'error_solutions' collection.
131+
Update an existing error solution in the Unified Database.
129132
130133
Args:
131134
solution_id: The ID of the solution to update.
132-
updates: Dictionary of fields to update. Can include 'document' or 'metadata'.
135+
updates: Dictionary of fields to update. Can include 'document' or 'metadata' or 'project_id'.
133136
134137
Returns:
135138
True if updated successfully, False otherwise.
136139
"""
137-
if not self.chroma_connector.is_available():
138-
self._logger.warning("ChromaDB not available, cannot update error solution.")
140+
if not self.unified_db.is_available():
141+
self._logger.warning("Unified Database not available, cannot update error solution.")
139142
return False
140143

141144
document_text = updates.get("document")
142145
metadata = updates.get("metadata")
146+
project_id = updates.get("project_id")
143147
embedding = None
144148

145149
if document_text and self.semantic_search.is_available():
@@ -154,25 +158,27 @@ def update_error_solution(self, solution_id: str, updates: Dict[str, Any]) -> bo
154158
if metadata is not None:
155159
metadata["updated_at"] = datetime.now().isoformat()
156160

157-
return self.chroma_connector.update_document(
158-
collection_name="error_solutions",
159-
doc_id=solution_id,
160-
document=document_text,
161+
# UnifiedDatabase handles updating both PG and Chroma
162+
return self.unified_db.update_error_solution(
163+
solution_id=solution_id,
164+
document_text=document_text,
161165
embedding=embedding,
162-
metadata=metadata
166+
metadata=metadata,
167+
project_id=project_id
163168
)
164169

165170
def delete_error_solution(self, solution_id: str) -> bool:
166171
"""
167-
Delete an error solution from the 'error_solutions' collection.
172+
Delete an error solution from the Unified Database.
168173
169174
Args:
170175
solution_id: The ID of the solution to delete.
171176
172177
Returns:
173178
True if deleted successfully, False otherwise.
174179
"""
175-
if not self.chroma_connector.is_available():
176-
self._logger.warning("ChromaDB not available, cannot delete error solution.")
180+
if not self.unified_db.is_available():
181+
self._logger.warning("Unified Database not available, cannot delete error solution.")
177182
return False
178-
return self.chroma_connector.delete_document(collection_name="error_solutions", doc_id=solution_id)
183+
# UnifiedDatabase handles deleting from both PG and Chroma
184+
return self.unified_db.delete_error_solution(solution_id)

0 commit comments

Comments
 (0)