@prmichaelsen/remember-mcp 0.1.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 +65 -0
- package/AGENT.md +840 -0
- package/README.md +72 -0
- package/agent/design/.gitkeep +0 -0
- package/agent/design/access-control-result-pattern.md +458 -0
- package/agent/design/action-audit-memory-types.md +637 -0
- package/agent/design/common-template-fields.md +282 -0
- package/agent/design/complete-tool-set.md +407 -0
- package/agent/design/content-types-expansion.md +521 -0
- package/agent/design/cross-database-id-strategy.md +358 -0
- package/agent/design/default-template-library.md +423 -0
- package/agent/design/firestore-wrapper-analysis.md +606 -0
- package/agent/design/llm-provider-abstraction.md +691 -0
- package/agent/design/location-handling-architecture.md +523 -0
- package/agent/design/memory-templates-design.md +364 -0
- package/agent/design/permissions-storage-architecture.md +680 -0
- package/agent/design/relationship-storage-strategy.md +361 -0
- package/agent/design/remember-mcp-implementation-tasks.md +417 -0
- package/agent/design/remember-mcp-progress.yaml +141 -0
- package/agent/design/requirements-enhancements.md +468 -0
- package/agent/design/requirements.md +56 -0
- package/agent/design/template-storage-strategy.md +412 -0
- package/agent/design/template-suggestion-system.md +853 -0
- package/agent/design/trust-escalation-prevention.md +343 -0
- package/agent/design/trust-system-implementation.md +592 -0
- package/agent/design/user-preferences.md +683 -0
- package/agent/design/weaviate-collection-strategy.md +461 -0
- package/agent/milestones/.gitkeep +0 -0
- package/agent/milestones/milestone-1-project-foundation.md +121 -0
- package/agent/milestones/milestone-2-core-memory-system.md +150 -0
- package/agent/milestones/milestone-3-relationships-graph.md +116 -0
- package/agent/milestones/milestone-4-user-preferences.md +103 -0
- package/agent/milestones/milestone-5-template-system.md +126 -0
- package/agent/milestones/milestone-6-auth-multi-tenancy.md +124 -0
- package/agent/milestones/milestone-7-trust-permissions.md +133 -0
- package/agent/milestones/milestone-8-testing-quality.md +137 -0
- package/agent/milestones/milestone-9-deployment-documentation.md +147 -0
- package/agent/patterns/.gitkeep +0 -0
- package/agent/patterns/bootstrap.md +1271 -0
- package/agent/patterns/firebase-admin-sdk-v8-usage.md +950 -0
- package/agent/patterns/firestore-users-pattern-best-practices.md +347 -0
- package/agent/patterns/library-services.md +454 -0
- package/agent/patterns/testing-colocated.md +316 -0
- package/agent/progress.yaml +395 -0
- package/agent/tasks/.gitkeep +0 -0
- package/agent/tasks/task-1-initialize-project-structure.md +266 -0
- package/agent/tasks/task-2-install-dependencies.md +199 -0
- package/agent/tasks/task-3-setup-weaviate-client.md +330 -0
- package/agent/tasks/task-4-setup-firestore-client.md +362 -0
- package/agent/tasks/task-5-create-basic-mcp-server.md +114 -0
- package/agent/tasks/task-6-create-integration-tests.md +195 -0
- package/agent/tasks/task-7-finalize-milestone-1.md +363 -0
- package/agent/tasks/task-8-setup-utility-scripts.md +382 -0
- package/agent/tasks/task-9-create-server-factory.md +404 -0
- package/dist/config.d.ts +26 -0
- package/dist/constants/content-types.d.ts +60 -0
- package/dist/firestore/init.d.ts +14 -0
- package/dist/firestore/paths.d.ts +53 -0
- package/dist/firestore/paths.spec.d.ts +2 -0
- package/dist/server-factory.d.ts +40 -0
- package/dist/server-factory.js +1741 -0
- package/dist/server-factory.spec.d.ts +2 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +1690 -0
- package/dist/tools/create-memory.d.ts +94 -0
- package/dist/tools/delete-memory.d.ts +47 -0
- package/dist/tools/search-memory.d.ts +88 -0
- package/dist/types/memory.d.ts +183 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/weaviate/client.d.ts +39 -0
- package/dist/weaviate/client.spec.d.ts +2 -0
- package/dist/weaviate/schema.d.ts +29 -0
- package/esbuild.build.js +60 -0
- package/esbuild.watch.js +25 -0
- package/jest.config.js +31 -0
- package/jest.e2e.config.js +17 -0
- package/package.json +68 -0
- package/src/.gitkeep +0 -0
- package/src/config.ts +56 -0
- package/src/constants/content-types.ts +454 -0
- package/src/firestore/init.ts +68 -0
- package/src/firestore/paths.spec.ts +75 -0
- package/src/firestore/paths.ts +124 -0
- package/src/server-factory.spec.ts +60 -0
- package/src/server-factory.ts +215 -0
- package/src/server.ts +243 -0
- package/src/tools/create-memory.ts +198 -0
- package/src/tools/delete-memory.ts +126 -0
- package/src/tools/search-memory.ts +216 -0
- package/src/types/memory.ts +276 -0
- package/src/utils/logger.ts +42 -0
- package/src/weaviate/client.spec.ts +58 -0
- package/src/weaviate/client.ts +114 -0
- package/src/weaviate/schema.ts +288 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# Cross-Database ID Strategy
|
|
2
|
+
|
|
3
|
+
**Concept**: Reuse Weaviate UUIDs as Firestore document IDs for consistency
|
|
4
|
+
**Created**: 2026-02-11
|
|
5
|
+
**Status**: Design Specification
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
When data is stored in both Weaviate and Firestore, we use the **Weaviate-generated UUID as the primary identifier** for both databases. This creates a single source of truth for IDs and simplifies cross-database operations.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Strategy: Weaviate ID as Primary
|
|
16
|
+
|
|
17
|
+
### Principle
|
|
18
|
+
|
|
19
|
+
**Weaviate generates the ID, Firestore reuses it**
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
1. Create document in Weaviate → Get UUID
|
|
23
|
+
2. Use that UUID as Firestore document ID
|
|
24
|
+
3. Both databases reference same ID
|
|
25
|
+
4. No ID mapping table needed
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Implementation
|
|
31
|
+
|
|
32
|
+
### Creating a Template
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
async function createTemplate(
|
|
36
|
+
template: Template,
|
|
37
|
+
user_id: string
|
|
38
|
+
): Promise<string> {
|
|
39
|
+
// 1. Create in Weaviate (generates UUID)
|
|
40
|
+
const weaviateId = await weaviateClient
|
|
41
|
+
.collection(`Template_${user_id}`)
|
|
42
|
+
.data.insert({
|
|
43
|
+
...template,
|
|
44
|
+
user_id,
|
|
45
|
+
created_at: new Date()
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// 2. Use same ID in Firestore
|
|
49
|
+
await firestore
|
|
50
|
+
.collection('templates')
|
|
51
|
+
.doc(weaviateId) // ✅ Reuse Weaviate ID
|
|
52
|
+
.set({
|
|
53
|
+
template_id: weaviateId,
|
|
54
|
+
owner_user_id: user_id,
|
|
55
|
+
template_name: template.template_name,
|
|
56
|
+
visibility: 'private',
|
|
57
|
+
created_at: Timestamp.now()
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return weaviateId; // Return single ID
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Creating a Memory
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
async function createMemory(
|
|
68
|
+
memory: Memory,
|
|
69
|
+
user_id: string
|
|
70
|
+
): Promise<string> {
|
|
71
|
+
// 1. Create in Weaviate (generates UUID)
|
|
72
|
+
const memoryId = await weaviateClient
|
|
73
|
+
.collection(`Memory_${user_id}`)
|
|
74
|
+
.data.insert({
|
|
75
|
+
...memory,
|
|
76
|
+
user_id,
|
|
77
|
+
created_at: new Date()
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// 2. If memory needs Firestore metadata (e.g., for permissions)
|
|
81
|
+
if (memory.needs_firestore_metadata) {
|
|
82
|
+
await firestore
|
|
83
|
+
.collection('memories')
|
|
84
|
+
.doc(memoryId) // ✅ Reuse Weaviate ID
|
|
85
|
+
.set({
|
|
86
|
+
memory_id: memoryId,
|
|
87
|
+
user_id,
|
|
88
|
+
trust_overrides: {},
|
|
89
|
+
access_log: [],
|
|
90
|
+
created_at: Timestamp.now()
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return memoryId;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Updating Across Databases
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
async function updateTemplate(
|
|
102
|
+
template_id: string,
|
|
103
|
+
updates: Partial<Template>
|
|
104
|
+
): Promise<void> {
|
|
105
|
+
// 1. Update in Weaviate
|
|
106
|
+
await weaviateClient
|
|
107
|
+
.collection(`Template_${user_id}`)
|
|
108
|
+
.data.update({
|
|
109
|
+
id: template_id,
|
|
110
|
+
properties: updates
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// 2. Update in Firestore (same ID)
|
|
114
|
+
await firestore
|
|
115
|
+
.collection('templates')
|
|
116
|
+
.doc(template_id) // ✅ Same ID
|
|
117
|
+
.update({
|
|
118
|
+
...updates,
|
|
119
|
+
updated_at: Timestamp.now()
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Querying Across Databases
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
async function getTemplateWithMetadata(
|
|
128
|
+
template_id: string
|
|
129
|
+
): Promise<TemplateWithMetadata> {
|
|
130
|
+
// Parallel fetch using same ID
|
|
131
|
+
const [weaviateData, firestoreData] = await Promise.all([
|
|
132
|
+
weaviateClient
|
|
133
|
+
.collection('Template_system')
|
|
134
|
+
.data.getById(template_id),
|
|
135
|
+
firestore
|
|
136
|
+
.collection('templates')
|
|
137
|
+
.doc(template_id) // ✅ Same ID
|
|
138
|
+
.get()
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
...weaviateData.properties,
|
|
143
|
+
...firestoreData.data(),
|
|
144
|
+
id: template_id // Single consistent ID
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Benefits
|
|
152
|
+
|
|
153
|
+
### 1. **Simplicity**
|
|
154
|
+
- Single ID to track
|
|
155
|
+
- No ID mapping table needed
|
|
156
|
+
- No synchronization issues
|
|
157
|
+
- Clear primary key
|
|
158
|
+
|
|
159
|
+
### 2. **Consistency**
|
|
160
|
+
- Same ID in both databases
|
|
161
|
+
- Easy to correlate data
|
|
162
|
+
- Simpler debugging
|
|
163
|
+
- Clear data lineage
|
|
164
|
+
|
|
165
|
+
### 3. **Performance**
|
|
166
|
+
- Parallel queries using same ID
|
|
167
|
+
- No lookup overhead
|
|
168
|
+
- Efficient joins
|
|
169
|
+
- Fast cross-database operations
|
|
170
|
+
|
|
171
|
+
### 4. **Maintainability**
|
|
172
|
+
- Less code complexity
|
|
173
|
+
- Fewer edge cases
|
|
174
|
+
- Easier to reason about
|
|
175
|
+
- Simpler migrations
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Firestore Collection Structure
|
|
180
|
+
|
|
181
|
+
### Recommended Structure
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
firestore/
|
|
185
|
+
├── templates/
|
|
186
|
+
│ ├── default/
|
|
187
|
+
│ │ ├── {weaviate_uuid_1}/ # ✅ Weaviate ID as doc ID
|
|
188
|
+
│ │ │ ├── metadata
|
|
189
|
+
│ │ │ └── permissions/
|
|
190
|
+
│ │ └── {weaviate_uuid_2}/
|
|
191
|
+
│ │ └── ...
|
|
192
|
+
│ └── users/
|
|
193
|
+
│ └── {user_id}/
|
|
194
|
+
│ └── templates/
|
|
195
|
+
│ └── {weaviate_uuid_3}/ # ✅ Weaviate ID as doc ID
|
|
196
|
+
│ ├── metadata
|
|
197
|
+
│ └── permissions/
|
|
198
|
+
│
|
|
199
|
+
├── memories/
|
|
200
|
+
│ └── {weaviate_uuid}/ # ✅ Only if metadata needed
|
|
201
|
+
│ ├── trust_overrides/
|
|
202
|
+
│ └── access_log/
|
|
203
|
+
│
|
|
204
|
+
└── user_preferences/
|
|
205
|
+
└── {user_id}/
|
|
206
|
+
└── preferences
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Alternative Simpler Structure**:
|
|
210
|
+
```
|
|
211
|
+
firestore/
|
|
212
|
+
├── templates/
|
|
213
|
+
│ ├── {weaviate_uuid}/ # ✅ All templates, default and user
|
|
214
|
+
│ │ ├── owner_user_id
|
|
215
|
+
│ │ ├── is_default: boolean
|
|
216
|
+
│ │ └── permissions/
|
|
217
|
+
│ └── {weaviate_uuid}/
|
|
218
|
+
│ └── ...
|
|
219
|
+
│
|
|
220
|
+
└── user_preferences/
|
|
221
|
+
└── {user_id}/
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Comparison
|
|
227
|
+
|
|
228
|
+
### ❌ Bad: Separate IDs
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// Weaviate
|
|
232
|
+
{
|
|
233
|
+
id: "weav_abc123", // Weaviate-generated
|
|
234
|
+
template_name: "Person Profile"
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Firestore
|
|
238
|
+
{
|
|
239
|
+
firestore_id: "fire_xyz789", // Firestore-generated
|
|
240
|
+
weaviate_id: "weav_abc123", // Reference to Weaviate
|
|
241
|
+
template_name: "Person Profile"
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Problems:
|
|
245
|
+
// - Two IDs to track
|
|
246
|
+
// - Need mapping table
|
|
247
|
+
// - Synchronization complexity
|
|
248
|
+
// - More error-prone
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### ✅ Good: Shared ID
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// Weaviate
|
|
255
|
+
{
|
|
256
|
+
id: "abc123-def456-ghi789", // Weaviate-generated UUID
|
|
257
|
+
template_name: "Person Profile"
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Firestore
|
|
261
|
+
{
|
|
262
|
+
// Document ID: "abc123-def456-ghi789" ✅ Same as Weaviate
|
|
263
|
+
template_id: "abc123-def456-ghi789",
|
|
264
|
+
owner_user_id: "user_123",
|
|
265
|
+
visibility: "private"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Benefits:
|
|
269
|
+
// - Single ID
|
|
270
|
+
// - No mapping needed
|
|
271
|
+
// - Simple queries
|
|
272
|
+
// - Clear relationship
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Edge Cases
|
|
278
|
+
|
|
279
|
+
### 1. Weaviate ID Conflicts
|
|
280
|
+
|
|
281
|
+
**Q**: What if Weaviate UUID conflicts with Firestore?
|
|
282
|
+
**A**: Extremely unlikely (UUID collision probability ~10^-18)
|
|
283
|
+
|
|
284
|
+
### 2. Firestore Document Already Exists
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Handle race conditions
|
|
288
|
+
try {
|
|
289
|
+
await firestore
|
|
290
|
+
.collection('templates')
|
|
291
|
+
.doc(weaviateId)
|
|
292
|
+
.create({ // Use .create() not .set()
|
|
293
|
+
...metadata
|
|
294
|
+
});
|
|
295
|
+
} catch (error) {
|
|
296
|
+
if (error.code === 'already-exists') {
|
|
297
|
+
// Document exists, update instead
|
|
298
|
+
await firestore
|
|
299
|
+
.collection('templates')
|
|
300
|
+
.doc(weaviateId)
|
|
301
|
+
.update(metadata);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 3. Orphaned Records
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// If Weaviate insert succeeds but Firestore fails
|
|
310
|
+
async function createWithRollback(data: any): Promise<string> {
|
|
311
|
+
let weaviateId: string | null = null;
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
// 1. Create in Weaviate
|
|
315
|
+
weaviateId = await weaviateClient.insert(data);
|
|
316
|
+
|
|
317
|
+
// 2. Create in Firestore
|
|
318
|
+
await firestore.doc(weaviateId).set(metadata);
|
|
319
|
+
|
|
320
|
+
return weaviateId;
|
|
321
|
+
} catch (error) {
|
|
322
|
+
// Rollback Weaviate if Firestore fails
|
|
323
|
+
if (weaviateId) {
|
|
324
|
+
await weaviateClient.delete(weaviateId);
|
|
325
|
+
}
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Recommendation
|
|
334
|
+
|
|
335
|
+
**Use Weaviate UUID as primary ID for both databases**
|
|
336
|
+
|
|
337
|
+
### For Templates:
|
|
338
|
+
```
|
|
339
|
+
Weaviate: Template_system/{uuid}
|
|
340
|
+
Firestore: templates/{uuid} ✅ Same ID
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### For Memories (if Firestore metadata needed):
|
|
344
|
+
```
|
|
345
|
+
Weaviate: Memory_{user_id}/{uuid}
|
|
346
|
+
Firestore: memories/{uuid} ✅ Same ID
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### For User Preferences:
|
|
350
|
+
```
|
|
351
|
+
Firestore: user_preferences/{user_id} ← User ID, not Weaviate ID
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
**Status**: Design Specification
|
|
357
|
+
**Strategy**: Weaviate generates UUID, Firestore reuses it
|
|
358
|
+
**Benefit**: Single consistent ID across databases
|