@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.
Files changed (95) hide show
  1. package/.env.example +65 -0
  2. package/AGENT.md +840 -0
  3. package/README.md +72 -0
  4. package/agent/design/.gitkeep +0 -0
  5. package/agent/design/access-control-result-pattern.md +458 -0
  6. package/agent/design/action-audit-memory-types.md +637 -0
  7. package/agent/design/common-template-fields.md +282 -0
  8. package/agent/design/complete-tool-set.md +407 -0
  9. package/agent/design/content-types-expansion.md +521 -0
  10. package/agent/design/cross-database-id-strategy.md +358 -0
  11. package/agent/design/default-template-library.md +423 -0
  12. package/agent/design/firestore-wrapper-analysis.md +606 -0
  13. package/agent/design/llm-provider-abstraction.md +691 -0
  14. package/agent/design/location-handling-architecture.md +523 -0
  15. package/agent/design/memory-templates-design.md +364 -0
  16. package/agent/design/permissions-storage-architecture.md +680 -0
  17. package/agent/design/relationship-storage-strategy.md +361 -0
  18. package/agent/design/remember-mcp-implementation-tasks.md +417 -0
  19. package/agent/design/remember-mcp-progress.yaml +141 -0
  20. package/agent/design/requirements-enhancements.md +468 -0
  21. package/agent/design/requirements.md +56 -0
  22. package/agent/design/template-storage-strategy.md +412 -0
  23. package/agent/design/template-suggestion-system.md +853 -0
  24. package/agent/design/trust-escalation-prevention.md +343 -0
  25. package/agent/design/trust-system-implementation.md +592 -0
  26. package/agent/design/user-preferences.md +683 -0
  27. package/agent/design/weaviate-collection-strategy.md +461 -0
  28. package/agent/milestones/.gitkeep +0 -0
  29. package/agent/milestones/milestone-1-project-foundation.md +121 -0
  30. package/agent/milestones/milestone-2-core-memory-system.md +150 -0
  31. package/agent/milestones/milestone-3-relationships-graph.md +116 -0
  32. package/agent/milestones/milestone-4-user-preferences.md +103 -0
  33. package/agent/milestones/milestone-5-template-system.md +126 -0
  34. package/agent/milestones/milestone-6-auth-multi-tenancy.md +124 -0
  35. package/agent/milestones/milestone-7-trust-permissions.md +133 -0
  36. package/agent/milestones/milestone-8-testing-quality.md +137 -0
  37. package/agent/milestones/milestone-9-deployment-documentation.md +147 -0
  38. package/agent/patterns/.gitkeep +0 -0
  39. package/agent/patterns/bootstrap.md +1271 -0
  40. package/agent/patterns/firebase-admin-sdk-v8-usage.md +950 -0
  41. package/agent/patterns/firestore-users-pattern-best-practices.md +347 -0
  42. package/agent/patterns/library-services.md +454 -0
  43. package/agent/patterns/testing-colocated.md +316 -0
  44. package/agent/progress.yaml +395 -0
  45. package/agent/tasks/.gitkeep +0 -0
  46. package/agent/tasks/task-1-initialize-project-structure.md +266 -0
  47. package/agent/tasks/task-2-install-dependencies.md +199 -0
  48. package/agent/tasks/task-3-setup-weaviate-client.md +330 -0
  49. package/agent/tasks/task-4-setup-firestore-client.md +362 -0
  50. package/agent/tasks/task-5-create-basic-mcp-server.md +114 -0
  51. package/agent/tasks/task-6-create-integration-tests.md +195 -0
  52. package/agent/tasks/task-7-finalize-milestone-1.md +363 -0
  53. package/agent/tasks/task-8-setup-utility-scripts.md +382 -0
  54. package/agent/tasks/task-9-create-server-factory.md +404 -0
  55. package/dist/config.d.ts +26 -0
  56. package/dist/constants/content-types.d.ts +60 -0
  57. package/dist/firestore/init.d.ts +14 -0
  58. package/dist/firestore/paths.d.ts +53 -0
  59. package/dist/firestore/paths.spec.d.ts +2 -0
  60. package/dist/server-factory.d.ts +40 -0
  61. package/dist/server-factory.js +1741 -0
  62. package/dist/server-factory.spec.d.ts +2 -0
  63. package/dist/server.d.ts +3 -0
  64. package/dist/server.js +1690 -0
  65. package/dist/tools/create-memory.d.ts +94 -0
  66. package/dist/tools/delete-memory.d.ts +47 -0
  67. package/dist/tools/search-memory.d.ts +88 -0
  68. package/dist/types/memory.d.ts +183 -0
  69. package/dist/utils/logger.d.ts +7 -0
  70. package/dist/weaviate/client.d.ts +39 -0
  71. package/dist/weaviate/client.spec.d.ts +2 -0
  72. package/dist/weaviate/schema.d.ts +29 -0
  73. package/esbuild.build.js +60 -0
  74. package/esbuild.watch.js +25 -0
  75. package/jest.config.js +31 -0
  76. package/jest.e2e.config.js +17 -0
  77. package/package.json +68 -0
  78. package/src/.gitkeep +0 -0
  79. package/src/config.ts +56 -0
  80. package/src/constants/content-types.ts +454 -0
  81. package/src/firestore/init.ts +68 -0
  82. package/src/firestore/paths.spec.ts +75 -0
  83. package/src/firestore/paths.ts +124 -0
  84. package/src/server-factory.spec.ts +60 -0
  85. package/src/server-factory.ts +215 -0
  86. package/src/server.ts +243 -0
  87. package/src/tools/create-memory.ts +198 -0
  88. package/src/tools/delete-memory.ts +126 -0
  89. package/src/tools/search-memory.ts +216 -0
  90. package/src/types/memory.ts +276 -0
  91. package/src/utils/logger.ts +42 -0
  92. package/src/weaviate/client.spec.ts +58 -0
  93. package/src/weaviate/client.ts +114 -0
  94. package/src/weaviate/schema.ts +288 -0
  95. package/tsconfig.json +26 -0
