@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,347 @@
|
|
|
1
|
+
# Firestore Users Subcollection Pattern - Best Practices
|
|
2
|
+
|
|
3
|
+
**Concept**: Organize user-specific data under `users/{user_id}/` path
|
|
4
|
+
**Created**: 2026-02-11
|
|
5
|
+
**Status**: Best Practice Documentation
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
The `users/{user_id}/*` subcollection pattern is a Firestore best practice for organizing user-specific data. All user-scoped data lives under the user's document, making queries, security rules, and data management simpler.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Pattern Structure
|
|
16
|
+
|
|
17
|
+
### Recommended Firestore Organization
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
firestore/
|
|
21
|
+
├── users/
|
|
22
|
+
│ └── {user_id}/
|
|
23
|
+
│ ├── profile/ # User profile data
|
|
24
|
+
│ ├── preferences/ # User preferences
|
|
25
|
+
│ ├── templates/ # User's custom templates
|
|
26
|
+
│ │ └── {template_id}/
|
|
27
|
+
│ ├── memories/ # Memory metadata (if needed)
|
|
28
|
+
│ │ └── {memory_id}/
|
|
29
|
+
│ ├── relationships/ # Relationship metadata (if needed)
|
|
30
|
+
│ │ └── {relationship_id}/
|
|
31
|
+
│ ├── access_logs/ # Access attempt logs
|
|
32
|
+
│ │ └── {log_id}/
|
|
33
|
+
│ └── trust_relationships/ # Who this user trusts
|
|
34
|
+
│ └── {accessor_user_id}/
|
|
35
|
+
│
|
|
36
|
+
├── templates/
|
|
37
|
+
│ └── default/ # Default templates (shared)
|
|
38
|
+
│ └── {template_id}/
|
|
39
|
+
│
|
|
40
|
+
└── user_permissions/ # Cross-user permissions
|
|
41
|
+
└── {owner_user_id}/
|
|
42
|
+
└── allowed_accessors/
|
|
43
|
+
└── {accessor_user_id}/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Benefits of Users Subcollection Pattern
|
|
49
|
+
|
|
50
|
+
### 1. **Security Rules Simplification**
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// Simple rule: user can access their own data
|
|
54
|
+
match /users/{user_id}/{document=**} {
|
|
55
|
+
allow read, write: if request.auth.uid == user_id;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// vs complex rules for flat structure
|
|
59
|
+
match /templates/{template_id} {
|
|
60
|
+
allow read, write: if get(/databases/$(database)/documents/templates/$(template_id)).data.owner_user_id == request.auth.uid;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. **Query Simplification**
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Get all user's templates
|
|
68
|
+
const templates = await firestore
|
|
69
|
+
.collection('users')
|
|
70
|
+
.doc(user_id)
|
|
71
|
+
.collection('templates')
|
|
72
|
+
.get();
|
|
73
|
+
|
|
74
|
+
// vs querying flat structure with filter
|
|
75
|
+
const templates = await firestore
|
|
76
|
+
.collection('templates')
|
|
77
|
+
.where('owner_user_id', '==', user_id)
|
|
78
|
+
.get();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 3. **Data Locality**
|
|
82
|
+
|
|
83
|
+
All user data is co-located under their user document:
|
|
84
|
+
- Easier to understand data organization
|
|
85
|
+
- Simpler data export/deletion (GDPR compliance)
|
|
86
|
+
- Better for backups and migrations
|
|
87
|
+
- Clear data ownership
|
|
88
|
+
|
|
89
|
+
### 4. **Scalability**
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Each user's data is isolated
|
|
93
|
+
// No cross-user queries needed for user-specific data
|
|
94
|
+
// Better Firestore performance
|
|
95
|
+
// Easier to shard if needed
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 5. **GDPR Compliance**
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Delete all user data
|
|
102
|
+
async function deleteUserData(user_id: string): Promise<void> {
|
|
103
|
+
// Delete entire user document and all subcollections
|
|
104
|
+
await firestore
|
|
105
|
+
.collection('users')
|
|
106
|
+
.doc(user_id)
|
|
107
|
+
.delete({ recursive: true });
|
|
108
|
+
|
|
109
|
+
// All user data gone in one operation
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Pattern Application in Remember-MCP
|
|
116
|
+
|
|
117
|
+
### User-Specific Data (Under `users/{user_id}/`)
|
|
118
|
+
|
|
119
|
+
**1. Preferences** - `users/{user_id}/preferences`
|
|
120
|
+
```typescript
|
|
121
|
+
{
|
|
122
|
+
templates: { auto_suggest: true, ... },
|
|
123
|
+
search: { default_limit: 10, ... },
|
|
124
|
+
privacy: { default_trust: 0.5, ... }
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**2. Templates** - `users/{user_id}/templates/{template_id}`
|
|
129
|
+
```typescript
|
|
130
|
+
{
|
|
131
|
+
template_id: weaviate_uuid,
|
|
132
|
+
template_name: "My Custom Template",
|
|
133
|
+
derived_from: default_template_id,
|
|
134
|
+
usage_count: 5
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**3. Access Logs** - `users/{user_id}/access_logs/{log_id}`
|
|
139
|
+
```typescript
|
|
140
|
+
{
|
|
141
|
+
memory_id: string,
|
|
142
|
+
accessor_user_id: string,
|
|
143
|
+
result: "granted" | "denied" | "blocked",
|
|
144
|
+
timestamp: Timestamp
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**4. Trust Relationships** - `users/{user_id}/trust_relationships/{accessor_id}`
|
|
149
|
+
```typescript
|
|
150
|
+
{
|
|
151
|
+
accessor_user_id: string,
|
|
152
|
+
trust_level: float,
|
|
153
|
+
trust_summary: string,
|
|
154
|
+
granted_at: Timestamp
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Shared/Global Data (Outside `users/`)
|
|
159
|
+
|
|
160
|
+
**1. Default Templates** - `templates/default/{template_id}`
|
|
161
|
+
```typescript
|
|
162
|
+
{
|
|
163
|
+
template_id: weaviate_uuid,
|
|
164
|
+
template_name: "Person Profile",
|
|
165
|
+
is_default: true,
|
|
166
|
+
usage_count: 15234
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**2. Cross-User Permissions** - `user_permissions/{owner_id}/allowed_accessors/{accessor_id}`
|
|
171
|
+
```typescript
|
|
172
|
+
{
|
|
173
|
+
owner_user_id: string,
|
|
174
|
+
accessor_user_id: string,
|
|
175
|
+
trust_level: float,
|
|
176
|
+
can_access: boolean
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Note**: Cross-user permissions can't go under `users/{user_id}/` because they involve two users
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Query Patterns
|
|
185
|
+
|
|
186
|
+
### Get All User Data
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// Get all subcollections for a user
|
|
190
|
+
async function getAllUserData(user_id: string): Promise<UserData> {
|
|
191
|
+
const [profile, preferences, templates, accessLogs] = await Promise.all([
|
|
192
|
+
firestore.collection('users').doc(user_id).collection('profile').get(),
|
|
193
|
+
firestore.collection('users').doc(user_id).collection('preferences').get(),
|
|
194
|
+
firestore.collection('users').doc(user_id).collection('templates').get(),
|
|
195
|
+
firestore.collection('users').doc(user_id).collection('access_logs').get()
|
|
196
|
+
]);
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
profile: profile.docs.map(d => d.data()),
|
|
200
|
+
preferences: preferences.docs.map(d => d.data()),
|
|
201
|
+
templates: templates.docs.map(d => d.data()),
|
|
202
|
+
access_logs: accessLogs.docs.map(d => d.data())
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### List All Users with Templates
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// Collection group query across all users
|
|
211
|
+
const usersWithTemplates = await firestore
|
|
212
|
+
.collectionGroup('templates')
|
|
213
|
+
.get();
|
|
214
|
+
|
|
215
|
+
// Returns templates from all users
|
|
216
|
+
// Each doc has path: users/{user_id}/templates/{template_id}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Anti-Patterns to Avoid
|
|
222
|
+
|
|
223
|
+
### ❌ Flat Structure with Owner Field
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
// DON'T DO THIS
|
|
227
|
+
templates/{template_id}
|
|
228
|
+
owner_user_id: string
|
|
229
|
+
|
|
230
|
+
// Problems:
|
|
231
|
+
// - Need to filter by owner_user_id on every query
|
|
232
|
+
// - Security rules more complex
|
|
233
|
+
// - Harder to delete all user data
|
|
234
|
+
// - Less clear ownership
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### ❌ User ID in Document ID
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
// DON'T DO THIS
|
|
241
|
+
templates/{user_id}_{template_id}
|
|
242
|
+
|
|
243
|
+
// Problems:
|
|
244
|
+
// - Ugly document IDs
|
|
245
|
+
// - Can't reuse Weaviate UUID
|
|
246
|
+
// - Harder to parse
|
|
247
|
+
// - No clear structure
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### ✅ Subcollection Pattern
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
// DO THIS
|
|
254
|
+
users/{user_id}/templates/{template_id}
|
|
255
|
+
|
|
256
|
+
// Benefits:
|
|
257
|
+
// - Clear structure
|
|
258
|
+
// - Simple security rules
|
|
259
|
+
// - Easy queries
|
|
260
|
+
// - Clean IDs
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Migration Considerations
|
|
266
|
+
|
|
267
|
+
### Moving to Users Pattern
|
|
268
|
+
|
|
269
|
+
If you have existing flat structure:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// Migrate templates to users subcollection
|
|
273
|
+
async function migrateTemplatesToUsers(): Promise<void> {
|
|
274
|
+
const templates = await firestore.collection('templates').get();
|
|
275
|
+
|
|
276
|
+
for (const doc of templates.docs) {
|
|
277
|
+
const template = doc.data();
|
|
278
|
+
|
|
279
|
+
if (!template.is_default) {
|
|
280
|
+
// Move to users subcollection
|
|
281
|
+
await firestore
|
|
282
|
+
.collection('users')
|
|
283
|
+
.doc(template.owner_user_id)
|
|
284
|
+
.collection('templates')
|
|
285
|
+
.doc(doc.id)
|
|
286
|
+
.set(template);
|
|
287
|
+
|
|
288
|
+
// Delete from flat structure
|
|
289
|
+
await doc.ref.delete();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Best Practices Summary
|
|
298
|
+
|
|
299
|
+
### ✅ DO
|
|
300
|
+
|
|
301
|
+
1. **Use `users/{user_id}/` for all user-specific data**
|
|
302
|
+
2. **Keep shared/global data outside `users/`**
|
|
303
|
+
3. **Use subcollections for different data types**
|
|
304
|
+
4. **Reuse external IDs (like Weaviate UUID) as doc IDs**
|
|
305
|
+
5. **Keep security rules simple with path-based access**
|
|
306
|
+
|
|
307
|
+
### ❌ DON'T
|
|
308
|
+
|
|
309
|
+
1. **Don't use flat structure with owner_user_id field**
|
|
310
|
+
2. **Don't embed user_id in document IDs**
|
|
311
|
+
3. **Don't mix user data with shared data**
|
|
312
|
+
4. **Don't create permission documents for every user**
|
|
313
|
+
5. **Don't use complex security rules when simple path-based rules work**
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Complete Firestore Structure for Remember-MCP
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
firestore/
|
|
321
|
+
├── templates/
|
|
322
|
+
│ └── default/
|
|
323
|
+
│ └── {weaviate_uuid}/ # Default templates
|
|
324
|
+
│
|
|
325
|
+
├── users/
|
|
326
|
+
│ └── {user_id}/
|
|
327
|
+
│ ├── preferences # User preferences (single doc)
|
|
328
|
+
│ ├── templates/ # User's custom templates
|
|
329
|
+
│ │ └── {weaviate_uuid}/
|
|
330
|
+
│ ├── access_logs/ # Access attempt logs
|
|
331
|
+
│ │ └── {log_id}/
|
|
332
|
+
│ └── trust_relationships/ # Who this user trusts
|
|
333
|
+
│ └── {accessor_user_id}/
|
|
334
|
+
│
|
|
335
|
+
└── user_permissions/ # Cross-user permissions
|
|
336
|
+
└── {owner_user_id}/
|
|
337
|
+
└── allowed_accessors/
|
|
338
|
+
└── {accessor_user_id}/
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Note**: `user_permissions` is outside `users/` because it involves two users (owner and accessor)
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
**Status**: Best Practice Documentation
|
|
346
|
+
**Pattern**: `users/{user_id}/*` for all user-specific data
|
|
347
|
+
**Benefit**: Simpler, more scalable, better security, easier maintenance
|