@@ -0,0 +1,454 @@
1
+ # Library Services Pattern
2
+
3
+ ## Overview
4
+
5
+ All data access operations (API calls, Firestore operations, external services) must go through dedicated service layer libraries. Direct calls from components, routes, or other non-service code are anti-patterns.
6
+
7
+ ## Service Types
8
+
9
+ ### 1. Database Services
10
+ **Purpose**: Direct Firestore/database operations
11
+ **Naming**: `{Domain}DatabaseService`
12
+ **File**: `{domain}-database.service.ts`
13
+ **Used By**: API routes, beforeLoad, server functions, cron jobs
14
+
15
+ **Characteristics**:
16
+ - Directly calls `getDocument`, `setDocument`, `queryDocuments`
17
+ - Server-side only (uses firebase-admin-sdk)
18
+ - Handles Zod validation
19
+ - Manages timestamps (created_at, updated_at)
20
+ - Returns typed data models
21
+
22
+ **Example**: `OAuthIntegrationDatabaseService`, `ConversationDatabaseService`
23
+
24
+ ### 2. API Services (Client Wrappers)
25
+ **Purpose**: Wrap API endpoint calls for client-side use
26
+ **Naming**: `{Domain}Service`
27
+ **File**: `{domain}.service.ts`
28
+ **Used By**: Components, client-side hooks
29
+
30
+ **Characteristics**:
31
+ - Calls `fetch('/api/...')`
32
+ - Client-side safe
33
+ - Handles HTTP errors
34
+ - Returns typed data models
35
+
36
+ **Example**: `IntegrationsService`, `UserService`
37
+
38
+ ## Naming Convention
39
+
40
+ **Key Insight**: Service class names indicate scope - no method suffixes needed!
41
+
42
+ ### Database Services
43
+ - **File**: `oauth-integration-database.service.ts`
44
+ - **Class**: `OAuthIntegrationDatabaseService`
45
+ - **Methods**: `getIntegration()`, `saveIntegration()`, `getUserIntegrations()`
46
+
47
+ ### API Services
48
+ - **File**: `integrations.service.ts`
49
+ - **Class**: `IntegrationsService`
50
+ - **Methods**: `getUserIntegrations()` (same name as database service!)
51
+
52
+ ### Benefits
53
+
54
+ ✅ **No method suffixes** - class name indicates scope
55
+ ✅ **Same method names** across services - consistent API
56
+ ✅ **Clear separation** - `DatabaseService` vs `Service`
57
+ ✅ **Import errors prevent misuse** - can't accidentally use database service in component
58
+ ✅ **Self-documenting** - name tells you everything
59
+
60
+ ## Architecture Diagram
61
+
62
+ ```
63
+ ┌─────────────────────────────────────────────────────────┐
64
+ │ Components │
65
+ │ (Client-Side Only) │
66
+ └────────────────────┬────────────────────────────────────┘
67
+
68
+ │ calls
69
+
70
+ ┌─────────────────────────────────────────────────────────┐
71
+ │ IntegrationsService │
72
+ │ (API Service - Client Layer) │
73
+ │ - getUserIntegrations() │
74
+ │ - Calls fetch('/api/integrations') │
75
+ └────────────────────┬────────────────────────────────────┘
76
+
77
+ │ HTTP
78
+
79
+ ┌─────────────────────────────────────────────────────────┐
80
+ │ API Routes │
81
+ │ (Server-Side Handlers) │
82
+ │ - /api/integrations/ │
83
+ │ - Validates session │
84
+ └────────────────────┬────────────────────────────────────┘
85
+
86
+ │ calls
87
+
88
+ ┌─────────────────────────────────────────────────────────┐
89
+ │ OAuthIntegrationDatabaseService │
90
+ │ (Database Service - Data Layer) │
91
+ │ - getUserIntegrations() │
92
+ │ - Calls getDocument(), setDocument() │
93
+ └────────────────────┬────────────────────────────────────┘
94
+
95
+ │ queries
96
+
97
+ ┌─────────────────────────────────────────────────────────┐
98
+ │ Firestore │
99
+ │ (Database Layer) │
100
+ └─────────────────────────────────────────────────────────┘
101
+ ```
102
+
103
+ ## When to Use Each Type
104
+
105
+ ### Use Database Services When:
106
+ - ✅ In API route handlers (server-side)
107
+ - ✅ In beforeLoad (server-side rendering)
108
+ - ✅ In server functions
109
+ - ✅ In other services (service can call service)
110
+ - ✅ In cron jobs or background tasks
111
+
112
+ ### Use API Services When:
113
+ - ✅ In React components (client-side)
114
+ - ✅ In `useEffect` hooks
115
+ - ✅ In event handlers (onClick, onSubmit)
116
+ - ✅ In custom hooks
117
+
118
+ ## Example Implementation
119
+
120
+ ### Database Service
121
+
122
+ **File**: `src/services/oauth-integration-database.service.ts`
123
+
124
+ ```typescript
125
+ import { getDocument, setDocument } from '@prmichaelsen/firebase-admin-sdk-v8'
126
+ import { getUserOAuthIntegration } from '@/constant/collections'
127
+ import { OAuthIntegrationSchema, type OAuthIntegration } from '@/schemas/oauth-integration'
128
+
129
+ export class OAuthIntegrationDatabaseService {
130
+ static async getIntegration(userId: string, provider: string): Promise<OAuthIntegration | null> {
131
+ try {
132
+ const path = getUserOAuthIntegration(userId, provider)
133
+ const doc = await getDocument(path, 'current')
134
+
135
+ if (!doc) return null
136
+
137
+ const result = OAuthIntegrationSchema.safeParse(doc)
138
+ if (!result.success) {
139
+ console.error(`Invalid OAuth integration data for ${provider}:`, result.error)
140
+ return null
141
+ }
142
+
143
+ return result.data
144
+ } catch (error) {
145
+ console.error(`Failed to get OAuth integration for ${provider}:`, error)
146
+ return null
147
+ }
148
+ }
149
+
150
+ static async saveIntegration(userId: string, provider: string, data: OAuthIntegrationInput): Promise<void> {
151
+ try {
152
+ const path = getUserOAuthIntegration(userId, provider)
153
+ const now = new Date().toISOString()
154
+
155
+ const integration: OAuthIntegration = {
156
+ ...data,
157
+ connected_at: now,
158
+ created_at: now,
159
+ updated_at: now,
160
+ }
161
+
162
+ await setDocument(path, 'current', integration)
163
+ console.log(`[OAuthIntegrationDatabaseService] Saved ${provider} integration for user ${userId}`)
164
+ } catch (error) {
165
+ console.error(`[OAuthIntegrationDatabaseService] Failed to save ${provider} integration:`, error)
166
+ throw error
167
+ }
168
+ }
169
+
170
+ static async getUserIntegrations(userId: string, providers: string[]): Promise<Record<string, OAuthIntegration>> {
171
+ const integrations: Record<string, OAuthIntegration> = {}
172
+
173
+ await Promise.all(
174
+ providers.map(async (provider) => {
175
+ const integration = await this.getIntegration(userId, provider)
176
+ if (integration && integration.connected) {
177
+ integrations[provider] = integration
178
+ }
179
+ })
180
+ )
181
+
182
+ return integrations
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### API Service
188
+
189
+ **File**: `src/services/integrations.service.ts`
190
+
191
+ ```typescript
192
+ import { OAuthIntegrationDatabaseService } from './oauth-integration-database.service'
193
+ import type { OAuthIntegration } from '@/schemas/oauth-integration'
194
+
195
+ export class IntegrationsService {
196
+ /**
197
+ * Get user's OAuth integrations (client-side)
198
+ * Calls the API endpoint which validates session server-side
199
+ */
200
+ static async getUserIntegrations(): Promise<Record<string, OAuthIntegration>> {
201
+ try {
202
+ const response = await fetch('/api/integrations/')
203
+
204
+ if (!response.ok) {
205
+ throw new Error(`Failed to fetch integrations: ${response.statusText}`)
206
+ }
207
+
208
+ const data: any = await response.json()
209
+ return data.integrations || {}
210
+ } catch (error) {
211
+ console.error('[IntegrationsService] Failed to fetch integrations:', error)
212
+ return {}
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ ## Usage Examples
219
+
220
+ ### In Component (Client-Side)
221
+
222
+ ```typescript
223
+ import { IntegrationsService } from '@/services/integrations.service'
224
+
225
+ function MyComponent() {
226
+ useEffect(() => {
227
+ IntegrationsService.getUserIntegrations() // Calls API
228
+ .then(integrations => setUserIntegrations(integrations))
229
+ }, [user])
230
+ }
231
+ ```
232
+
233
+ ### In API Route (Server-Side)
234
+
235
+ ```typescript
236
+ import { OAuthIntegrationDatabaseService } from '@/services/oauth-integration-database.service'
237
+
238
+ export const APIRoute = createAPIFileRoute('/api/integrations')({
239
+ GET: async ({ request }) => {
240
+ const session = await getServerSession(request)
241
+
242
+ const integrations = await OAuthIntegrationDatabaseService.getUserIntegrations(
243
+ session.user.uid,
244
+ ['instagram', 'eventbrite']
245
+ )
246
+
247
+ return Response.json({ integrations })
248
+ }
249
+ })
250
+ ```
251
+
252
+ ### In beforeLoad (Server-Side)
253
+
254
+ ```typescript
255
+ import { OAuthIntegrationDatabaseService } from '@/services/oauth-integration-database.service'
256
+
257
+ export const Route = createFileRoute('/integrations')({
258
+ beforeLoad: async () => {
259
+ const user = await getAuthSession()
260
+ if (!user) return { initialIntegrations: {} }
261
+
262
+ const initialIntegrations = await OAuthIntegrationDatabaseService.getUserIntegrations(
263
+ user.uid,
264
+ ['instagram', 'eventbrite']
265
+ )
266
+
267
+ return { initialIntegrations }
268
+ },
269
+ })
270
+ ```
271
+
272
+ ## Core Principles
273
+
274
+ ### 1. Service Layer Abstraction
275
+ - **All data operations** must be encapsulated in service classes
276
+ - Services provide a clean API for data access
277
+ - Services handle error logging and validation
278
+ - Services can be easily mocked for testing
279
+
280
+ ### 2. No Direct Database Calls
281
+ ```typescript
282
+ // ❌ ANTI-PATTERN: Direct Firestore call in component
283
+ import { setDocument } from '@prmichaelsen/firebase-admin-sdk-v8'
284
+
285
+ function MyComponent() {
286
+ const handleSave = async () => {
287
+ await setDocument('users', userId, data) // BAD!
288
+ }
289
+ }
290
+
291
+ // ✅ CORRECT: Use service layer
292
+ import { UserDatabaseService } from '@/services/user-database.service'
293
+
294
+ function MyComponent() {
295
+ const handleSave = async () => {
296
+ await UserDatabaseService.updateUser(userId, data) // GOOD!
297
+ }
298
+ }
299
+ ```
300
+
301
+ ### 3. No Direct API Calls
302
+ ```typescript
303
+ // ❌ ANTI-PATTERN: Direct fetch in component
304
+ function MyComponent() {
305
+ useEffect(() => {
306
+ fetch('/api/integrations') // BAD!
307
+ .then(res => res.json())
308
+ .then(data => setData(data))
309
+ }, [])
310
+ }
311
+
312
+ // ✅ CORRECT: Use service layer
313
+ import { IntegrationsService } from '@/services/integrations.service'
314
+
315
+ function MyComponent() {
316
+ useEffect(() => {
317
+ IntegrationsService.getUserIntegrations() // GOOD!
318
+ .then(integrations => setData(integrations))
319
+ }, [])
320
+ }
321
+ ```
322
+
323
+ ## Benefits
324
+
325
+ ### 1. Testability
326
+ ```typescript
327
+ // Easy to mock services in tests
328
+ jest.mock('@/services/integrations.service')
329
+
330
+ test('component loads integrations', async () => {
331
+ IntegrationsService.getUserIntegrations.mockResolvedValue({ instagram: {...} })
332
+ // Test component behavior
333
+ })
334
+ ```
335
+
336
+ ### 2. Consistency
337
+ - All Firestore operations follow same pattern
338
+ - Consistent error handling and logging
339
+ - Consistent Zod validation
340
+
341
+ ### 3. Maintainability
342
+ - Change database structure in one place
343
+ - Update API endpoints in one place
344
+ - Easy to add caching, retry logic, etc.
345
+
346
+ ### 4. Type Safety
347
+ - Services provide typed interfaces
348
+ - No `any` types leaking into components
349
+ - Zod validation at service boundary
350
+
351
+ ## Anti-Patterns to Avoid
352
+
353
+ ### ❌ Direct Firestore in Components
354
+ ```typescript
355
+ // BAD
356
+ function MyComponent() {
357
+ const handleSave = async () => {
358
+ await setDocument('users', userId, data)
359
+ }
360
+ }
361
+ ```
362
+
363
+ ### ❌ Direct Firestore in Routes
364
+ ```typescript
365
+ // BAD
366
+ export const Route = createFileRoute('/users')({
367
+ beforeLoad: async () => {
368
+ const doc = await getDocument('users', userId)
369
+ return { user: doc }
370
+ },
371
+ })
372
+ ```
373
+
374
+ ### ❌ Direct fetch in Components
375
+ ```typescript
376
+ // BAD
377
+ function MyComponent() {
378
+ useEffect(() => {
379
+ fetch('/api/data').then(...)
380
+ }, [])
381
+ }
382
+ ```
383
+
384
+ ### ❌ Mixing Concerns
385
+ ```typescript
386
+ // BAD: Service doing UI logic
387
+ static async saveUser(user: User): Promise<void> {
388
+ await setDocument(...)
389
+ toast.success('User saved!') // UI logic in service!
390
+ }
391
+ ```
392
+
393
+ ## Migration Guide
394
+
395
+ ### Step 1: Identify Direct Calls
396
+ Search codebase for:
397
+ - `setDocument(`
398
+ - `getDocument(`
399
+ - `queryDocuments(`
400
+ - `fetch('/api/`
401
+
402
+ ### Step 2: Create Services
403
+ ```typescript
404
+ // src/services/domain-database.service.ts
405
+ export class DomainDatabaseService {
406
+ static async operation(): Promise<Result> {
407
+ // Move database logic here
408
+ }
409
+ }
410
+
411
+ // src/services/domain.service.ts
412
+ export class DomainService {
413
+ static async operation(): Promise<Result> {
414
+ // Move API logic here
415
+ }
416
+ }
417
+ ```
418
+
419
+ ### Step 3: Update Callers
420
+ ```typescript
421
+ // Before
422
+ await setDocument(path, id, data)
423
+
424
+ // After (in API route)
425
+ await DomainDatabaseService.saveEntity(id, data)
426
+
427
+ // After (in component)
428
+ await DomainService.saveEntity(id, data)
429
+ ```
430
+
431
+ ### Step 4: Test
432
+ - Verify functionality unchanged
433
+ - Add unit tests for services
434
+ - Mock services in component tests
435
+
436
+ ## Summary
437
+
438
+ ✅ **DO**:
439
+ - Use `{Domain}DatabaseService` for database operations
440
+ - Use `{Domain}Service` for API wrappers
441
+ - Same method names across both service types
442
+ - Handle errors and validation in services
443
+ - Log operations in services
444
+ - Use Zod schemas for validation
445
+
446
+ ❌ **DON'T**:
447
+ - Call `setDocument`, `getDocument`, etc. directly
448
+ - Call `fetch('/api/...` directly
449
+ - Mix UI logic with data logic
450
+ - Skip error handling
451
+ - Use `any` types
452
+ - Add method suffixes - let class name indicate scope
453
+
454
+ **Every data operation should go through a service layer.**