fix: improve note interactions and markdown LaTeX support
## Bug Fixes ### Note Card Actions - Fix broken size change functionality (missing state declaration) - Implement React 19 useOptimistic for instant UI feedback - Add startTransition for non-blocking updates - Ensure smooth animations without page refresh - All note actions now work: pin, archive, color, size, checklist ### Markdown LaTeX Rendering - Add remark-math and rehype-katex plugins - Support inline equations with dollar sign syntax - Support block equations with double dollar sign syntax - Import KaTeX CSS for proper styling - Equations now render correctly instead of showing raw LaTeX ## Technical Details - Replace undefined currentNote references with optimistic state - Add optimistic updates before server actions for instant feedback - Use router.refresh() in transitions for smart cache invalidation - Install remark-math, rehype-katex, and katex packages ## Testing - Build passes successfully with no TypeScript errors - Dev server hot-reloads changes correctly
This commit is contained in:
447
docs/api-contracts-keep-notes.md
Normal file
447
docs/api-contracts-keep-notes.md
Normal file
@@ -0,0 +1,447 @@
|
||||
# API Contracts - keep-notes (Memento Web App)
|
||||
|
||||
## Overview
|
||||
|
||||
The keep-notes web application exposes REST API endpoints via Next.js App Router. All endpoints return JSON responses with a consistent format.
|
||||
|
||||
**Base URL:** `/api`
|
||||
**Authentication:** NextAuth session-based (required for most endpoints)
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"success": true|false,
|
||||
"data": any,
|
||||
"error": string // only present when success: false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes Endpoints
|
||||
|
||||
### GET /api/notes
|
||||
Get all notes with optional filtering.
|
||||
|
||||
**Authentication:** Not required (currently)
|
||||
|
||||
**Query Parameters:**
|
||||
- `archived` (boolean, optional): Include archived notes. Default: `false`
|
||||
- `search` (string, optional): Search in title and content (case-insensitive)
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "default|red|orange|yellow|green|teal|blue|purple|pink|gray",
|
||||
"isPinned": boolean,
|
||||
"isArchived": boolean,
|
||||
"type": "text|checklist",
|
||||
"checkItems": [
|
||||
{
|
||||
"id": "string",
|
||||
"text": "string",
|
||||
"checked": boolean
|
||||
}
|
||||
] | null,
|
||||
"labels": ["string"] | null,
|
||||
"images": ["string"] | null,
|
||||
"reminder": "ISO8601 datetime" | null,
|
||||
"isReminderDone": boolean,
|
||||
"reminderRecurrence": "none|daily|weekly|monthly|custom" | null,
|
||||
"reminderLocation": "string" | null,
|
||||
"isMarkdown": boolean,
|
||||
"size": "small|medium|large",
|
||||
"embedding": "JSON string" | null,
|
||||
"order": number,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response (500):**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Failed to fetch notes"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/notes
|
||||
Create a new note.
|
||||
|
||||
**Authentication:** Not required (currently)
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"title": "string (optional)",
|
||||
"content": "string (required unless type=checklist)",
|
||||
"color": "string (optional, default: 'default')",
|
||||
"type": "text|checklist (optional, default: 'text')",
|
||||
"checkItems": [
|
||||
{
|
||||
"id": "string",
|
||||
"text": "string",
|
||||
"checked": boolean
|
||||
}
|
||||
] (optional),
|
||||
"labels": ["string"] (optional),
|
||||
"images": ["string"] (optional, base64 encoded)
|
||||
}
|
||||
```
|
||||
|
||||
**Response (201 Created):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": { /* note object */ }
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400 Bad Request`: Content is required
|
||||
- `500 Internal Server Error`: Failed to create note
|
||||
|
||||
---
|
||||
|
||||
### PUT /api/notes
|
||||
Update an existing note.
|
||||
|
||||
**Authentication:** Not required (currently)
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"id": "string (required)",
|
||||
"title": "string (optional)",
|
||||
"content": "string (optional)",
|
||||
"color": "string (optional)",
|
||||
"type": "text|checklist (optional)",
|
||||
"checkItems": [...] (optional),
|
||||
"labels": ["string"] (optional),
|
||||
"isPinned": boolean (optional),
|
||||
"isArchived": boolean (optional),
|
||||
"images": ["string"] (optional)
|
||||
}
|
||||
```
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": { /* updated note object */ }
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400 Bad Request`: Note ID is required
|
||||
- `500 Internal Server Error`: Failed to update note
|
||||
|
||||
---
|
||||
|
||||
### DELETE /api/notes?id=xxx
|
||||
Delete a note by ID.
|
||||
|
||||
**Authentication:** Not required (currently)
|
||||
|
||||
**Query Parameters:**
|
||||
- `id` (string, required): Note ID
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Note deleted successfully"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400 Bad Request`: Note ID is required
|
||||
- `500 Internal Server Error`: Failed to delete note
|
||||
|
||||
---
|
||||
|
||||
## Labels Endpoints
|
||||
|
||||
### GET /api/labels
|
||||
Get all labels for the authenticated user.
|
||||
|
||||
**Authentication:** Required (NextAuth session)
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"name": "string",
|
||||
"color": "red|orange|yellow|green|teal|blue|purple|pink|gray",
|
||||
"userId": "string",
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response (401 Unauthorized):**
|
||||
```json
|
||||
{
|
||||
"error": "Unauthorized"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### POST /api/labels
|
||||
Create a new label.
|
||||
|
||||
**Authentication:** Required (NextAuth session)
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"name": "string (required)",
|
||||
"color": "string (optional, random color if not provided)"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": { /* label object */ }
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400 Bad Request`: Label name is required
|
||||
- `401 Unauthorized`: Not authenticated
|
||||
- `409 Conflict`: Label already exists for this user
|
||||
- `500 Internal Server Error`: Failed to create label
|
||||
|
||||
---
|
||||
|
||||
### DELETE /api/labels/{id}
|
||||
Delete a label by ID.
|
||||
|
||||
**Authentication:** Required (NextAuth session)
|
||||
|
||||
**URL Parameters:**
|
||||
- `id` (string): Label ID
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Label deleted successfully"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `401 Unauthorized`: Not authenticated
|
||||
- `500 Internal Server Error`: Failed to delete label
|
||||
|
||||
---
|
||||
|
||||
## Authentication Endpoints
|
||||
|
||||
### GET/POST /api/auth/[...nextauth]
|
||||
NextAuth.js authentication handler.
|
||||
|
||||
**Authentication:** Not required (this is the auth endpoint)
|
||||
|
||||
All NextAuth operations are handled by this route:
|
||||
- Sign in
|
||||
- Sign out
|
||||
- Session management
|
||||
- OAuth callbacks
|
||||
- Email verification
|
||||
|
||||
**Implementation:** Delegates to `@/auth` configuration
|
||||
|
||||
---
|
||||
|
||||
## AI Endpoints
|
||||
|
||||
### POST /api/ai/tags
|
||||
Generate intelligent tags for a note using AI.
|
||||
|
||||
**Authentication:** Not specified (likely required)
|
||||
|
||||
**Request Body:** (to be determined from implementation)
|
||||
|
||||
**Response:** (to be determined from implementation)
|
||||
|
||||
---
|
||||
|
||||
### POST /api/ai/test
|
||||
Test AI integration.
|
||||
|
||||
**Authentication:** Not specified (likely required)
|
||||
|
||||
**Request Body:** (to be determined from implementation)
|
||||
|
||||
**Response:** (to be determined from implementation)
|
||||
|
||||
---
|
||||
|
||||
## Admin Endpoints
|
||||
|
||||
### POST /api/admin/randomize-labels
|
||||
Randomize label colors (admin functionality).
|
||||
|
||||
**Authentication:** Required (admin role)
|
||||
|
||||
**Request Body:** (to be determined from implementation)
|
||||
|
||||
**Response:** (to be determined from implementation)
|
||||
|
||||
---
|
||||
|
||||
### POST /api/admin/sync-labels
|
||||
Synchronize labels across the system (admin functionality).
|
||||
|
||||
**Authentication:** Required (admin role)
|
||||
|
||||
**Request Body:** (to be determined from implementation)
|
||||
|
||||
**Response:** (to be determined from implementation)
|
||||
|
||||
---
|
||||
|
||||
## Upload Endpoint
|
||||
|
||||
### POST /api/upload
|
||||
Upload files (e.g., images for notes).
|
||||
|
||||
**Authentication:** Not specified
|
||||
|
||||
**Request Body:** multipart/form-data
|
||||
|
||||
**Response:** (to be determined from implementation)
|
||||
|
||||
---
|
||||
|
||||
## Cron/Reminder Endpoint
|
||||
|
||||
### POST /api/cron/reminders
|
||||
Scheduled job for handling reminders.
|
||||
|
||||
**Authentication:** Not required (cron job)
|
||||
|
||||
**Request Body:** (to be determined from implementation)
|
||||
|
||||
**Response:** (to be determined from implementation)
|
||||
|
||||
---
|
||||
|
||||
## Debug Endpoints
|
||||
|
||||
### POST /api/debug/search
|
||||
Debug search functionality.
|
||||
|
||||
**Authentication:** Not specified (admin/debug only)
|
||||
|
||||
**Request Body:** (to be determined from implementation)
|
||||
|
||||
**Response:** (to be determined from implementation)
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### Note Model (Prisma)
|
||||
```prisma
|
||||
model Note {
|
||||
id String @id @default(cuid())
|
||||
title String?
|
||||
content String
|
||||
color String @default("default")
|
||||
isPinned Boolean @default(false)
|
||||
isArchived Boolean @default(false)
|
||||
type String @default("text")
|
||||
checkItems String? // JSON array
|
||||
labels String? // JSON array
|
||||
images String? // JSON array
|
||||
links String? // JSON array
|
||||
reminder DateTime?
|
||||
isReminderDone Boolean @default(false)
|
||||
reminderRecurrence String?
|
||||
reminderLocation String?
|
||||
isMarkdown Boolean @default(false)
|
||||
size String @default("small")
|
||||
embedding String? // JSON vector
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
order Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([isPinned])
|
||||
@@index([isArchived])
|
||||
@@index([order])
|
||||
@@index([reminder])
|
||||
@@index([userId])
|
||||
}
|
||||
```
|
||||
|
||||
### Label Model (Prisma)
|
||||
```prisma
|
||||
model Label {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
color String @default("gray")
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([name, userId])
|
||||
@@index([userId])
|
||||
}
|
||||
```
|
||||
|
||||
### User Model (Prisma)
|
||||
```prisma
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
password String?
|
||||
role String @default("USER")
|
||||
image String?
|
||||
theme String @default("light")
|
||||
resetToken String? @unique
|
||||
resetTokenExpiry DateTime?
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
notes Note[]
|
||||
labels Label[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- **State Management**: Server actions and API routes (no dedicated state management library detected)
|
||||
- **Database**: SQLite via Prisma ORM with better-sqlite3 adapter
|
||||
- **Authentication**: NextAuth.js v5 with Prisma adapter
|
||||
- **Error Handling**: All endpoints return consistent error format
|
||||
- **JSON Parsing**: Arrays (checkItems, labels, images) stored as JSON strings in DB, parsed in API layer
|
||||
- **Ordering**: Notes sorted by `isPinned DESC`, then `order ASC`, then `updatedAt DESC`
|
||||
- **Search**: Case-insensitive search across title and content fields
|
||||
452
docs/api-contracts-mcp-server.md
Normal file
452
docs/api-contracts-mcp-server.md
Normal file
@@ -0,0 +1,452 @@
|
||||
# API Contracts - mcp-server (Memento MCP Server)
|
||||
|
||||
## Overview
|
||||
|
||||
The mcp-server provides a Model Context Protocol (MCP) interface for integrating Memento with AI assistants and automation tools like N8N. It exposes tools (functions) that can be called via the MCP protocol.
|
||||
|
||||
**Protocol:** Model Context Protocol (MCP) SDK v1.0.4
|
||||
**Transport:** Stdio (standard input/output)
|
||||
**Type:** JavaScript ES modules
|
||||
**Database:** Shared Prisma SQLite database (connects to `keep-notes/prisma/dev.db`)
|
||||
|
||||
---
|
||||
|
||||
## MCP Tools
|
||||
|
||||
The server exposes the following MCP tools that can be invoked by MCP clients:
|
||||
|
||||
---
|
||||
|
||||
### create_note
|
||||
Create a new note in Memento.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"title": "string (optional) - Note title",
|
||||
"content": "string (required) - Note content",
|
||||
"color": "string (optional, default: 'default') - Note color: default|red|orange|yellow|green|teal|blue|purple|pink|gray",
|
||||
"type": "string (optional, default: 'text') - Note type: 'text' or 'checklist'",
|
||||
"checkItems": "array (optional) - Checklist items (if type is 'checklist')",
|
||||
"labels": "array (optional) - Note labels/tags",
|
||||
"isPinned": "boolean (optional, default: false) - Pin the note",
|
||||
"isArchived": "boolean (optional, default: false) - Archive the note",
|
||||
"images": "array (optional) - Note images as base64 encoded strings"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "string",
|
||||
"type": "text|checklist",
|
||||
"checkItems": [...] | null,
|
||||
"labels": [...] | null,
|
||||
"images": [...] | null,
|
||||
"isPinned": boolean,
|
||||
"isArchived": boolean,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on failure
|
||||
|
||||
---
|
||||
|
||||
### get_notes
|
||||
Get all notes from Memento with optional filtering.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"includeArchived": "boolean (optional, default: false) - Include archived notes",
|
||||
"search": "string (optional) - Search query to filter notes (case-insensitive)"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "string",
|
||||
"isPinned": boolean,
|
||||
"isArchived": boolean,
|
||||
"type": "text|checklist",
|
||||
"checkItems": [...] | null,
|
||||
"labels": [...] | null,
|
||||
"images": [...] | null,
|
||||
"order": number,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Ordering:** `isPinned DESC`, `order ASC`, `updatedAt DESC`
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on failure
|
||||
|
||||
---
|
||||
|
||||
### get_note
|
||||
Get a specific note by ID.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"id": "string (required) - Note ID"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "string",
|
||||
"isPinned": boolean,
|
||||
"isArchived": boolean,
|
||||
"type": "text|checklist",
|
||||
"checkItems": [...] | null,
|
||||
"labels": [...] | null,
|
||||
"images": [...] | null,
|
||||
"reminder": "ISO8601 datetime" | null,
|
||||
"isReminderDone": boolean,
|
||||
"reminderRecurrence": "string" | null,
|
||||
"reminderLocation": "string" | null,
|
||||
"isMarkdown": boolean,
|
||||
"size": "small|medium|large",
|
||||
"embedding": "JSON string" | null,
|
||||
"userId": "string" | null,
|
||||
"order": number,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InvalidRequest` if note not found
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on other failures
|
||||
|
||||
---
|
||||
|
||||
### update_note
|
||||
Update an existing note.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"id": "string (required) - Note ID",
|
||||
"title": "string (optional) - Note title",
|
||||
"content": "string (optional) - Note content",
|
||||
"color": "string (optional) - Note color",
|
||||
"checkItems": "array (optional) - Checklist items",
|
||||
"labels": "array (optional) - Note labels",
|
||||
"isPinned": "boolean (optional) - Pin status",
|
||||
"isArchived": "boolean (optional) - Archive status",
|
||||
"images": "array (optional) - Note images as base64 encoded strings"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "string",
|
||||
"type": "text|checklist",
|
||||
"checkItems": [...] | null,
|
||||
"labels": [...] | null,
|
||||
"images": [...] | null,
|
||||
"isPinned": boolean,
|
||||
"isArchived": boolean,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Automatically updates `updatedAt` timestamp
|
||||
- Arrays (checkItems, labels, images) are JSON-encoded before storage
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on failure
|
||||
|
||||
---
|
||||
|
||||
### delete_note
|
||||
Delete a note by ID.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"id": "string (required) - Note ID"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Note deleted"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on failure
|
||||
|
||||
---
|
||||
|
||||
### search_notes
|
||||
Search notes by query.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"query": "string (required) - Search query"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "string",
|
||||
"isPinned": boolean,
|
||||
"isArchived": boolean,
|
||||
"type": "text|checklist",
|
||||
"checkItems": [...] | null,
|
||||
"labels": [...] | null,
|
||||
"images": [...] | null,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Search Logic:**
|
||||
- Only searches non-archived notes (`isArchived: false`)
|
||||
- Case-insensitive search across `title` and `content` fields
|
||||
- Uses SQL `LIKE` operator (contains matching)
|
||||
|
||||
**Ordering:** `isPinned DESC`, `updatedAt DESC`
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on failure
|
||||
|
||||
---
|
||||
|
||||
### get_labels
|
||||
Get all unique labels from all notes.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
[
|
||||
"label1",
|
||||
"label2",
|
||||
"label3"
|
||||
]
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Extracts labels from all notes in the database
|
||||
- Labels are stored as JSON arrays in the `labels` field
|
||||
- Returns unique, sorted list of all label strings
|
||||
- Does not create or use the Label table (reads directly from Note.labels)
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on failure
|
||||
|
||||
---
|
||||
|
||||
### toggle_pin
|
||||
Toggle pin status of a note.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"id": "string (required) - Note ID"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "string",
|
||||
"isPinned": boolean, // Toggled value
|
||||
"isArchived": boolean,
|
||||
"type": "text|checklist",
|
||||
"checkItems": [...] | null,
|
||||
"labels": [...] | null,
|
||||
"images": [...] | null,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InvalidRequest` if note not found
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on other failures
|
||||
|
||||
---
|
||||
|
||||
### toggle_archive
|
||||
Toggle archive status of a note.
|
||||
|
||||
**Parameters:**
|
||||
```json
|
||||
{
|
||||
"id": "string (required) - Note ID"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (text content):**
|
||||
```json
|
||||
{
|
||||
"id": "clxxxxxxx",
|
||||
"title": "string or null",
|
||||
"content": "string",
|
||||
"color": "string",
|
||||
"isPinned": boolean,
|
||||
"isArchived": boolean, // Toggled value
|
||||
"type": "text|checklist",
|
||||
"checkItems": [...] | null,
|
||||
"labels": [...] | null,
|
||||
"images": [...] | null,
|
||||
"createdAt": "ISO8601 datetime",
|
||||
"updatedAt": "ISO8601 datetime"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
- Throws `McpError` with `ErrorCode.InvalidRequest` if note not found
|
||||
- Throws `McpError` with `ErrorCode.InternalError` on other failures
|
||||
|
||||
---
|
||||
|
||||
## Server Information
|
||||
|
||||
**Name:** `memento-mcp-server`
|
||||
**Version:** `1.0.0`
|
||||
**Capabilities:** Tools only (no resources or prompts)
|
||||
|
||||
## Connection Details
|
||||
|
||||
**Transport:** Stdio (Standard Input/Output)
|
||||
**Entry Point:** `index.js`
|
||||
**Alternative SSE Endpoint:** `index-sse.js` (Server-Sent Events variant)
|
||||
|
||||
## Database Connection
|
||||
|
||||
```javascript
|
||||
const prisma = new PrismaClient({
|
||||
datasources: {
|
||||
db: {
|
||||
url: `file:${join(__dirname, '../keep-notes/prisma/dev.db')}`
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Important:** The MCP server connects directly to the keep-notes SQLite database file, sharing the same data as the web application.
|
||||
|
||||
## Error Handling
|
||||
|
||||
All errors are returned as MCP errors with appropriate error codes:
|
||||
- `ErrorCode.InvalidRequest`: Invalid parameters or resource not found
|
||||
- `ErrorCode.MethodNotFound`: Unknown tool requested
|
||||
- `ErrorCode.InternalError`: Server-side errors (database, parsing, etc.)
|
||||
|
||||
## Usage Example
|
||||
|
||||
With N8N or MCP-compatible client:
|
||||
|
||||
```javascript
|
||||
// List available tools
|
||||
server.tools()
|
||||
|
||||
// Create a note
|
||||
server.callTool('create_note', {
|
||||
title: 'Meeting Notes',
|
||||
content: 'Discussed Q1 roadmap...',
|
||||
labels: ['work', 'planning'],
|
||||
color: 'blue'
|
||||
})
|
||||
|
||||
// Search notes
|
||||
server.callTool('search_notes', {
|
||||
query: 'roadmap'
|
||||
})
|
||||
|
||||
// Toggle pin
|
||||
server.callTool('toggle_pin', {
|
||||
id: 'clxxxxxxx'
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Helper Functions
|
||||
|
||||
### parseNote(dbNote)
|
||||
Internal helper to parse JSON fields from database:
|
||||
|
||||
```javascript
|
||||
function parseNote(dbNote) {
|
||||
return {
|
||||
...dbNote,
|
||||
checkItems: dbNote.checkItems ? JSON.parse(dbNote.checkItems) : null,
|
||||
labels: dbNote.labels ? JSON.parse(dbNote.labels) : null,
|
||||
images: dbNote.images ? JSON.parse(dbNote.images) : null,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
This function is called on all note objects returned to clients to ensure JSON arrays are properly parsed from their string representation in the database.
|
||||
|
||||
---
|
||||
|
||||
## Integration with N8N
|
||||
|
||||
The MCP server is designed to work with N8N workflows:
|
||||
1. Install N8N MCP integration
|
||||
2. Configure connection to `memento-mcp-server`
|
||||
3. Use tools in N8N nodes:
|
||||
- Create notes from external sources
|
||||
- Search and retrieve notes
|
||||
- Update notes based on triggers
|
||||
- Archive/delete old notes
|
||||
- Extract labels for categorization
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- **No Authentication:** MCP server runs with direct database access (no auth layer)
|
||||
- **Shared Database:** Uses same SQLite file as keep-notes web app
|
||||
- **JSON Encoding:** Array fields (checkItems, labels, images) stored as JSON strings
|
||||
- **Idempotent Operations:** Toggle operations (pin, archive) are idempotent
|
||||
- **Case-Insensitive Search:** Search operations use `mode: 'insensitive'`
|
||||
- **Ordering:** Results sorted by relevance (pinned first, then by date)
|
||||
671
docs/architecture-keep-notes.md
Normal file
671
docs/architecture-keep-notes.md
Normal file
@@ -0,0 +1,671 @@
|
||||
# Architecture - keep-notes (Memento Web App)
|
||||
|
||||
## Overview
|
||||
|
||||
Complete system architecture for the Memento web application, a Next.js 16 full-stack application using the App Router architecture pattern.
|
||||
|
||||
**Architecture Pattern:** Full-stack JAMstack with Server-Side Rendering (SSR)
|
||||
**Framework:** Next.js 16.1.1 (App Router)
|
||||
**Language:** TypeScript 5
|
||||
**Database:** SQLite via Prisma ORM
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Frontend
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| React | 19.2.3 | UI library |
|
||||
| Next.js | 16.1.1 | Full-stack framework |
|
||||
| TypeScript | 5.x | Type safety |
|
||||
| Tailwind CSS | 4.x | Styling |
|
||||
| Radix UI | Multiple | Component primitives |
|
||||
| Lucide React | 0.562.0 | Icons |
|
||||
|
||||
### Backend (Integrated)
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| Next.js API Routes | Built-in | REST API |
|
||||
| Prisma | 5.22.0 | ORM |
|
||||
| better-sqlite3 | 12.5.0 | SQLite driver |
|
||||
| @libsql/client | 0.15.15 | Alternative DB client |
|
||||
| NextAuth | 5.0.0-beta.30 | Authentication |
|
||||
|
||||
### AI/LLM
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| Vercel AI SDK | 6.0.23 | AI integration |
|
||||
| OpenAI Provider | 3.0.7 | GPT models |
|
||||
| Ollama Provider | 1.2.0 | Local models |
|
||||
|
||||
### Additional
|
||||
- @dnd-kit (drag and drop)
|
||||
- Muuri (masonry grid)
|
||||
- react-markdown (markdown rendering)
|
||||
- nodemailer (email)
|
||||
- bcryptjs (password hashing)
|
||||
- Zod (validation)
|
||||
- Playwright (testing)
|
||||
|
||||
---
|
||||
|
||||
## Architecture Pattern: JAMstack with App Router
|
||||
|
||||
### Request Flow
|
||||
|
||||
```
|
||||
User Browser
|
||||
↓
|
||||
Next.js App Router
|
||||
↓
|
||||
├─────────────────┬─────────────────┐
|
||||
│ │ │
|
||||
React Server API Routes Server Actions
|
||||
Components (REST) (Mutations)
|
||||
│ │ │
|
||||
└─────────────────┴─────────────────┘
|
||||
↓
|
||||
Prisma ORM
|
||||
↓
|
||||
SQLite Database
|
||||
```
|
||||
|
||||
### Rendering Strategy
|
||||
- **Server Components:** Default (faster initial load, SEO friendly)
|
||||
- **Client Components:** Interactive features (drag-drop, forms)
|
||||
- **Streaming:** Progressive rendering with Suspense
|
||||
- **ISR:** Not used (dynamic content)
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure (App Router)
|
||||
|
||||
```
|
||||
app/
|
||||
├── (auth)/ # Auth route group
|
||||
│ ├── layout.tsx # Auth layout
|
||||
│ ├── login/page.tsx # Login page
|
||||
│ ├── register/page.tsx # Register page
|
||||
│ └── [reset flows]/ # Password reset
|
||||
│
|
||||
├── (main)/ # Main app route group
|
||||
│ ├── layout.tsx # Main layout
|
||||
│ ├── page.tsx # Home/dashboard
|
||||
│ ├── admin/ # Admin panel
|
||||
│ ├── archive/ # Archived notes
|
||||
│ └── settings/ # User settings
|
||||
│
|
||||
├── actions/ # Server actions
|
||||
│ ├── notes.ts # Note mutations
|
||||
│ ├── register.ts # User registration
|
||||
│ └── [other actions] # Additional mutations
|
||||
│
|
||||
├── api/ # REST API
|
||||
│ ├── auth/[...nextauth]/ # NextAuth handler
|
||||
│ ├── notes/ # Note CRUD
|
||||
│ ├── labels/ # Label CRUD
|
||||
│ ├── ai/ # AI endpoints
|
||||
│ ├── admin/ # Admin endpoints
|
||||
│ └── [other routes] # Additional endpoints
|
||||
│
|
||||
├── globals.css # Global styles
|
||||
└── layout.tsx # Root layout
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Architecture
|
||||
|
||||
### Component Hierarchy
|
||||
|
||||
```
|
||||
layout.tsx (Root)
|
||||
├── HeaderWrapper
|
||||
│ ├── Header
|
||||
│ │ ├── Logo/Title
|
||||
│ │ └── UserNav
|
||||
│ └── [Auth providers]
|
||||
│
|
||||
├── Sidebar (collapsible)
|
||||
│ ├── Navigation
|
||||
│ └── Filters
|
||||
│
|
||||
└── Page Content
|
||||
└── MasonryGrid
|
||||
└── NoteCard[n]
|
||||
├── NoteEditor
|
||||
├── NoteChecklist
|
||||
├── NoteImages
|
||||
└── NoteActions
|
||||
```
|
||||
|
||||
### State Management
|
||||
|
||||
**No Global State Library** (Redux, Zustand, etc.)
|
||||
|
||||
**State Strategies:**
|
||||
1. **Server State:** Fetched from API, cached with React Cache
|
||||
2. **URL State:** Search params, route params
|
||||
3. **Form State:** Controlled components with useState
|
||||
4. **Context:** User session, theme preference
|
||||
5. **Server Actions:** Mutations that update DB
|
||||
|
||||
**Data Flow:**
|
||||
```
|
||||
User Action
|
||||
↓
|
||||
Server Action / API Call
|
||||
↓
|
||||
Prisma Mutation
|
||||
↓
|
||||
Database Update
|
||||
↓
|
||||
Revalidate / Refetch
|
||||
↓
|
||||
UI Update
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Architecture
|
||||
|
||||
### REST Endpoints
|
||||
|
||||
**Base URL:** `/api`
|
||||
|
||||
**Authentication:** NextAuth session (most endpoints)
|
||||
|
||||
**Endpoints:**
|
||||
|
||||
| Method | Endpoint | Purpose | Auth |
|
||||
|--------|----------|---------|------|
|
||||
| GET | `/api/notes` | List notes | No (currently) |
|
||||
| POST | `/api/notes` | Create note | No (currently) |
|
||||
| PUT | `/api/notes` | Update note | No (currently) |
|
||||
| DELETE | `/api/notes` | Delete note | No (currently) |
|
||||
| GET | `/api/labels` | List labels | Yes |
|
||||
| POST | `/api/labels` | Create label | Yes |
|
||||
| DELETE | `/api/labels/{id}` | Delete label | Yes |
|
||||
| GET/POST | `/api/auth/[...nextauth]` | Auth handler | No (this is auth) |
|
||||
| POST | `/api/ai/tags` | Auto-tagging | TBD |
|
||||
| POST | `/api/upload` | File upload | TBD |
|
||||
| POST | `/api/admin/*` | Admin ops | Yes (admin) |
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"success": true|false,
|
||||
"data": any,
|
||||
"error": string // only when success: false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Server Actions Architecture
|
||||
|
||||
**Location:** `app/actions/`
|
||||
|
||||
**Purpose:** Mutations that bypass REST, direct server-side execution
|
||||
|
||||
**Examples:**
|
||||
- `notes.ts`: Create, update, delete notes
|
||||
- `register.ts`: User registration
|
||||
- `scrape.ts`: Web scraping for link previews
|
||||
|
||||
**Benefits:**
|
||||
- Type-safe (from schema)
|
||||
- No API layer needed
|
||||
- Direct database access
|
||||
- Form validation (Zod)
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
// Client component
|
||||
import { createNote } from '@/app/actions/notes'
|
||||
|
||||
function NoteForm() {
|
||||
async function handleSubmit(data) {
|
||||
await createNote(data) // Server action
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database Architecture
|
||||
|
||||
### ORM: Prisma
|
||||
|
||||
**Schema Location:** `prisma/schema.prisma`
|
||||
**Migrations:** `prisma/migrations/` (13 migrations)
|
||||
**Database File:** `prisma/dev.db`
|
||||
|
||||
**Models:**
|
||||
- User (authentication, profile)
|
||||
- Account (OAuth providers)
|
||||
- Session (active sessions)
|
||||
- VerificationToken (email verification)
|
||||
- Note (core data model)
|
||||
- Label (tags/categories)
|
||||
- SystemConfig (key-value store)
|
||||
|
||||
**Connection:**
|
||||
```typescript
|
||||
// lib/prisma.ts
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import { PrismaLibSQL } from '@prisma/adapter-libsql'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
```
|
||||
|
||||
**Adapters:**
|
||||
- `@prisma/adapter-better-sqlite3` (primary - local dev)
|
||||
- `@prisma/adapter-libsql` (alternative - Turso cloud)
|
||||
|
||||
---
|
||||
|
||||
## Authentication Architecture
|
||||
|
||||
### NextAuth.js v5
|
||||
|
||||
**Configuration:** `auth.config.ts`
|
||||
**Implementation:** `auth.ts`
|
||||
|
||||
**Providers:**
|
||||
- Credentials (email/password)
|
||||
- OAuth options (Google, GitHub, etc.)
|
||||
|
||||
**Strategy:**
|
||||
1. User submits credentials
|
||||
2. NextAuth validates against database
|
||||
3. Session created in `Session` table
|
||||
4. JWT token issued
|
||||
5. Session stored in HTTP-only cookie
|
||||
|
||||
**Session Management:**
|
||||
- Server-side sessions in database
|
||||
- HTTP-only cookies for security
|
||||
- Automatic token refresh
|
||||
|
||||
**Password Security:**
|
||||
- bcryptjs hashing (cost factor: default)
|
||||
- Password reset flow with tokens
|
||||
- Reset token stored in `User.resetToken`
|
||||
|
||||
**User Roles:**
|
||||
- `USER` (default)
|
||||
- `ADMIN` (elevated permissions)
|
||||
- Role-based access control in API routes
|
||||
|
||||
---
|
||||
|
||||
## AI Integration Architecture
|
||||
|
||||
### Provider Pattern
|
||||
|
||||
**Location:** `lib/ai/providers/`
|
||||
|
||||
**Providers:**
|
||||
- OpenAI (`ollama.ts` is misnamed, should be `openai.ts` or separate)
|
||||
- Ollama (`ollama.ts` - local models)
|
||||
|
||||
**Factory Pattern:**
|
||||
```typescript
|
||||
// lib/ai/factory.ts
|
||||
export function createProvider(provider: string) {
|
||||
switch (provider) {
|
||||
case 'openai': return new OpenAIProvider()
|
||||
case 'ollama': return new OllamaProvider()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Auto-tagging (suggest labels for notes)
|
||||
- Semantic search (vector embeddings)
|
||||
- Content summarization (future)
|
||||
- Smart categorization (future)
|
||||
|
||||
**AI SDK Usage:**
|
||||
```typescript
|
||||
import { generateText } from 'ai'
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
|
||||
const response = await generateText({
|
||||
model: openai('gpt-4'),
|
||||
prompt: note.content
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Feature Architecture
|
||||
|
||||
### Note Management
|
||||
|
||||
**Data Flow:**
|
||||
1. User creates note → `NoteInput` component
|
||||
2. Server action → `app/actions/notes.ts`
|
||||
3. Prisma create → `Note` table
|
||||
4. Revalidate → UI updates
|
||||
5. Real-time → No WebSocket currently
|
||||
|
||||
**Search:**
|
||||
- Text search: SQL `LIKE` queries (case-insensitive)
|
||||
- Semantic search: Vector embeddings (JSON field)
|
||||
- Filtering: By labels, archived status, pinned status
|
||||
|
||||
**Organization:**
|
||||
- Pinning: `isPinned` boolean
|
||||
- Archiving: `isArchived` boolean
|
||||
- Ordering: `order` field (drag-drop)
|
||||
- Colors: `color` string
|
||||
- Size: `size` (small, medium, large)
|
||||
|
||||
### Label System
|
||||
|
||||
**Two Approaches:**
|
||||
1. **Label Table:** `Label` model with user ownership
|
||||
2. **Note Labels:** JSON array in `Note.labels`
|
||||
|
||||
**Current State:** Both exist (migration artifact)
|
||||
- `Label` table: User-managed labels
|
||||
- `Note.labels`: JSON array of label names
|
||||
|
||||
**Future:** Consolidate to one approach
|
||||
|
||||
### Reminder System
|
||||
|
||||
**Fields:**
|
||||
- `reminder`: DateTime for reminder
|
||||
- `isReminderDone`: Completed flag
|
||||
- `reminderRecurrence`: none, daily, weekly, monthly, custom
|
||||
- `reminderLocation`: Location-based (future)
|
||||
|
||||
**Cron Job:**
|
||||
- Route: `/api/cron/reminders`
|
||||
- Triggered by external cron service
|
||||
- Checks due reminders
|
||||
- Sends notifications (nodemailer)
|
||||
|
||||
### Image Handling
|
||||
|
||||
**Storage Options:**
|
||||
1. Base64 encoded in `Note.images` JSON array
|
||||
2. File uploads to `public/uploads/notes/`
|
||||
|
||||
**Current:** Both supported
|
||||
- Base64 for small images
|
||||
- File uploads for larger images
|
||||
|
||||
**Future:** Move to CDN (S3, Cloudinary, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Performance Architecture
|
||||
|
||||
### Server-Side Rendering (SSR)
|
||||
- Faster initial page load
|
||||
- SEO friendly
|
||||
- Progressive enhancement
|
||||
|
||||
### Code Splitting
|
||||
- Route-based splitting (automatic)
|
||||
- Dynamic imports for heavy components
|
||||
|
||||
### Data Fetching
|
||||
- React Cache for deduplication
|
||||
- Server Actions for mutations
|
||||
- Streaming responses
|
||||
|
||||
### Database Optimization
|
||||
- Indexed fields (isPinned, isArchived, order, reminder, userId)
|
||||
- Efficient queries with Prisma
|
||||
- Connection pooling (limited in SQLite)
|
||||
|
||||
---
|
||||
|
||||
## Security Architecture
|
||||
|
||||
### Authentication
|
||||
- NextAuth session management
|
||||
- HTTP-only cookies
|
||||
- CSRF protection (NextAuth built-in)
|
||||
- Password hashing (bcrypt)
|
||||
|
||||
### Authorization
|
||||
- Role-based access control (USER, ADMIN)
|
||||
- Session validation in API routes
|
||||
- Protected routes (middleware)
|
||||
|
||||
### Data Validation
|
||||
- Zod schemas for input validation
|
||||
- TypeScript for type safety
|
||||
- SQL injection prevention (Prisma)
|
||||
- XSS protection (React escaping)
|
||||
|
||||
### Future Security Enhancements
|
||||
- Rate limiting
|
||||
- CSRF tokens for forms
|
||||
- Content Security Policy (CSP)
|
||||
- HTTPS enforcement in production
|
||||
|
||||
---
|
||||
|
||||
## Deployment Architecture
|
||||
|
||||
### Current: Local Development
|
||||
```bash
|
||||
npm run dev # Next.js dev server
|
||||
# Runs on http://localhost:3000
|
||||
```
|
||||
|
||||
### Production Deployment (Planned)
|
||||
**Container:** Docker
|
||||
**Orchestration:** Docker Compose
|
||||
**Process:**
|
||||
1. Build Next.js app: `npm run build`
|
||||
2. Start production server: `npm start`
|
||||
3. Serve with Node.js or Docker
|
||||
|
||||
**Environment Variables:**
|
||||
- `DATABASE_URL`: SQLite file path
|
||||
- `NEXTAUTH_SECRET`: Session secret
|
||||
- `NEXTAUTH_URL`: Application URL
|
||||
- Email configuration (SMTP)
|
||||
- AI provider API keys
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
### Current: Basic
|
||||
- Console logging
|
||||
- Playwright test reports
|
||||
- Prisma query logging (development)
|
||||
|
||||
### Future Needs
|
||||
- Application monitoring (Sentry, LogRocket)
|
||||
- Error tracking
|
||||
- Performance monitoring
|
||||
- Database query analysis
|
||||
- User analytics
|
||||
|
||||
---
|
||||
|
||||
## Scalability Considerations
|
||||
|
||||
### Current Limitations (SQLite)
|
||||
- Single writer (concurrent writes limited)
|
||||
- File-based storage
|
||||
- No automatic replication
|
||||
- Manual backups needed
|
||||
|
||||
### Future Scaling Options
|
||||
1. **PostgreSQL:** Replace SQLite with Postgres
|
||||
2. **Connection Pooling:** PgBouncer
|
||||
3. **Caching:** Redis for sessions and cache
|
||||
4. **CDN:** CloudFlare, AWS CloudFront
|
||||
5. **Object Storage:** S3 for images
|
||||
6. **Load Balancing:** Multiple app instances
|
||||
|
||||
---
|
||||
|
||||
## Testing Architecture
|
||||
|
||||
### E2E Testing: Playwright
|
||||
**Location:** `tests/search-quality.spec.ts`
|
||||
**Coverage:** Search functionality
|
||||
**Commands:**
|
||||
- `npm test` - Run all tests
|
||||
- `npm run test:ui` - UI mode
|
||||
- `npm run test:headed` - Headed mode
|
||||
|
||||
### Test Reports
|
||||
**Location:** `playwright-report/index.html`
|
||||
**Results:** `test-results/.last-run.json`
|
||||
|
||||
---
|
||||
|
||||
## Web Vitals & Performance
|
||||
|
||||
### Core Web Vitals
|
||||
- **LCP (Largest Contentful Paint):** Target < 2.5s
|
||||
- **FID (First Input Delay):** Target < 100ms
|
||||
- **CLS (Cumulative Layout Shift):** Target < 0.1
|
||||
|
||||
### Optimizations
|
||||
- Next.js Image optimization
|
||||
- Code splitting
|
||||
- Server components (reduce JS bundle)
|
||||
- Streaming responses
|
||||
- Lazy loading images
|
||||
|
||||
---
|
||||
|
||||
## PWA Architecture
|
||||
|
||||
### Progressive Web App Features
|
||||
**Package:** `@ducanh2912/next-pwa`
|
||||
**Manifest:** `public/manifest.json`
|
||||
|
||||
**Features:**
|
||||
- Offline support (future)
|
||||
- Install as app (future)
|
||||
- Push notifications (future)
|
||||
- App shortcuts (future)
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### MCP Server
|
||||
**Connection:** Database-mediated (shared SQLite)
|
||||
**Location:** `../mcp-server/index.js`
|
||||
**Protocol:** MCP (Model Context Protocol)
|
||||
|
||||
### Third-Party Services
|
||||
- **Email:** nodemailer (SMTP)
|
||||
- **AI:** OpenAI API, Ollama (local)
|
||||
- **Future:** N8N workflows via MCP
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
cd keep-notes
|
||||
npm install
|
||||
npm run db:generate # Generate Prisma client
|
||||
npm run dev # Start dev server
|
||||
```
|
||||
|
||||
### Database Migrations
|
||||
```bash
|
||||
npx prisma migrate dev
|
||||
npx prisma migrate deploy # Production
|
||||
```
|
||||
|
||||
### Type Checking
|
||||
```bash
|
||||
npx tsc --noEmit # Type check only
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `next.config.ts` | Next.js configuration |
|
||||
| `tsconfig.json` | TypeScript configuration |
|
||||
| `tailwind.config.ts` | Tailwind CSS (if present) |
|
||||
| `playwright.config.ts` | E2E test configuration |
|
||||
| `auth.config.ts` | NextAuth configuration |
|
||||
| `.env` | Environment variables |
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decision Records
|
||||
|
||||
### Why Next.js App Router?
|
||||
- Modern React features (Server Components)
|
||||
- Built-in API routes
|
||||
- File-based routing
|
||||
- Excellent performance
|
||||
- Strong community
|
||||
|
||||
### Why Prisma?
|
||||
- Type-safe database access
|
||||
- Excellent migration system
|
||||
- Multiple database support
|
||||
- Great developer experience
|
||||
|
||||
### Why SQLite?
|
||||
- Zero configuration
|
||||
- Portable (single file)
|
||||
- Sufficient for single-user/small teams
|
||||
- Easy local development
|
||||
|
||||
### Why No Redux/Zustand?
|
||||
- Server Components reduce need for global state
|
||||
- React Context sufficient for app state
|
||||
- Server Actions simplify mutations
|
||||
- Reduced bundle size
|
||||
|
||||
---
|
||||
|
||||
## Future Architecture Enhancements
|
||||
|
||||
### Short Term
|
||||
1. Add Redis for caching
|
||||
2. Implement rate limiting
|
||||
3. Add error boundaries
|
||||
4. Improve error logging
|
||||
5. Add request tracing
|
||||
|
||||
### Long Term
|
||||
1. Migrate to PostgreSQL
|
||||
2. Add read replicas
|
||||
3. Implement event sourcing
|
||||
4. Add real-time features (WebSocket)
|
||||
5. Microservices architecture
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The keep-notes application uses a modern JAMstack architecture with:
|
||||
- **Next.js 16** for full-stack development
|
||||
- **App Router** for routing and server components
|
||||
- **Prisma** for type-safe database access
|
||||
- **SQLite** for embedded database
|
||||
- **NextAuth** for authentication
|
||||
- **Radix UI** for accessible components
|
||||
- **Vercel AI SDK** for AI features
|
||||
- **Playwright** for E2E testing
|
||||
|
||||
This architecture provides a solid foundation for the Memento note-taking application with room for scaling and enhancement.
|
||||
709
docs/architecture-mcp-server.md
Normal file
709
docs/architecture-mcp-server.md
Normal file
@@ -0,0 +1,709 @@
|
||||
# Architecture - mcp-server (MCP Server)
|
||||
|
||||
## Overview
|
||||
|
||||
Architecture documentation for the Memento MCP (Model Context Protocol) server, an Express-based microservice that provides AI assistant and automation integration for the Memento note-taking application.
|
||||
|
||||
**Architecture Pattern:** Microservice API
|
||||
**Framework:** Express.js 4.22.1
|
||||
**Protocol:** MCP SDK 1.0.4
|
||||
**Language:** JavaScript (ES modules)
|
||||
**Database:** Shared SQLite via Prisma
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Core
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| Node.js | 20+ | Runtime |
|
||||
| Express.js | 4.22.1 | Web framework |
|
||||
| MCP SDK | 1.0.4 | Model Context Protocol |
|
||||
| Prisma | 5.22.0 | ORM |
|
||||
|
||||
### Transport
|
||||
- **Primary:** Stdio (standard input/output)
|
||||
- **Alternative:** Server-Sent Events (SSE) via `index-sse.js`
|
||||
|
||||
### Database
|
||||
- **ORM:** Prisma 5.22.0
|
||||
- **Database:** SQLite (shared with keep-notes)
|
||||
- **File:** `../keep-notes/prisma/dev.db`
|
||||
|
||||
---
|
||||
|
||||
## Architecture Pattern: Microservice
|
||||
|
||||
### System Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ MCP Client │
|
||||
│ (AI Assistant) │
|
||||
│ N8N Workflow │
|
||||
└────────┬────────┘
|
||||
│ MCP Protocol
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ mcp-server │
|
||||
│ │
|
||||
│ MCP Tools: │
|
||||
│ - create_note │
|
||||
│ - get_notes │
|
||||
│ - search_notes │
|
||||
│ - update_note │
|
||||
│ - delete_note │
|
||||
│ - toggle_pin │
|
||||
│ - toggle_archive│
|
||||
│ - get_labels │
|
||||
└────────┬────────┘
|
||||
│
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ Prisma ORM │
|
||||
│ │
|
||||
│ Shared SQLite │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### Communication Flow
|
||||
|
||||
1. **MCP Client** (AI assistant, N8N) connects via stdio
|
||||
2. **Request:** Tool invocation with parameters
|
||||
3. **Processing:** Server executes business logic
|
||||
4. **Database:** Prisma queries/updates
|
||||
5. **Response:** JSON result returned via stdio
|
||||
|
||||
---
|
||||
|
||||
## Server Structure
|
||||
|
||||
### File Organization
|
||||
|
||||
```
|
||||
mcp-server/
|
||||
├── index.js # Main MCP server (stdio transport)
|
||||
├── index-sse.js # SSE variant (HTTP + SSE)
|
||||
├── package.json # Dependencies
|
||||
├── README.md # Server documentation
|
||||
├── README-SSE.md # SSE documentation
|
||||
├── N8N-CONFIG.md # N8N setup guide
|
||||
└── prisma/ # Prisma client (shared)
|
||||
├── schema.prisma # Schema reference
|
||||
└── [generated client]
|
||||
```
|
||||
|
||||
### Entry Points
|
||||
|
||||
**Primary: index.js**
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
// ... tool definitions
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
```
|
||||
|
||||
**Alternative: index-sse.js**
|
||||
```javascript
|
||||
// HTTP server with Server-Sent Events
|
||||
// For web-based MCP clients
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MCP Tool Architecture
|
||||
|
||||
### Tool Registration Pattern
|
||||
|
||||
```javascript
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
return {
|
||||
tools: [
|
||||
{
|
||||
name: 'create_note',
|
||||
description: 'Create a new note in Memento',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: { /* ... */ },
|
||||
required: ['content']
|
||||
}
|
||||
},
|
||||
// ... 7 more tools
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Tool Execution Pattern
|
||||
|
||||
```javascript
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
try {
|
||||
switch (name) {
|
||||
case 'create_note': {
|
||||
const note = await prisma.note.create({ /* ... */ });
|
||||
return {
|
||||
content: [{ type: 'text', text: JSON.stringify(parseNote(note)) }]
|
||||
};
|
||||
}
|
||||
// ... handle other tools
|
||||
}
|
||||
} catch (error) {
|
||||
throw new McpError(ErrorCode.InternalError, error.message);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available MCP Tools
|
||||
|
||||
### Note Management (6 tools)
|
||||
|
||||
| Tool | Purpose | Required Params |
|
||||
|------|---------|----------------|
|
||||
| **create_note** | Create note | content |
|
||||
| **get_notes** | List all notes | (optional) includeArchived, search |
|
||||
| **get_note** | Get single note | id |
|
||||
| **update_note** | Update note | id, (optional) fields to update |
|
||||
| **delete_note** | Delete note | id |
|
||||
| **search_notes** | Search notes | query |
|
||||
|
||||
### Note Operations (2 tools)
|
||||
|
||||
| Tool | Purpose | Required Params |
|
||||
|------|---------|----------------|
|
||||
| **toggle_pin** | Toggle pin status | id |
|
||||
| **toggle_archive** | Toggle archive status | id |
|
||||
|
||||
### Data Query (1 tool)
|
||||
|
||||
| Tool | Purpose | Required Params |
|
||||
|------|---------|----------------|
|
||||
| **get_labels** | Get all unique labels | (none) |
|
||||
|
||||
**Total Tools:** 9 tools
|
||||
|
||||
---
|
||||
|
||||
## Database Integration
|
||||
|
||||
### Connection Details
|
||||
|
||||
```javascript
|
||||
const prisma = new PrismaClient({
|
||||
datasources: {
|
||||
db: {
|
||||
url: `file:${join(__dirname, '../keep-notes/prisma/dev.db')}`
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Path Resolution:**
|
||||
- From `mcp-server/index.js`
|
||||
- To: `../keep-notes/prisma/dev.db`
|
||||
- Absolute: `D:/dev_new_pc/Keep/keep-notes/prisma/dev.db`
|
||||
|
||||
### Database Access Pattern
|
||||
|
||||
**Read Operations:**
|
||||
```javascript
|
||||
const notes = await prisma.note.findMany({
|
||||
where: { /* conditions */ },
|
||||
orderBy: [/* sorting */]
|
||||
});
|
||||
```
|
||||
|
||||
**Write Operations:**
|
||||
```javascript
|
||||
const note = await prisma.note.create({
|
||||
data: { /* note data */ }
|
||||
});
|
||||
```
|
||||
|
||||
**Update Operations:**
|
||||
```javascript
|
||||
const note = await prisma.note.update({
|
||||
where: { id: args.id },
|
||||
data: { /* updates */ }
|
||||
});
|
||||
```
|
||||
|
||||
**Delete Operations:**
|
||||
```javascript
|
||||
await prisma.note.delete({
|
||||
where: { id: args.id }
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Processing
|
||||
|
||||
### JSON Field Parsing
|
||||
|
||||
**Helper Function:**
|
||||
```javascript
|
||||
function parseNote(dbNote) {
|
||||
return {
|
||||
...dbNote,
|
||||
checkItems: dbNote.checkItems ? JSON.parse(dbNote.checkItems) : null,
|
||||
labels: dbNote.labels ? JSON.parse(dbNote.labels) : null,
|
||||
images: dbNote.images ? JSON.parse(dbNote.images) : null,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:** Convert JSON strings from DB to JavaScript objects
|
||||
|
||||
**Fields Parsed:**
|
||||
- `checkItems`: Array of checklist items
|
||||
- `labels`: Array of label names
|
||||
- `images`: Array of image URLs/data
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### MCP Error Pattern
|
||||
|
||||
```javascript
|
||||
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
// Not found
|
||||
throw new McpError(ErrorCode.InvalidRequest, 'Note not found');
|
||||
|
||||
// Server error
|
||||
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error.message}`);
|
||||
|
||||
// Unknown tool
|
||||
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
||||
```
|
||||
|
||||
### Error Types
|
||||
|
||||
| Error Code | Usage |
|
||||
|------------|-------|
|
||||
| `InvalidRequest` | Invalid parameters, resource not found |
|
||||
| `MethodNotFound` | Unknown tool requested |
|
||||
| `InternalError` | Server-side failures (DB, parsing, etc.) |
|
||||
|
||||
---
|
||||
|
||||
## Tool Schemas
|
||||
|
||||
### create_note
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": { "type": "string" },
|
||||
"content": { "type": "string" },
|
||||
"color": { "type": "string", "enum": ["default","red",...] },
|
||||
"type": { "type": "string", "enum": ["text","checklist"] },
|
||||
"checkItems": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"text": { "type": "string" },
|
||||
"checked": { "type": "boolean" }
|
||||
},
|
||||
"required": ["id","text","checked"]
|
||||
}
|
||||
},
|
||||
"labels": { "type": "array", "items": { "type": "string" } },
|
||||
"images": { "type": "array", "items": { "type": "string" } },
|
||||
"isPinned": { "type": "boolean" },
|
||||
"isArchived": { "type": "boolean" }
|
||||
},
|
||||
"required": ["content"]
|
||||
}
|
||||
```
|
||||
|
||||
### update_note
|
||||
|
||||
**Input Schema:**
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"title": { "type": "string" },
|
||||
"content": { "type": "string" },
|
||||
"color": { "type": "string" },
|
||||
"checkItems": { "type": "array", "items": {/*...*/} },
|
||||
"labels": { "type": "array", "items": { "type": "string" } },
|
||||
"isPinned": { "type": "boolean" },
|
||||
"isArchived": { "type": "boolean" },
|
||||
"images": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"required": ["id"]
|
||||
}
|
||||
```
|
||||
|
||||
**Behavior:** Only updates fields provided (partial update)
|
||||
|
||||
---
|
||||
|
||||
## Transport Layer
|
||||
|
||||
### Stdio Transport (Primary)
|
||||
|
||||
**Implementation:**
|
||||
```javascript
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- AI assistants (ChatGPT, Claude, etc.)
|
||||
- N8N MCP integration
|
||||
- Command-line tools
|
||||
- Desktop applications
|
||||
|
||||
**Communication:**
|
||||
- **Input:** STDIN (JSON-RPC messages)
|
||||
- **Output:** STDOUT (JSON-RPC responses)
|
||||
- **Logging:** STDERR (diagnostic messages)
|
||||
|
||||
### SSE Transport (Alternative)
|
||||
|
||||
**File:** `index-sse.js`
|
||||
**Implementation:** HTTP server with Server-Sent Events
|
||||
|
||||
**Use Cases:**
|
||||
- Web-based clients
|
||||
- Browser integrations
|
||||
- Real-time notifications
|
||||
- Long-running operations
|
||||
|
||||
---
|
||||
|
||||
## Concurrency Model
|
||||
|
||||
### Single-Threaded Event Loop
|
||||
- Node.js event loop
|
||||
- No parallel execution
|
||||
- Sequential request handling
|
||||
|
||||
### Database Concurrency
|
||||
- SQLite handles concurrent reads
|
||||
- Single writer limitation
|
||||
- Prisma manages connection
|
||||
|
||||
### Scalability
|
||||
**Current:** Single instance
|
||||
**Limitations:**
|
||||
- No load balancing
|
||||
- No automatic failover
|
||||
- Single point of failure
|
||||
|
||||
**Future Enhancements:**
|
||||
- Multiple instances with connection pooling
|
||||
- PostgreSQL for better concurrency
|
||||
- Redis for session management
|
||||
- Message queue for async operations
|
||||
|
||||
---
|
||||
|
||||
## Security Architecture
|
||||
|
||||
### Current: No Authentication
|
||||
**Rationale:**
|
||||
- Trusted environment (localhost)
|
||||
- AI assistants need full access
|
||||
- Simplified integration
|
||||
|
||||
### Security Considerations
|
||||
**Risks:**
|
||||
- No access control
|
||||
- No rate limiting
|
||||
- No audit logging
|
||||
- Direct database access
|
||||
|
||||
**Recommendations for Production:**
|
||||
1. Add API key authentication
|
||||
2. Implement rate limiting
|
||||
3. Add request logging
|
||||
4. Restrict to localhost or VPN
|
||||
5. Use reverse proxy (nginx) for SSL
|
||||
|
||||
### Future Security
|
||||
- JWT tokens for authentication
|
||||
- Role-based access control
|
||||
- IP whitelisting
|
||||
- Request signing
|
||||
- Audit logging
|
||||
|
||||
---
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
### Latency
|
||||
- **Direct DB access:** ~1-5ms per query
|
||||
- **JSON parsing:** ~0.1-0.5ms
|
||||
- **Total tool execution:** ~5-20ms
|
||||
|
||||
### Throughput
|
||||
- **Single-threaded:** Limited by CPU
|
||||
- **SQLite:** ~1000-5000 ops/sec
|
||||
- **Bottleneck:** Database I/O
|
||||
|
||||
### Optimization Opportunities
|
||||
1. **Connection pooling:** Reuse Prisma client
|
||||
2. **Query optimization:** Add indexes
|
||||
3. **Caching:** Redis for frequent queries
|
||||
4. **Batching:** Batch multiple operations
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
### Current: Basic Logging
|
||||
```javascript
|
||||
console.error('Memento MCP server running on stdio');
|
||||
```
|
||||
|
||||
**Logged to:** STDERR (won't interfere with stdio transport)
|
||||
|
||||
### Future Monitoring Needs
|
||||
1. **Request Logging:** Log all tool invocations
|
||||
2. **Error Tracking:** Sentry, Rollbar
|
||||
3. **Performance Monitoring:** Query latency
|
||||
4. **Metrics:** Tool usage statistics
|
||||
5. **Health Checks:** `/health` endpoint
|
||||
|
||||
---
|
||||
|
||||
## Deployment Architecture
|
||||
|
||||
### Development
|
||||
```bash
|
||||
cd mcp-server
|
||||
npm install
|
||||
npm start
|
||||
# Connects via stdio
|
||||
```
|
||||
|
||||
### Production Options
|
||||
|
||||
**Option 1: Standalone Process**
|
||||
```bash
|
||||
node /path/to/mcp-server/index.js
|
||||
```
|
||||
|
||||
**Option 2: Docker Container**
|
||||
```dockerfile
|
||||
FROM node:20-alpine
|
||||
COPY mcp-server/ /app
|
||||
WORKDIR /app
|
||||
RUN npm install
|
||||
CMD ["node", "index.js"]
|
||||
```
|
||||
|
||||
**Option 3: Docker Compose**
|
||||
```yaml
|
||||
services:
|
||||
mcp-server:
|
||||
build: ./mcp-server
|
||||
volumes:
|
||||
- ./keep-notes/prisma:/app/db
|
||||
```
|
||||
|
||||
**Option 4: Process Manager**
|
||||
- PM2
|
||||
- Systemd service
|
||||
- Supervisord
|
||||
|
||||
---
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### N8N Workflow Integration
|
||||
|
||||
**Setup:** See `N8N-CONFIG.md`
|
||||
|
||||
**Usage:**
|
||||
1. Add MCP node in N8N
|
||||
2. Configure connection to mcp-server
|
||||
3. Select tools (create_note, search_notes, etc.)
|
||||
4. Build workflow
|
||||
|
||||
**Example Workflow:**
|
||||
- Trigger: Webhook
|
||||
- Tool: create_note
|
||||
- Parameters: From webhook data
|
||||
- Output: Created note
|
||||
|
||||
### AI Assistant Integration
|
||||
|
||||
**Supported Assistants:**
|
||||
- ChatGPT (via MCP plugin)
|
||||
- Claude (via MCP plugin)
|
||||
- Custom AI agents
|
||||
|
||||
**Usage Pattern:**
|
||||
1. User asks assistant: "Create a note about..."
|
||||
2. Assistant calls MCP tools
|
||||
3. Tools execute on Memento DB
|
||||
4. Results returned to assistant
|
||||
5. Assistant responds to user
|
||||
|
||||
---
|
||||
|
||||
## Versioning & Compatibility
|
||||
|
||||
### Current Version
|
||||
**Server:** 1.0.0
|
||||
**MCP Protocol:** 1.0.4
|
||||
|
||||
### Backward Compatibility
|
||||
- Tool schemas evolve
|
||||
- New tools added (non-breaking)
|
||||
- Existing tools maintained
|
||||
|
||||
### Versioning Strategy
|
||||
- Semantic versioning (MAJOR.MINOR.PATCH)
|
||||
- MAJOR: Breaking changes
|
||||
- MINOR: New features, backward compatible
|
||||
- PATCH: Bug fixes
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Current: Manual Testing
|
||||
- N8N workflow testing
|
||||
- Direct stdio invocation
|
||||
- SSE variant testing
|
||||
|
||||
### Recommended Tests
|
||||
1. **Unit Tests:** Tool execution logic
|
||||
2. **Integration Tests:** Prisma operations
|
||||
3. **E2E Tests:** Full MCP protocol flow
|
||||
4. **Load Tests:** Concurrent tool execution
|
||||
|
||||
### Test Tools
|
||||
- Jest for unit tests
|
||||
- Supertest for HTTP endpoints
|
||||
- Playwright for E2E
|
||||
- Artillery for load testing
|
||||
|
||||
---
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Environment Variables
|
||||
**Current:** Hardcoded (dev.db path)
|
||||
|
||||
**Recommended:**
|
||||
```bash
|
||||
DATABASE_URL="file:../keep-notes/prisma/dev.db"
|
||||
LOG_LEVEL="info"
|
||||
PORT="3000" # For SSE variant
|
||||
```
|
||||
|
||||
### Configuration File
|
||||
**Future:** `config.json`
|
||||
```json
|
||||
{
|
||||
"database": {
|
||||
"url": "file:../keep-notes/prisma/dev.db"
|
||||
},
|
||||
"logging": {
|
||||
"level": "info"
|
||||
},
|
||||
"server": {
|
||||
"name": "memento-mcp-server",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Maintenance & Operations
|
||||
|
||||
### Startup
|
||||
```bash
|
||||
node index.js
|
||||
# Output to stderr: "Memento MCP server running on stdio"
|
||||
```
|
||||
|
||||
### Shutdown
|
||||
- Send SIGTERM (Ctrl+C)
|
||||
- Graceful shutdown
|
||||
- Close database connections
|
||||
|
||||
### Health Checks
|
||||
**Future:** `/health` endpoint
|
||||
```javascript
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({ status: 'ok', uptime: process.uptime() })
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**1. Database Connection Failed**
|
||||
- **Symptom:** "Unable to connect to database"
|
||||
- **Cause:** Incorrect path or missing DB file
|
||||
- **Fix:** Verify `../keep-notes/prisma/dev.db` exists
|
||||
|
||||
**2. Permission Denied**
|
||||
- **Symptom:** "EACCES: permission denied"
|
||||
- **Cause:** File permissions on SQLite DB
|
||||
- **Fix:** chmod 644 dev.db
|
||||
|
||||
**3. Stdio Not Working**
|
||||
- **Symptom:** No response from server
|
||||
- **Cause:** Client not connected to stdin/stdout
|
||||
- **Fix:** Ensure proper stdio redirection
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Short Term
|
||||
1. Add authentication
|
||||
2. Implement rate limiting
|
||||
3. Add request logging
|
||||
4. Health check endpoint
|
||||
5. Configuration file support
|
||||
|
||||
### Long Term
|
||||
1. WebSocket support for real-time
|
||||
2. GraphQL integration
|
||||
3. Batch operations
|
||||
4. Transaction support
|
||||
5. Multi-database support
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The mcp-server is a lightweight, focused microservice that:
|
||||
- **Exposes 9 MCP tools** for note management
|
||||
- **Connects directly to SQLite** via Prisma
|
||||
- **Uses stdio transport** for AI/automation integration
|
||||
- **Provides N8N workflow** integration
|
||||
- **Shares database** with keep-notes web app
|
||||
- **Offers SSE variant** for web clients
|
||||
|
||||
This architecture provides a clean separation of concerns while maintaining data consistency through the shared database layer.
|
||||
817
docs/code-review-cleanup-report.md
Normal file
817
docs/code-review-cleanup-report.md
Normal file
@@ -0,0 +1,817 @@
|
||||
# Code Review & Cleanup Report - Memento Project
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Comprehensive code review and cleanup recommendations for the Memento note-taking application in preparation for GitHub release.
|
||||
|
||||
**Status:** Ready for cleanup
|
||||
**Files Reviewed:** 100+
|
||||
**Issues Found:** 57 files with debug/test code
|
||||
**Cleanup Priority:** High
|
||||
|
||||
---
|
||||
|
||||
## Cleanup Overview
|
||||
|
||||
### Critical Issues (Must Remove Before Release)
|
||||
|
||||
- ✅ **2 Debug API Routes** - Expose internal debugging information
|
||||
- ✅ **1 Debug Page** - Public-facing debug interface
|
||||
- ✅ **6 Debug Scripts** - Development utilities in production code
|
||||
- ⚠️ **41 Console Statements** - Logging in production code
|
||||
- ⚠️ **5 Playwright Test Files** - Should remain (E2E testing)
|
||||
|
||||
---
|
||||
|
||||
## Priority 1: Debug Routes (REMOVE)
|
||||
|
||||
### 1.1 API Debug Endpoint
|
||||
|
||||
**File:** `app/api/debug/search/route.ts`
|
||||
|
||||
**Purpose:** Debug semantic search by exposing embeddings and similarity scores
|
||||
|
||||
**Issue:**
|
||||
- Exposes internal embeddings data
|
||||
- Shows similarity scores (proprietary algorithm)
|
||||
- No rate limiting
|
||||
- Authenticated but still dangerous in production
|
||||
|
||||
**Recommendation:** ❌ **REMOVE**
|
||||
|
||||
**Action:**
|
||||
```bash
|
||||
rm keep-notes/app/api/debug/search/route.ts
|
||||
rmdir keep-notes/app/api/debug/search 2>/dev/null
|
||||
rmdir keep-notes/app/api/debug 2>/dev/null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.2 AI Test Endpoint
|
||||
|
||||
**File:** `app/api/ai/test/route.ts`
|
||||
|
||||
**Purpose:** Test AI provider connectivity
|
||||
|
||||
**Issue:**
|
||||
- Development-only endpoint
|
||||
- Returns stack traces to client
|
||||
- No authentication required
|
||||
- Wastes AI API quota
|
||||
|
||||
**Recommendation:** ❌ **REMOVE**
|
||||
|
||||
**Action:**
|
||||
```bash
|
||||
rm keep-notes/app/api/ai/test/route.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Debug Search Page
|
||||
|
||||
**File:** `app/debug-search/page.tsx`
|
||||
|
||||
**Purpose:** UI for testing semantic search
|
||||
|
||||
**Issue:**
|
||||
- Public debug interface
|
||||
- Accessible at `/debug-search` route
|
||||
- Shows internal embedding data
|
||||
- Should not be in production
|
||||
|
||||
**Recommendation:** ❌ **REMOVE**
|
||||
|
||||
**Action:**
|
||||
```bash
|
||||
rm keep-notes/app/debug-search/page.tsx
|
||||
rmdir keep-notes/app/debug-search 2>/dev/null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Priority 2: Debug Scripts (REMOVE)
|
||||
|
||||
### Scripts Directory Analysis
|
||||
|
||||
**Location:** `keep-notes/scripts/`
|
||||
|
||||
**Total Scripts:** 10
|
||||
**Debug Scripts:** 6 (REMOVE)
|
||||
**Utility Scripts:** 4 (KEEP - documented in docs)
|
||||
|
||||
---
|
||||
|
||||
### 2.1 Debug Scripts to Remove
|
||||
|
||||
| Script | Purpose | Action |
|
||||
|--------|---------|--------|
|
||||
| `check-labels.js` | Debug label issues | ❌ Remove |
|
||||
| `check-users.js` | Debug user accounts | ❌ Remove |
|
||||
| `check-users.ts` | TypeScript duplicate | ❌ Remove |
|
||||
| `debug-rrf.js` | Debug RRF (Reciprocal Rank Fusion) | ❌ Remove |
|
||||
| `debug-smtp.js` | Debug email sending | ❌ Remove |
|
||||
| `diagnose-mail.js` | Diagnose mail issues | ❌ Remove |
|
||||
| `fix-labels-userid.js` | One-time migration script | ❌ Remove |
|
||||
| `fix-order.ts` | One-time migration script | ❌ Remove |
|
||||
|
||||
**Cleanup Command:**
|
||||
```bash
|
||||
cd keep-notes/scripts
|
||||
rm check-labels.js
|
||||
rm check-users.js
|
||||
rm check-users.ts
|
||||
rm debug-rrf.js
|
||||
rm debug-smtp.js
|
||||
rm diagnose-mail.js
|
||||
rm fix-labels-userid.js
|
||||
rm fix-order.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Utility Scripts to Keep
|
||||
|
||||
| Script | Purpose | Action |
|
||||
|--------|---------|--------|
|
||||
| `promote-admin.js` | Promote user to admin role | ✅ Keep (document in README) |
|
||||
| `seed-user.ts` | Seed test data | ✅ Keep (document in README) |
|
||||
|
||||
**Documentation Required:** Add to `README.md` or `docs/admin-guide.md`
|
||||
|
||||
---
|
||||
|
||||
## Priority 3: Console Statements (REVIEW)
|
||||
|
||||
### Console Statement Analysis
|
||||
|
||||
**Total Files:** 41
|
||||
**Categories:**
|
||||
- Error logging (console.error) - Review
|
||||
- Warning logging (console.warn) - Review
|
||||
- Info logging (console.log) - Remove most
|
||||
- Debug logging (console.debug) - Remove all
|
||||
|
||||
---
|
||||
|
||||
### 3.1 Console Statements by Category
|
||||
|
||||
#### High Priority (Remove in Production)
|
||||
|
||||
**Files with excessive console.log:**
|
||||
```typescript
|
||||
// Components (should not log in production)
|
||||
keep-notes/components/masonry-grid.tsx
|
||||
keep-notes/components/note-editor.tsx
|
||||
keep-notes/components/note-card.tsx
|
||||
keep-notes/components/note-input.tsx
|
||||
keep-notes/components/label-management-dialog.tsx
|
||||
keep-notes/components/label-manager.tsx
|
||||
```
|
||||
|
||||
**Recommendation:** Replace with proper logging library or remove
|
||||
|
||||
**Example Cleanup:**
|
||||
```typescript
|
||||
// BEFORE
|
||||
console.log('Creating note:', note);
|
||||
|
||||
// AFTER - Option 1: Remove entirely
|
||||
// (Just delete the line)
|
||||
|
||||
// AFTER - Option 2: Use logger
|
||||
import { logger } from '@/lib/logger'
|
||||
logger.info('Creating note', { noteId: note.id });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Medium Priority (Error Logging - Review)
|
||||
|
||||
**Files with console.error:**
|
||||
```typescript
|
||||
keep-notes/app/actions/register.ts
|
||||
keep-notes/app/actions/auth-reset.ts
|
||||
keep-notes/lib/mail.ts
|
||||
keep-notes/app/api/ai/tags/route.ts
|
||||
keep-notes/app/actions/admin-settings.ts
|
||||
keep-notes/lib/ai/factory.ts
|
||||
keep-notes/lib/config.ts
|
||||
keep-notes/app/actions/admin.ts
|
||||
```
|
||||
|
||||
**Recommendation:** Replace with proper error handling
|
||||
|
||||
**Example Cleanup:**
|
||||
```typescript
|
||||
// BEFORE
|
||||
catch (error) {
|
||||
console.error('Failed to create user:', error);
|
||||
return { success: false, error: 'Registration failed' };
|
||||
}
|
||||
|
||||
// AFTER
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
catch (error) {
|
||||
logger.error('User registration failed', {
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
return { success: false, error: 'Registration failed' };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Console Statement Cleanup Strategy
|
||||
|
||||
#### Option 1: Environment-Based Logging
|
||||
|
||||
```typescript
|
||||
// lib/logger.ts
|
||||
class Logger {
|
||||
private isDevelopment = process.env.NODE_ENV === 'development';
|
||||
|
||||
log(...args: any[]) {
|
||||
if (this.isDevelopment) {
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
|
||||
error(...args: any[]) {
|
||||
if (this.isDevelopment || process.env.LOG_ERRORS === 'true') {
|
||||
console.error(...args);
|
||||
}
|
||||
}
|
||||
|
||||
warn(...args: any[]) {
|
||||
if (this.isDevelopment) {
|
||||
console.warn(...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const logger = new Logger();
|
||||
```
|
||||
|
||||
#### Option 2: Production Logging Service
|
||||
|
||||
```typescript
|
||||
// Use external service for production
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
Sentry.captureException(error);
|
||||
```
|
||||
|
||||
#### Option 3: Remove All (Simplest)
|
||||
|
||||
```bash
|
||||
# Remove all console.log statements
|
||||
find keep-notes -type f \( -name "*.ts" -o -name "*.tsx" \) \
|
||||
-not -path "*/node_modules/*" \
|
||||
-not -path "*/tests/*" \
|
||||
-exec sed -i '/console\.log/d' {} +
|
||||
```
|
||||
|
||||
**Recommendation:** Use Option 1 (Environment-Based) for balance
|
||||
|
||||
---
|
||||
|
||||
## Priority 4: Test Files (KEEP)
|
||||
|
||||
### Playwright E2E Tests
|
||||
|
||||
**Location:** `keep-notes/tests/`
|
||||
|
||||
**Files:**
|
||||
- `capture-masonry.spec.ts` - Test masonry grid screenshot capture
|
||||
- `drag-drop.spec.ts` - Test drag-and-drop functionality
|
||||
- `reminder-dialog.spec.ts` - Test reminder dialog
|
||||
- `search-quality.spec.ts` - Test search quality (semantic search)
|
||||
- `undo-redo.spec.ts` - Test undo/redo functionality
|
||||
|
||||
**Recommendation:** ✅ **KEEP ALL**
|
||||
|
||||
**Reasoning:**
|
||||
- E2E tests are critical for quality assurance
|
||||
- Playwright tests should run in CI/CD
|
||||
- Tests are isolated in `/tests` directory
|
||||
- Documented in `package.json` test scripts
|
||||
|
||||
---
|
||||
|
||||
## Priority 5: Other Code Issues
|
||||
|
||||
### 5.1 Commented-Out Code
|
||||
|
||||
**Search for:** Multi-line commented code blocks
|
||||
|
||||
**Action Required:** Manual review
|
||||
|
||||
**Example Locations to Check:**
|
||||
```typescript
|
||||
// Components with likely commented code
|
||||
keep-notes/components/note-editor.tsx
|
||||
keep-notes/components/label-selector.tsx
|
||||
keep-notes/app/actions/scrape.ts
|
||||
```
|
||||
|
||||
**Cleanup Command (Find):**
|
||||
```bash
|
||||
# Find files with >5 consecutive commented lines
|
||||
find keep-notes -type f \( -name "*.ts" -o -name "*.tsx" \) \
|
||||
-not -path "*/node_modules/*" | \
|
||||
xargs awk '/^\/\*/{inBlock=1; count=0} inBlock && /\*\//{inBlock=0} inBlock{count++} /^\/\//{comment++} END{if(count>5 || comment>5) print FILENAME}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.2 Unused Imports
|
||||
|
||||
**Search for:** Import statements that aren't used
|
||||
|
||||
**Tool:** ESLint with `no-unused-vars` rule
|
||||
|
||||
**Check Command:**
|
||||
```bash
|
||||
cd keep-notes
|
||||
npx eslint . --ext .ts,.tsx --rule 'no-unused-vars: error'
|
||||
```
|
||||
|
||||
**Auto-Fix:**
|
||||
```bash
|
||||
npx eslint . --ext .ts,.tsx --fix
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.3 TypeScript Strict Mode
|
||||
|
||||
**Check:** Ensure `tsconfig.json` has strict mode enabled
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true // Should be true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Current Status:** Already enabled ✅
|
||||
|
||||
---
|
||||
|
||||
## Cleanup Execution Plan
|
||||
|
||||
### Phase 1: Critical Removals (5 minutes)
|
||||
|
||||
```bash
|
||||
# 1. Remove debug routes
|
||||
rm -rf keep-notes/app/api/debug
|
||||
rm keep-notes/app/api/ai/test/route.ts
|
||||
|
||||
# 2. Remove debug page
|
||||
rm -rf keep-notes/app/debug-search
|
||||
|
||||
# 3. Remove debug scripts
|
||||
cd keep-notes/scripts
|
||||
rm check-labels.js
|
||||
rm check-users.js
|
||||
rm check-users.ts
|
||||
rm debug-rrf.js
|
||||
rm debug-smtp.js
|
||||
rm diagnose-mail.js
|
||||
rm fix-labels-userid.js
|
||||
rm fix-order.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Console Statement Cleanup (15 minutes)
|
||||
|
||||
**Option A: Create Logger Utility (Recommended)**
|
||||
|
||||
1. Create `keep-notes/lib/logger.ts`
|
||||
2. Replace all console statements with logger calls
|
||||
3. Use environment-based filtering
|
||||
|
||||
**Option B: Remove All Console.Log (Quick)**
|
||||
|
||||
```bash
|
||||
# Remove all console.log (keep console.error for now)
|
||||
find keep-notes -type f \( -name "*.ts" -o -name "*.tsx" \) \
|
||||
-not -path "*/node_modules/*" \
|
||||
-not -path "*/tests/*" \
|
||||
-exec sed -i '/console\.log/d' {} +
|
||||
|
||||
# Remove console.debug
|
||||
find keep-notes -type f \( -name "*.ts" -o -name "*.tsx" \) \
|
||||
-not -path "*/node_modules/*" \
|
||||
-not -path "*/tests/*" \
|
||||
-exec sed -i '/console\.debug/d' {} +
|
||||
```
|
||||
|
||||
**Option C: Manual Review (Thorough)**
|
||||
|
||||
Review each of the 41 files individually and make informed decisions.
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Code Quality Checks (10 minutes)
|
||||
|
||||
```bash
|
||||
# 1. Check for unused imports
|
||||
cd keep-notes
|
||||
npx eslint . --ext .ts,.tsx --fix
|
||||
|
||||
# 2. Type check
|
||||
npx tsc --noEmit
|
||||
|
||||
# 3. Run tests
|
||||
npm test
|
||||
|
||||
# 4. Build check
|
||||
npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Documentation Updates (5 minutes)
|
||||
|
||||
1. Update `README.md` with:
|
||||
- Admin utility scripts (promote-admin.js, seed-user.ts)
|
||||
- Test commands (`npm test`)
|
||||
- Debugging tips for developers
|
||||
|
||||
2. Create `ADMIN.md` documenting:
|
||||
- How to promote users to admin
|
||||
- How to seed test data
|
||||
- Common admin tasks
|
||||
|
||||
---
|
||||
|
||||
## Pre-Release Checklist
|
||||
|
||||
### Critical (Must Complete)
|
||||
|
||||
- [ ] Remove `/app/api/debug` directory
|
||||
- [ ] Remove `/app/api/ai/test/route.ts`
|
||||
- [ ] Remove `/app/debug-search` page
|
||||
- [ ] Remove 8 debug scripts from `/scripts`
|
||||
- [ ] Review and clean console statements (41 files)
|
||||
- [ ] Run `npm run build` successfully
|
||||
- [ ] Run `npm test` successfully
|
||||
- [ ] Run `npx tsc --noEmit` (no type errors)
|
||||
|
||||
### Important (Should Complete)
|
||||
|
||||
- [ ] Remove commented-out code blocks
|
||||
- [ ] Remove unused imports
|
||||
- [ ] Add environment variable validation
|
||||
- [ ] Add error boundaries
|
||||
- [ ] Document admin scripts
|
||||
- [ ] Update README.md
|
||||
|
||||
### Nice to Have
|
||||
|
||||
- [ ] Set up Sentry for error tracking
|
||||
- [ ] Add structured logging
|
||||
- [ ] Add performance monitoring
|
||||
- [ ] Add API rate limiting
|
||||
- [ ] Add request tracing
|
||||
|
||||
---
|
||||
|
||||
## File-by-File Cleanup Details
|
||||
|
||||
### API Routes Requiring Console Statement Cleanup
|
||||
|
||||
```typescript
|
||||
// app/api/ai/tags/route.ts
|
||||
// Line ~22: console.error('AI tagging error:', error)
|
||||
// → Replace with logger.error()
|
||||
|
||||
// app/api/upload/route.ts
|
||||
// Line ~XX: console.log statements
|
||||
// → Remove or replace
|
||||
|
||||
// app/api/labels/route.ts
|
||||
// Line ~XX: console.log statements
|
||||
// → Remove or replace
|
||||
|
||||
// app/api/labels/[id]/route.ts
|
||||
// Line ~XX: console.log statements
|
||||
// → Remove or replace
|
||||
|
||||
// app/api/notes/route.ts
|
||||
// Line ~XX: console.log statements
|
||||
// → Remove or replace
|
||||
|
||||
// app/api/notes/[id]/route.ts
|
||||
// Line ~XX: console.log statements
|
||||
// → Remove or replace
|
||||
|
||||
// app/api/cron/reminders/route.ts
|
||||
// Line ~XX: console.log statements
|
||||
// → Keep (cron jobs need logging)
|
||||
```
|
||||
|
||||
### Server Actions Requiring Cleanup
|
||||
|
||||
```typescript
|
||||
// app/actions/register.ts
|
||||
// Lines with console.error
|
||||
// → Replace with proper error handling
|
||||
|
||||
// app/actions/auth-reset.ts
|
||||
// Lines with console.error
|
||||
// → Replace with proper error handling
|
||||
|
||||
// app/actions/admin-settings.ts
|
||||
// Lines with console.log
|
||||
// → Remove or replace
|
||||
|
||||
// app/actions/admin.ts
|
||||
// Lines with console.log
|
||||
// → Remove or replace
|
||||
|
||||
// app/actions/scrape.ts
|
||||
// Lines with console.error
|
||||
// → Replace with proper error handling
|
||||
|
||||
// app/actions/notes.ts
|
||||
// Lines with console.log
|
||||
// → Remove or replace
|
||||
```
|
||||
|
||||
### Components Requiring Cleanup
|
||||
|
||||
```typescript
|
||||
// components/masonry-grid.tsx
|
||||
// Lines with console.log (drag-drop debugging)
|
||||
// → Remove
|
||||
|
||||
// components/note-editor.tsx
|
||||
// Lines with console.log
|
||||
// → Remove
|
||||
|
||||
// components/note-card.tsx
|
||||
// Lines with console.log
|
||||
// → Remove
|
||||
|
||||
// components/note-input.tsx
|
||||
// Lines with console.log
|
||||
// → Remove
|
||||
|
||||
// components/label-management-dialog.tsx
|
||||
// Lines with console.log
|
||||
// → Remove
|
||||
|
||||
// components/label-manager.tsx
|
||||
// Lines with console.log
|
||||
// → Remove
|
||||
```
|
||||
|
||||
### Library Files Requiring Cleanup
|
||||
|
||||
```typescript
|
||||
// lib/ai/factory.ts
|
||||
// Lines with console.error
|
||||
// → Keep (AI provider errors need logging)
|
||||
|
||||
// lib/ai/providers/ollama.ts
|
||||
// Lines with console.error
|
||||
// → Keep (Ollama connection errors)
|
||||
|
||||
// lib/ai/providers/openai.ts
|
||||
// Lines with console.error
|
||||
// → Keep (OpenAI API errors)
|
||||
|
||||
// lib/mail.ts
|
||||
// Lines with console.error
|
||||
// → Replace with proper email error handling
|
||||
|
||||
// lib/config.ts
|
||||
// Lines with console.error
|
||||
// → Keep (config errors need logging)
|
||||
|
||||
// lib/label-storage.ts
|
||||
// Lines with console.log
|
||||
// → Remove
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
### High Risk Items (Breaking Changes)
|
||||
|
||||
**None identified** - All proposed cleanups are non-breaking
|
||||
|
||||
### Medium Risk Items (Behavior Changes)
|
||||
|
||||
- Removing console statements may make debugging harder
|
||||
- **Mitigation:** Add environment-based logging
|
||||
|
||||
### Low Risk Items (Cosmetic)
|
||||
|
||||
- Comment removal
|
||||
- Unused import removal
|
||||
- Code formatting
|
||||
|
||||
---
|
||||
|
||||
## Recommendations
|
||||
|
||||
### Immediate Actions (Before GitHub Release)
|
||||
|
||||
1. ✅ **Remove all debug routes and pages**
|
||||
2. ✅ **Remove debug scripts**
|
||||
3. ✅ **Clean up console statements**
|
||||
4. ✅ **Run build and tests**
|
||||
|
||||
### Post-Release Actions
|
||||
|
||||
1. Implement structured logging
|
||||
2. Add error tracking (Sentry)
|
||||
3. Set up CI/CD pipeline
|
||||
4. Add automated code quality checks
|
||||
|
||||
---
|
||||
|
||||
## Automation Scripts
|
||||
|
||||
### Cleanup Script (One-Command Execution)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# cleanup.sh - Automated cleanup script
|
||||
|
||||
echo "🧹 Starting Memento code cleanup..."
|
||||
|
||||
# Phase 1: Remove debug routes
|
||||
echo "📁 Removing debug routes..."
|
||||
rm -rf keep-notes/app/api/debug
|
||||
rm -f keep-notes/app/api/ai/test/route.ts
|
||||
rm -rf keep-notes/app/debug-search
|
||||
|
||||
# Phase 2: Remove debug scripts
|
||||
echo "📁 Removing debug scripts..."
|
||||
cd keep-notes/scripts
|
||||
rm -f check-labels.js check-users.js check-users.ts
|
||||
rm -f debug-rrf.js debug-smtp.js diagnose-mail.js
|
||||
rm -f fix-labels-userid.js fix-order.ts
|
||||
cd ../..
|
||||
|
||||
# Phase 3: Remove console.log and console.debug
|
||||
echo "🔧 Removing console statements..."
|
||||
find keep-notes -type f \( -name "*.ts" -o -name "*.tsx" \) \
|
||||
-not -path "*/node_modules/*" \
|
||||
-not -path "*/tests/*" \
|
||||
-not -path "*/prisma/*" \
|
||||
-exec sed -i '/console\.log(/d' {} +
|
||||
|
||||
find keep-notes -type f \( -name "*.ts" -o -name "*.tsx" \) \
|
||||
-not -path "*/node_modules/*" \
|
||||
-not -path "*/tests/*" \
|
||||
-not -path "*/prisma/*" \
|
||||
-exec sed -i '/console\.debug(/d' {} +
|
||||
|
||||
# Phase 4: Type check
|
||||
echo "🔍 Running type check..."
|
||||
cd keep-notes
|
||||
npx tsc --noEmit
|
||||
|
||||
# Phase 5: Build check
|
||||
echo "🏗️ Running build..."
|
||||
npm run build
|
||||
|
||||
echo "✅ Cleanup complete!"
|
||||
echo ""
|
||||
echo "📊 Summary:"
|
||||
echo " - Debug routes removed"
|
||||
echo " - Debug scripts removed"
|
||||
echo " - Console statements cleaned"
|
||||
echo " - Type check passed"
|
||||
echo " - Build successful"
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
chmod +x cleanup.sh
|
||||
./cleanup.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Post-Cleanup Validation
|
||||
|
||||
### 1. Application Smoke Test
|
||||
|
||||
```bash
|
||||
# Start development server
|
||||
cd keep-notes
|
||||
npm run dev
|
||||
|
||||
# Manual testing checklist:
|
||||
# [ ] Homepage loads
|
||||
# [ ] Can create note
|
||||
# [ ] Can edit note
|
||||
# [ ] Can delete note
|
||||
# [ ] Search works
|
||||
# [ ] Labels work
|
||||
# [ ] Login works
|
||||
# [ ] Settings page loads
|
||||
```
|
||||
|
||||
### 2. Production Build Test
|
||||
|
||||
```bash
|
||||
# Build for production
|
||||
npm run build
|
||||
|
||||
# Start production server
|
||||
npm start
|
||||
|
||||
# Verify application works
|
||||
```
|
||||
|
||||
### 3. Docker Build Test
|
||||
|
||||
```bash
|
||||
# Test Docker build
|
||||
docker compose build
|
||||
|
||||
# Verify containers start
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary Statistics
|
||||
|
||||
### Before Cleanup
|
||||
|
||||
- **Total Routes:** 12 API endpoints + 2 debug endpoints = **14**
|
||||
- **Total Scripts:** 10 utility scripts + 6 debug scripts = **16**
|
||||
- **Files with Console Statements:** 41
|
||||
- **Debug Pages:** 1
|
||||
- **Test Files:** 5 ✅ (kept)
|
||||
|
||||
### After Cleanup
|
||||
|
||||
- **Total Routes:** 12 API endpoints (clean)
|
||||
- **Total Scripts:** 10 utility scripts (clean)
|
||||
- **Files with Console Statements:** 0 (or environment-controlled)
|
||||
- **Debug Pages:** 0
|
||||
- **Test Files:** 5 ✅ (kept)
|
||||
|
||||
### Code Quality Improvement
|
||||
|
||||
- **Security:** ✅ Removed debug endpoints
|
||||
- **Performance:** ✅ Removed console overhead
|
||||
- **Maintainability:** ✅ Cleaner codebase
|
||||
- **Production-Ready:** ✅ No development artifacts
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Memento codebase is **well-structured** but contains **development artifacts** that should be removed before GitHub release:
|
||||
|
||||
### Critical Cleanup Items:
|
||||
1. ❌ 2 debug API routes
|
||||
2. ❌ 1 debug page
|
||||
3. ❌ 6-8 debug scripts
|
||||
4. ⚠️ 41 files with console statements
|
||||
|
||||
### Items to Keep:
|
||||
1. ✅ 5 Playwright E2E test files
|
||||
2. ✅ 2 admin utility scripts (document them)
|
||||
3. ✅ Core error logging (console.error in server code)
|
||||
|
||||
**Estimated Cleanup Time:** 30-45 minutes
|
||||
**Risk Level:** Low (no breaking changes)
|
||||
**Recommendation:** Execute cleanup before GitHub release
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Run automated cleanup script
|
||||
2. Manual review of changes
|
||||
3. Test application functionality
|
||||
4. Commit changes with message:
|
||||
```
|
||||
chore: remove debug code and clean up console statements
|
||||
|
||||
- Remove debug API routes (/api/debug/*, /api/ai/test)
|
||||
- Remove debug page (/debug-search)
|
||||
- Remove 8 debug scripts from /scripts
|
||||
- Clean up console.log statements
|
||||
- Keep E2E tests and admin utilities
|
||||
```
|
||||
5. Tag release: `v1.0.0`
|
||||
6. Push to GitHub 🚀
|
||||
424
docs/component-inventory.md
Normal file
424
docs/component-inventory.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# Component Inventory - keep-notes
|
||||
|
||||
## Overview
|
||||
|
||||
Complete inventory of React components in the Memento web application. The application uses 20+ domain-specific components organized by functionality.
|
||||
|
||||
**Total Components:** 20+
|
||||
**UI Library:** Radix UI
|
||||
**Icons:** Lucide React
|
||||
|
||||
---
|
||||
|
||||
## Component Categories
|
||||
|
||||
### 1. Authentication Components
|
||||
|
||||
| Component | File | Purpose | Props |
|
||||
|-----------|------|---------|-------|
|
||||
| **LoginForm** | `login-form.tsx` | User login form | email, password, handleSubmit |
|
||||
| **RegisterForm** | `register-form.tsx` | User registration | name, email, password, confirmPassword |
|
||||
|
||||
**Usage:** Used in `(auth)/login` and `(auth)/register` routes
|
||||
|
||||
---
|
||||
|
||||
### 2. Note Components
|
||||
|
||||
| Component | File | Purpose | Props |
|
||||
|-----------|------|---------|-------|
|
||||
| **NoteCard** | `note-card.tsx` | Individual note display | note, onPin, onArchive, onUpdate, onDelete |
|
||||
| **NoteEditor** | `note-editor.tsx` | Rich note editor | note, onChange, onSave |
|
||||
| **NoteInput** | `note-input.tsx` | Quick note creation | onCreate, autoFocus |
|
||||
| **NoteActions** | `note-actions.tsx` | Note action menu | note, onEdit, onPin, onArchive, onDelete |
|
||||
| **NoteChecklist** | `note-checklist.tsx` | Checklist items | items, onChange, onToggle |
|
||||
| **NoteImages** | `note-images.tsx` | Image gallery | images, onAdd, onRemove |
|
||||
| **EditorImages** | `editor-images.tsx` | Image upload/edit | images, onChange |
|
||||
|
||||
**Features:**
|
||||
- Drag-and-drop support via @dnd-kit
|
||||
- Color-coded backgrounds
|
||||
- Markdown rendering support
|
||||
- Checklist with checkbox items
|
||||
- Image attachments (base64 or URL)
|
||||
- Pin/unpin functionality
|
||||
- Archive/unarchive
|
||||
|
||||
---
|
||||
|
||||
### 3. Label Components
|
||||
|
||||
| Component | File | Purpose | Props |
|
||||
|-----------|------|---------|-------|
|
||||
| **LabelBadge** | `label-badge.tsx` | Label display badge | label, onRemove, color |
|
||||
| **LabelFilter** | `label-filter.tsx` | Filter by labels | labels, selectedLabels, onChange |
|
||||
| **LabelSelector** | `label-selector.tsx` | Select labels for note | availableLabels, selectedLabels, onChange |
|
||||
| **LabelManager** | `label-manager.tsx` | Manage user labels | labels, onCreate, onUpdate, onDelete |
|
||||
| **LabelManagementDialog** | `label-management-dialog.tsx` | Label management modal | isOpen, onClose, labels |
|
||||
| **GhostTags** | `ghost-tags.tsx` | Floating tag display | tags, onTagClick |
|
||||
|
||||
**Color Options:** red, orange, yellow, green, teal, blue, purple, pink, gray
|
||||
|
||||
---
|
||||
|
||||
### 4. Layout Components
|
||||
|
||||
| Component | File | Purpose | Props |
|
||||
|-----------|------|---------|-------|
|
||||
| **Header** | `header.tsx` | Application header | title, user |
|
||||
| **HeaderWrapper** | `header-wrapper.tsx` | Header container with logic | children, user |
|
||||
| **Sidebar** | `sidebar.tsx` | Navigation sidebar | isOpen, onClose |
|
||||
| **MasonryGrid** | `masonry-grid.tsx` | Masonry grid layout | items, renderItem |
|
||||
|
||||
**Layout Libraries:**
|
||||
- Muuri (masonry grid)
|
||||
- react-grid-layout
|
||||
- @dnd-kit (drag and drop)
|
||||
|
||||
---
|
||||
|
||||
### 5. Content Components
|
||||
|
||||
| Component | File | Purpose | Props |
|
||||
|-----------|------|---------|-------|
|
||||
| **MarkdownContent** | `markdown-content.tsx` | Markdown renderer | content, className |
|
||||
|
||||
**Features:**
|
||||
- GitHub Flavored Markdown (GFM)
|
||||
- Syntax highlighting (if configured)
|
||||
- Safe rendering (sanitization)
|
||||
|
||||
---
|
||||
|
||||
### 6. User Components
|
||||
|
||||
| Component | File | Purpose | Props |
|
||||
|-----------|------|---------|-------|
|
||||
| **UserNav** | `user-nav.tsx` (inferred) | User navigation menu | user, onLogout |
|
||||
|
||||
**Features:**
|
||||
- Profile settings access
|
||||
- Logout functionality
|
||||
- Theme toggle
|
||||
|
||||
---
|
||||
|
||||
### 7. Dialog/Modal Components
|
||||
|
||||
| Component | File | Purpose | Props |
|
||||
|-----------|------|---------|-------|
|
||||
| **ReminderDialog** | `reminder-dialog.tsx` | Set note reminders | note, onSave, onClose |
|
||||
|
||||
**Features:**
|
||||
- Date/time picker
|
||||
- Recurrence options
|
||||
- Location-based reminders (future)
|
||||
|
||||
---
|
||||
|
||||
### 8. UI Primitives (Radix UI)
|
||||
|
||||
Located in `components/ui/` - Auto-generated or minimal wrappers around Radix UI:
|
||||
|
||||
| Component | Radix Primitive | Purpose |
|
||||
|-----------|----------------|---------|
|
||||
| Avatar | @radix-ui/react-avatar | User avatar display |
|
||||
| Checkbox | @radix-ui/react-checkbox | Checkbox input |
|
||||
| Dialog | @radix-ui/react-dialog | Modal dialogs |
|
||||
| Dropdown Menu | @radix-ui/react-dropdown-menu | Dropdown menus |
|
||||
| Popover | @radix-ui/react-popover | Floating content |
|
||||
| Separator | @radix-ui/react-separator | Visual separators |
|
||||
| Slot | @radix-ui/react-slot | Component composition |
|
||||
| Tooltip | @radix-ui/react-tooltip | Hover tooltips |
|
||||
|
||||
**Usage:** Domain components compose these primitives
|
||||
|
||||
---
|
||||
|
||||
## Component Hierarchy
|
||||
|
||||
```
|
||||
Layout Components
|
||||
├── Header → HeaderWrapper
|
||||
│ └── UserNav
|
||||
├── Sidebar
|
||||
└── MasonryGrid
|
||||
└── NoteCard
|
||||
├── NoteEditor
|
||||
│ ├── NoteChecklist
|
||||
│ ├── NoteImages
|
||||
│ └── EditorImages
|
||||
└── NoteActions
|
||||
|
||||
Label Management
|
||||
├── LabelBadge
|
||||
├── LabelFilter
|
||||
├── LabelSelector
|
||||
├── LabelManager → LabelManagementDialog
|
||||
└── GhostTags
|
||||
|
||||
Authentication
|
||||
├── LoginForm
|
||||
└── RegisterForm
|
||||
|
||||
Content
|
||||
└── MarkdownContent
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Patterns
|
||||
|
||||
### 1. Compound Components
|
||||
|
||||
**NoteEditor** contains:
|
||||
- NoteChecklist (if type=checklist)
|
||||
- NoteImages
|
||||
- EditorImages
|
||||
|
||||
**HeaderWrapper** wraps:
|
||||
- Header
|
||||
- UserNav
|
||||
|
||||
### 2. Controlled Components
|
||||
|
||||
Most components are controlled (parent state):
|
||||
- NoteCard receives note object and callbacks
|
||||
- LabelFilter receives selected labels and onChange
|
||||
- NoteEditor manages local state, calls onSave
|
||||
|
||||
### 3. Modal Pattern
|
||||
|
||||
Dialogs use Radix Dialog:
|
||||
- LabelManagementDialog
|
||||
- ReminderDialog
|
||||
|
||||
Pattern:
|
||||
```tsx
|
||||
{isOpen && (
|
||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||
<DialogContent>{/* content */}</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Communication
|
||||
|
||||
### Props Drilling
|
||||
- Components receive data via props
|
||||
- Callbacks passed for mutations
|
||||
|
||||
### Server Actions
|
||||
- Note mutations via `app/actions/notes.ts`
|
||||
- Label mutations via server actions
|
||||
- Auth mutations via `app/actions/register.ts`
|
||||
|
||||
### Context Providers
|
||||
- User session context (from NextAuth)
|
||||
- Theme context (light/dark mode)
|
||||
|
||||
---
|
||||
|
||||
## Design System
|
||||
|
||||
### Colors
|
||||
|
||||
**Note Colors:** default, red, orange, yellow, green, teal, blue, purple, pink, gray
|
||||
|
||||
**Label Colors:** Same palette as notes
|
||||
|
||||
### Typography
|
||||
|
||||
- **Font:** System font stack (Tailwind default)
|
||||
- **Sizes:** Based on Tailwind typography plugin
|
||||
|
||||
### Spacing
|
||||
|
||||
- **Gap:** Tailwind spacing scale
|
||||
- **Padding:** Consistent 4px/8px/16px/24px increments
|
||||
|
||||
---
|
||||
|
||||
## Component State Management
|
||||
|
||||
### Local State
|
||||
- Form inputs (controlled components)
|
||||
- Modal open/closed state
|
||||
- Temporary editing state
|
||||
|
||||
### Server State
|
||||
- Notes list (fetched from API)
|
||||
- User session (NextAuth)
|
||||
- Labels (fetched from API)
|
||||
|
||||
### State Updates
|
||||
1. User action → Server action / API call
|
||||
2. Database update (Prisma)
|
||||
3. Revalidate / refetch
|
||||
4. Component re-render
|
||||
|
||||
**No Global State Library:** Uses React Context + hooks instead of Redux/Zustand
|
||||
|
||||
---
|
||||
|
||||
## Component Dependencies
|
||||
|
||||
### UI Libraries
|
||||
- Radix UI (primitives)
|
||||
- Tailwind CSS (styling)
|
||||
- Lucide React (icons)
|
||||
- @dnd-kit (drag and drop)
|
||||
- Muuri (masonry layout)
|
||||
- react-grid-layout (grid system)
|
||||
- react-markdown (markdown rendering)
|
||||
- react-masonry-css (alternative masonry)
|
||||
|
||||
### Custom Hooks
|
||||
- Located in `hooks/`
|
||||
- Used for:
|
||||
- Form validation
|
||||
- Local storage
|
||||
- Debouncing
|
||||
- Media queries
|
||||
|
||||
---
|
||||
|
||||
## Component Performance
|
||||
|
||||
### Optimizations
|
||||
- React.memo (selective components)
|
||||
- Lazy loading (dynamic imports)
|
||||
- Image optimization (next/image)
|
||||
- Code splitting (route-based)
|
||||
|
||||
### Masonry Grid
|
||||
- Muuri for performant drag-and-drop
|
||||
- Virtualization for large note lists
|
||||
|
||||
---
|
||||
|
||||
## Component Testing
|
||||
|
||||
### E2E Coverage
|
||||
- Playwright tests in `tests/`
|
||||
- Coverage: Component interactions
|
||||
- Test file: `search-quality.spec.ts`
|
||||
|
||||
### Manual Testing
|
||||
- Test UI in `npm run test:headed`
|
||||
- Test reports: `playwright-report/`
|
||||
|
||||
---
|
||||
|
||||
## Component Styling
|
||||
|
||||
### CSS Strategy
|
||||
- **Framework:** Tailwind CSS 4
|
||||
- **Approach:** Utility-first
|
||||
- **Custom CSS:** In `globals.css`
|
||||
- **Component Styles:** Tailwind classes
|
||||
|
||||
### Responsive Design
|
||||
- Mobile-first approach
|
||||
- Breakpoints: sm, md, lg, xl
|
||||
- Grid adapts to screen size
|
||||
|
||||
### Theme Support
|
||||
- Light/dark mode via user preference
|
||||
- Theme stored in `User.theme`
|
||||
- CSS variables for theme colors
|
||||
|
||||
---
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Radix UI Features
|
||||
- Keyboard navigation
|
||||
- ARIA attributes
|
||||
- Focus management
|
||||
- Screen reader support
|
||||
|
||||
### Custom A11y
|
||||
- Alt text for images
|
||||
- Semantic HTML
|
||||
- Form labels
|
||||
- Error messages
|
||||
|
||||
---
|
||||
|
||||
## Component Future Enhancements
|
||||
|
||||
**Potential Improvements:**
|
||||
1. Add skeleton loaders
|
||||
2. Implement error boundaries
|
||||
3. Add undo/redo for note edits
|
||||
4. Rich text editor (WYSIWYG)
|
||||
5. Collaborative editing
|
||||
6. Note templates
|
||||
7. Color picker for custom colors
|
||||
8. Drag-and-drop file upload
|
||||
9. Voice input (Web Speech API)
|
||||
10. Export/import notes
|
||||
|
||||
---
|
||||
|
||||
## Component Maintenance
|
||||
|
||||
**File Organization:**
|
||||
- Domain-driven (note-*, label-*, auth-*)
|
||||
- Co-located with related components
|
||||
- Clear naming conventions
|
||||
|
||||
**Code Quality:**
|
||||
- TypeScript for type safety
|
||||
- Consistent prop interfaces
|
||||
- Reusable UI primitives
|
||||
- Minimal prop drilling (use context where appropriate)
|
||||
|
||||
---
|
||||
|
||||
## Component Usage Examples
|
||||
|
||||
### NoteCard
|
||||
```tsx
|
||||
<NoteCard
|
||||
note={note}
|
||||
onPin={() => handleTogglePin(note.id)}
|
||||
onArchive={() => handleToggleArchive(note.id)}
|
||||
onUpdate={(updates) => handleUpdateNote(note.id, updates)}
|
||||
onDelete={() => handleDeleteNote(note.id)}
|
||||
/>
|
||||
```
|
||||
|
||||
### LabelSelector
|
||||
```tsx
|
||||
<LabelSelector
|
||||
availableLabels={labels}
|
||||
selectedLabels={note.labels || []}
|
||||
onChange={(newLabels) => updateNoteLabels(note.id, newLabels)}
|
||||
/>
|
||||
```
|
||||
|
||||
### MasonryGrid
|
||||
```tsx
|
||||
<MasonryGrid
|
||||
items={notes}
|
||||
renderItem={(note) => <NoteCard key={note.id} note={note} />}
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The Memento application uses a well-organized component architecture with:
|
||||
- **20+ domain components** for notes, labels, auth, and layout
|
||||
- **Radix UI primitives** for accessible, composable UI
|
||||
- **Controlled components** with parent-managed state
|
||||
- **Server actions** for mutations
|
||||
- **No global state library** (Context + hooks instead)
|
||||
- **Drag-and-drop** via @dnd-kit
|
||||
- **Masonry layout** via Muuri
|
||||
- **Responsive design** with Tailwind CSS
|
||||
459
docs/data-models.md
Normal file
459
docs/data-models.md
Normal file
@@ -0,0 +1,459 @@
|
||||
# Data Models - Memento Project
|
||||
|
||||
## Overview
|
||||
|
||||
Memento uses SQLite as its database with Prisma ORM. The database schema is shared between the web application (keep-notes) and the MCP server.
|
||||
|
||||
**Database:** SQLite (`prisma/dev.db`)
|
||||
**ORM:** Prisma 5.22.0
|
||||
**Adapters:**
|
||||
- `@prisma/adapter-better-sqlite3` (primary)
|
||||
- `@prisma/adapter-libsql` (alternative for Turso)
|
||||
|
||||
---
|
||||
|
||||
## Database Schema
|
||||
|
||||
### User
|
||||
|
||||
Represents a user account with authentication and profile information.
|
||||
|
||||
```prisma
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
password String? // Hashed password (bcrypt)
|
||||
role String @default("USER") // "USER" or "ADMIN"
|
||||
image String? // Profile picture URL
|
||||
theme String @default("light") // UI theme preference
|
||||
resetToken String? @unique // Password reset token
|
||||
resetTokenExpiry DateTime? // Reset token expiration
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
notes Note[]
|
||||
labels Label[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
```
|
||||
|
||||
**Relationships:**
|
||||
- One-to-many with Account (OAuth providers)
|
||||
- One-to-many with Session (active sessions)
|
||||
- One-to-many with Note (user's notes)
|
||||
- One-to-many with Label (user's labels)
|
||||
|
||||
**Fields:**
|
||||
- `id`: CUID (Collision-resistant Unique Identifier)
|
||||
- `email`: Unique email address
|
||||
- `password`: Optional (can be OAuth-only users)
|
||||
- `role`: RBAC - "USER" or "ADMIN"
|
||||
- `theme`: UI theme preference ("light" or "dark")
|
||||
- `resetToken`: Password recovery token (unique)
|
||||
- `resetTokenExpiry`: Token validity period
|
||||
|
||||
---
|
||||
|
||||
### Account
|
||||
|
||||
Stores OAuth provider account information (NextAuth.js).
|
||||
|
||||
```prisma
|
||||
model Account {
|
||||
userId String
|
||||
type String
|
||||
provider String // google, github, etc.
|
||||
providerAccountId String
|
||||
refresh_token String?
|
||||
access_token String?
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String?
|
||||
session_state String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([provider, providerAccountId])
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:** Links OAuth provider accounts to local User accounts
|
||||
|
||||
**Relationships:**
|
||||
- Many-to-one with User (via `userId`)
|
||||
|
||||
**Constraints:**
|
||||
- Composite unique key on `provider` + `providerAccountId`
|
||||
|
||||
---
|
||||
|
||||
### Session
|
||||
|
||||
Stores active user sessions (NextAuth.js).
|
||||
|
||||
```prisma
|
||||
model Session {
|
||||
sessionToken String @unique
|
||||
userId String
|
||||
expires DateTime
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:** Manages active user sessions for authentication
|
||||
|
||||
**Relationships:**
|
||||
- Many-to-one with User (via `userId`)
|
||||
|
||||
**Fields:**
|
||||
- `sessionToken`: Unique session identifier
|
||||
- `expires`: Session expiration timestamp
|
||||
|
||||
---
|
||||
|
||||
### VerificationToken
|
||||
|
||||
Stores email verification tokens (NextAuth.js).
|
||||
|
||||
```prisma
|
||||
model VerificationToken {
|
||||
identifier String
|
||||
token String
|
||||
expires DateTime
|
||||
|
||||
@@id([identifier, token])
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:** Email verification flow
|
||||
|
||||
**Constraints:**
|
||||
- Composite unique key on `identifier` + `token`
|
||||
|
||||
---
|
||||
|
||||
### Label
|
||||
|
||||
User-defined labels/tags for organizing notes.
|
||||
|
||||
```prisma
|
||||
model Label {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
color String @default("gray")
|
||||
userId String? // Made optional for migration
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([name, userId]) // Labels unique per user
|
||||
@@index([userId])
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:** Categorization and organization of notes
|
||||
|
||||
**Relationships:**
|
||||
- Many-to-one with User (via `userId`)
|
||||
|
||||
**Fields:**
|
||||
- `name`: Label display name
|
||||
- `color`: Visual color (red, orange, yellow, green, teal, blue, purple, pink, gray)
|
||||
- `userId`: Optional (migration artifact, logic enforces ownership)
|
||||
|
||||
**Constraints:**
|
||||
- Unique label name per user
|
||||
- Indexed on `userId` for fast lookup
|
||||
|
||||
**Usage:**
|
||||
- Stored as JSON array in `Note.labels`
|
||||
- User can have multiple labels with the same name? No, unique constraint
|
||||
|
||||
---
|
||||
|
||||
### Note
|
||||
|
||||
Core data model - represents a note in the system.
|
||||
|
||||
```prisma
|
||||
model Note {
|
||||
id String @id @default(cuid())
|
||||
title String? // Optional title
|
||||
content String
|
||||
color String @default("default")
|
||||
isPinned Boolean @default(false)
|
||||
isArchived Boolean @default(false)
|
||||
type String @default("text") // "text" or "checklist"
|
||||
checkItems String? // JSON array
|
||||
labels String? // JSON array
|
||||
images String? // JSON array
|
||||
links String? // JSON array
|
||||
reminder DateTime? // Reminder timestamp
|
||||
isReminderDone Boolean @default(false)
|
||||
reminderRecurrence String? // "none", "daily", "weekly", "monthly", "custom"
|
||||
reminderLocation String? // Location-based reminders
|
||||
isMarkdown Boolean @default(false) // Markdown rendering
|
||||
size String @default("small") // "small", "medium", "large"
|
||||
embedding String? // Vector embeddings (JSON)
|
||||
userId String? // Owner
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
order Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([isPinned])
|
||||
@@index([isArchived])
|
||||
@@index([order])
|
||||
@@index([reminder])
|
||||
@@index([userId])
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:** Core note-taking entity
|
||||
|
||||
**Relationships:**
|
||||
- Many-to-one with User (via `userId`)
|
||||
|
||||
**Fields:**
|
||||
|
||||
**Basic:**
|
||||
- `id`: CUID
|
||||
- `title`: Optional heading/title
|
||||
- `content`: Note content (text or markdown)
|
||||
- `color`: Background color (default, red, orange, yellow, green, teal, blue, purple, pink, gray)
|
||||
- `type`: Note type - "text" or "checklist"
|
||||
|
||||
**State Flags:**
|
||||
- `isPinned`: Shows at top of list
|
||||
- `isArchived**: Removed from main view
|
||||
- `isReminderDone`: Reminder completed
|
||||
|
||||
**Rich Features:**
|
||||
- `checkItems`: JSON array of checklist items (if type=checklist)
|
||||
```json
|
||||
[
|
||||
{"id": "string", "text": "string", "checked": boolean}
|
||||
]
|
||||
```
|
||||
- `labels`: JSON array of label names
|
||||
```json
|
||||
["work", "ideas", "urgent"]
|
||||
```
|
||||
- `images`: JSON array of image URLs or base64
|
||||
```json
|
||||
["data:image/png;base64,..."]
|
||||
```
|
||||
- `links`: JSON array of link metadata
|
||||
- `reminder`: ISO8601 datetime for reminder
|
||||
- `reminderRecurrence`: Recurrence pattern
|
||||
- `reminderLocation`: Location-based reminders (future)
|
||||
- `isMarkdown`: Enable markdown rendering
|
||||
- `size`: Visual size (small, medium, large)
|
||||
- `embedding`: Vector embeddings for semantic search (JSON)
|
||||
|
||||
**Ordering:**
|
||||
- `order`: Manual sort order (drag-and-drop)
|
||||
|
||||
**Indexes:**
|
||||
- `isPinned`: Fast lookup for pinned notes
|
||||
- `isArchived`: Filter archived notes
|
||||
- `order`: Sort by manual ordering
|
||||
- `reminder`: Reminder queries (cron jobs)
|
||||
- `userId`: Filter by user
|
||||
|
||||
---
|
||||
|
||||
### SystemConfig
|
||||
|
||||
Key-value storage for system-wide configuration.
|
||||
|
||||
```prisma
|
||||
model SystemConfig {
|
||||
key String @id
|
||||
value String
|
||||
}
|
||||
```
|
||||
|
||||
**Purpose:** System configuration and feature flags
|
||||
|
||||
**Examples:**
|
||||
- Feature toggles
|
||||
- System-wide settings
|
||||
- Admin configuration
|
||||
|
||||
---
|
||||
|
||||
## Relationships Diagram
|
||||
|
||||
```
|
||||
User (1) ----< (N) Account
|
||||
|
|
||||
| (1)
|
||||
|
|
||||
+----< (N) Session
|
||||
|
|
||||
| (1)
|
||||
|
|
||||
+----< (N) Note
|
||||
|
|
||||
| (1)
|
||||
|
|
||||
+----< (N) Label
|
||||
|
||||
VerificationToken (standalone)
|
||||
|
||||
SystemConfig (standalone)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## JSON Field Structures
|
||||
|
||||
### checkItems (Note)
|
||||
Array of checklist items:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "unique-id",
|
||||
"text": "Task description",
|
||||
"checked": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### labels (Note)
|
||||
Array of label names (strings):
|
||||
```json
|
||||
[
|
||||
"work",
|
||||
"ideas",
|
||||
"urgent"
|
||||
]
|
||||
```
|
||||
|
||||
### images (Note)
|
||||
Array of image URLs or base64 strings:
|
||||
```json
|
||||
[
|
||||
"data:image/png;base64,iVBORw0KGgo...",
|
||||
"/uploads/images/note-image.png"
|
||||
]
|
||||
```
|
||||
|
||||
### links (Note)
|
||||
Array of link metadata (structure TBD):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"url": "https://example.com",
|
||||
"title": "Example Site",
|
||||
"description": "..."
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### embedding (Note)
|
||||
Vector embeddings for semantic search (JSON string):
|
||||
```json
|
||||
[0.123, -0.456, 0.789, ...]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database Operations
|
||||
|
||||
### Common Queries
|
||||
|
||||
**Get active user's notes:**
|
||||
```typescript
|
||||
const notes = await prisma.note.findMany({
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
isArchived: false
|
||||
},
|
||||
orderBy: [
|
||||
{ isPinned: 'desc' },
|
||||
{ order: 'asc' },
|
||||
{ updatedAt: 'desc' }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
**Search notes:**
|
||||
```typescript
|
||||
const notes = await prisma.note.findMany({
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
OR: [
|
||||
{ title: { contains: query, mode: 'insensitive' } },
|
||||
{ content: { contains: query, mode: 'insensitive' } }
|
||||
]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Get user's labels:**
|
||||
```typescript
|
||||
const labels = await prisma.label.findMany({
|
||||
where: { userId: session.user.id },
|
||||
orderBy: { name: 'asc' }
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Integrity
|
||||
|
||||
**Cascade Deletes:**
|
||||
- When User is deleted: delete their Accounts, Sessions, Notes, and Labels
|
||||
- Maintains referential integrity
|
||||
|
||||
**Unique Constraints:**
|
||||
- User.email
|
||||
- Account.provider + Account.providerAccountId
|
||||
- VerificationToken.identifier + VerificationToken.token
|
||||
- Label.name + Label.userId (per user)
|
||||
|
||||
**Indexes:**
|
||||
- All foreign keys indexed
|
||||
- Frequently queried fields indexed (isPinned, isArchived, order, reminder, userId)
|
||||
|
||||
---
|
||||
|
||||
## Migration Notes
|
||||
|
||||
**Current State:**
|
||||
- SQLite database for local development
|
||||
- Better-sqlite3 adapter for embedded usage
|
||||
- Optional LibSQL adapter for cloud deployment (Turso)
|
||||
|
||||
**Schema Evolution:**
|
||||
- `Label.userId` made optional for migration (logic enforces ownership)
|
||||
- JSON fields stored as strings (parsed in application layer)
|
||||
- Future: Consider PostgreSQL for production with proper JSONB support
|
||||
|
||||
---
|
||||
|
||||
## Database Size Considerations
|
||||
|
||||
**SQLite Limits:**
|
||||
- Max database size: 281 TB (theoretical)
|
||||
- Max row size: 1 GB
|
||||
- Max string/blob size: 1 GB
|
||||
|
||||
**Practical Considerations:**
|
||||
- Base64 images in Note.images could bloat database
|
||||
- Consider storing large files in filesystem and storing paths
|
||||
- Vector embeddings (Note.embedding) will grow with data
|
||||
|
||||
**Recommendations:**
|
||||
- Use CDN or object storage for images in production
|
||||
- Implement image compression before storage
|
||||
- Monitor database size with large note collections
|
||||
1214
docs/deployment-guide.md
Normal file
1214
docs/deployment-guide.md
Normal file
File diff suppressed because it is too large
Load Diff
853
docs/development-guide-keep-notes.md
Normal file
853
docs/development-guide-keep-notes.md
Normal file
@@ -0,0 +1,853 @@
|
||||
# Development Guide - keep-notes (Memento Web App)
|
||||
|
||||
## Overview
|
||||
|
||||
Complete development guide for the Memento web application. Covers setup, development workflow, debugging, testing, and common tasks.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Required Software
|
||||
|
||||
| Tool | Version | Purpose |
|
||||
|------|---------|---------|
|
||||
| **Node.js** | 20+ | JavaScript runtime |
|
||||
| **npm** | Latest | Package manager |
|
||||
| **Git** | Latest | Version control |
|
||||
|
||||
### Recommended Tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| VS Code | IDE with great TypeScript/React support |
|
||||
| Prisma Studio | Database GUI for viewing/editing data |
|
||||
| Postman/Insomnia | API testing |
|
||||
| Playwright VS Code | E2E test debugging |
|
||||
|
||||
---
|
||||
|
||||
## Initial Setup
|
||||
|
||||
### 1. Clone Repository
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd Keep
|
||||
```
|
||||
|
||||
### 2. Install Dependencies
|
||||
|
||||
```bash
|
||||
cd keep-notes
|
||||
npm install
|
||||
```
|
||||
|
||||
**Expected packages:**
|
||||
- React 19.2.3
|
||||
- Next.js 16.1.1
|
||||
- Prisma 5.22.0
|
||||
- 100+ dependencies
|
||||
|
||||
### 3. Database Setup
|
||||
|
||||
```bash
|
||||
# Generate Prisma client
|
||||
npm run db:generate
|
||||
|
||||
# Run migrations (if needed)
|
||||
npx prisma migrate dev
|
||||
|
||||
# Open Prisma Studio (optional)
|
||||
npx prisma studio
|
||||
```
|
||||
|
||||
**Prisma Studio:**
|
||||
- Opens at http://localhost:5555
|
||||
- View and edit database records
|
||||
- Visual database schema
|
||||
|
||||
### 4. Environment Configuration
|
||||
|
||||
Create `.env` file in `keep-notes/`:
|
||||
|
||||
```bash
|
||||
# Database
|
||||
DATABASE_URL="file:./prisma/dev.db"
|
||||
|
||||
# NextAuth
|
||||
NEXTAUTH_SECRET="your-secret-key-here"
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
|
||||
# Email (optional - for password reset)
|
||||
SMTP_HOST="smtp.example.com"
|
||||
SMTP_PORT="587"
|
||||
SMTP_USER="your-email@example.com"
|
||||
SMTP_PASS="your-password"
|
||||
SMTP_FROM="noreply@memento.app"
|
||||
|
||||
# AI Providers (optional)
|
||||
OPENAI_API_KEY="sk-..."
|
||||
OLLAMA_API_URL="http://localhost:11434"
|
||||
```
|
||||
|
||||
**Generate NEXTAUTH_SECRET:**
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Start Development Server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
**Server starts at:** http://localhost:3000
|
||||
|
||||
**Features:**
|
||||
- Hot reload (Fast Refresh)
|
||||
- TypeScript checking
|
||||
- Source maps for debugging
|
||||
- API routes available
|
||||
|
||||
### File Watching
|
||||
|
||||
Next.js automatically watches for changes in:
|
||||
- `app/` directory
|
||||
- `components/` directory
|
||||
- `lib/` directory
|
||||
- `public/` directory
|
||||
|
||||
**Automatic Actions:**
|
||||
- Recompile changed files
|
||||
- Refresh browser (HMR)
|
||||
- Regenerate Prisma client if schema changes
|
||||
|
||||
---
|
||||
|
||||
## Common Development Tasks
|
||||
|
||||
### 1. Create a New Component
|
||||
|
||||
```bash
|
||||
# Create component file
|
||||
touch components/my-component.tsx
|
||||
```
|
||||
|
||||
```typescript
|
||||
// components/my-component.tsx
|
||||
export default function MyComponent() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello from Memento!</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
import MyComponent from '@/components/my-component'
|
||||
|
||||
export default function Page() {
|
||||
return <MyComponent />
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Add a New API Route
|
||||
|
||||
```bash
|
||||
# Create API route directory
|
||||
mkdir -p app/api/my-resource
|
||||
touch app/api/my-resource/route.ts
|
||||
```
|
||||
|
||||
```typescript
|
||||
// app/api/my-resource/route.ts
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({ message: 'Hello' })
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const body = await request.json()
|
||||
return NextResponse.json({ received: body })
|
||||
}
|
||||
```
|
||||
|
||||
**Access:** http://localhost:3000/api/my-resource
|
||||
|
||||
### 3. Add a New Server Action
|
||||
|
||||
```bash
|
||||
# Create action file
|
||||
touch app/actions/my-action.ts
|
||||
```
|
||||
|
||||
```typescript
|
||||
'use server'
|
||||
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { revalidatePath } from 'next/cache'
|
||||
|
||||
export async function myAction(id: string) {
|
||||
const result = await prisma.note.update({
|
||||
where: { id },
|
||||
data: { /* updates */ }
|
||||
})
|
||||
|
||||
revalidatePath('/')
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
**Usage in Component:**
|
||||
```tsx
|
||||
import { myAction } from '@/app/actions/my-action'
|
||||
|
||||
export default function MyComponent() {
|
||||
async function handleSubmit() {
|
||||
await myAction('note-id')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Modify Database Schema
|
||||
|
||||
```bash
|
||||
# 1. Edit schema
|
||||
nano prisma/schema.prisma
|
||||
|
||||
# 2. Create migration
|
||||
npx prisma migrate dev --name my_changes
|
||||
|
||||
# 3. Update client
|
||||
npm run db:generate
|
||||
```
|
||||
|
||||
**Example Schema Change:**
|
||||
```prisma
|
||||
model Note {
|
||||
// ... existing fields
|
||||
newField String? // Add new optional field
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Run Tests
|
||||
|
||||
```bash
|
||||
# Run all E2E tests
|
||||
npm test
|
||||
|
||||
# Run tests with UI
|
||||
npm run test:ui
|
||||
|
||||
# Run tests in headed mode (see browser)
|
||||
npm run test:headed
|
||||
```
|
||||
|
||||
**Test Reports:**
|
||||
- HTML: `playwright-report/index.html`
|
||||
- Results: `test-results/.last-run.json`
|
||||
|
||||
---
|
||||
|
||||
## Database Operations
|
||||
|
||||
### View Data with Prisma Studio
|
||||
|
||||
```bash
|
||||
npx prisma studio
|
||||
# Opens at http://localhost:5555
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Browse tables
|
||||
- Edit records
|
||||
- Add records
|
||||
- Filter and query
|
||||
|
||||
### Manual Database Queries
|
||||
|
||||
```bash
|
||||
# Open SQLite CLI
|
||||
sqlite3 keep-notes/prisma/dev.db
|
||||
|
||||
# Query notes
|
||||
SELECT * FROM Note LIMIT 10;
|
||||
|
||||
# Query users
|
||||
SELECT * FROM User;
|
||||
|
||||
# Exit
|
||||
.quit
|
||||
```
|
||||
|
||||
### Reset Database
|
||||
|
||||
```bash
|
||||
# Delete database file
|
||||
rm keep-notes/prisma/dev.db
|
||||
|
||||
# Re-run migrations
|
||||
npx prisma migrate dev
|
||||
|
||||
# Seed data (if you have a seed script)
|
||||
npx prisma db seed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
### Server-Side Debugging
|
||||
|
||||
**VS Code Launch Config:**
|
||||
|
||||
Create `.vscode/launch.json`:
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Next.js: debug server-side",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "npm run dev"
|
||||
},
|
||||
{
|
||||
"name": "Next.js: debug client-side",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:3000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Console Logging
|
||||
|
||||
**Server Components:**
|
||||
```typescript
|
||||
console.log('Server log', data) // Appears in terminal
|
||||
```
|
||||
|
||||
**Client Components:**
|
||||
```typescript
|
||||
console.log('Client log', data) // Appears in browser console
|
||||
```
|
||||
|
||||
### Debug API Routes
|
||||
|
||||
Add logging to API routes:
|
||||
```typescript
|
||||
export async function GET(request: NextRequest) {
|
||||
console.log('GET /api/notes called')
|
||||
console.log('Query params:', request.nextUrl.searchParams)
|
||||
|
||||
const notes = await prisma.note.findMany()
|
||||
console.log('Found notes:', notes.length)
|
||||
|
||||
return NextResponse.json({ data: notes })
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TypeScript Configuration
|
||||
|
||||
### Type Checking
|
||||
|
||||
```bash
|
||||
# Type check all files
|
||||
npx tsc --noEmit
|
||||
|
||||
# Type check with watch mode
|
||||
npx tsc --noEmit --watch
|
||||
```
|
||||
|
||||
### Common Type Issues
|
||||
|
||||
**1. Prisma Client Types:**
|
||||
```typescript
|
||||
import prisma from '@/lib/prisma'
|
||||
|
||||
// Use Prisma types
|
||||
type Note = Prisma.NoteGetPayload<{ include: {} }>
|
||||
```
|
||||
|
||||
**2. Server Actions:**
|
||||
```typescript
|
||||
'use server'
|
||||
|
||||
// Server actions must be async
|
||||
export async function myAction() {
|
||||
// Action logic
|
||||
}
|
||||
```
|
||||
|
||||
**3. Component Props:**
|
||||
```typescript
|
||||
interface MyComponentProps {
|
||||
title: string
|
||||
count?: number // Optional
|
||||
}
|
||||
|
||||
export default function MyComponent({ title, count = 0 }: MyComponentProps) {
|
||||
return <div>{title}: {count}</div>
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Styling Guide
|
||||
|
||||
### Tailwind CSS Classes
|
||||
|
||||
**Documentation:** https://tailwindcss.com/docs
|
||||
|
||||
**Common Patterns:**
|
||||
```tsx
|
||||
// Spacing
|
||||
<div className="p-4 m-2"> // Padding 4, margin 2
|
||||
<div className="gap-4"> // Gap between children
|
||||
|
||||
// Colors
|
||||
<div className="bg-blue-500 text-white">
|
||||
<div className="text-gray-700 dark:text-gray-300">
|
||||
|
||||
// Typography
|
||||
<h1 className="text-2xl font-bold">
|
||||
<p className="text-sm leading-relaxed">
|
||||
|
||||
// Layout
|
||||
<div className="flex flex-col md:flex-row">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
|
||||
// Responsive
|
||||
<div className="hidden md:block">
|
||||
<div className="w-full md:w-1/2">
|
||||
```
|
||||
|
||||
### Custom CSS
|
||||
|
||||
**Global Styles:** `app/globals.css`
|
||||
|
||||
**Component-Specific:**
|
||||
```tsx
|
||||
// Use Tailwind @apply or inline styles
|
||||
<div style={{ customProperty: 'value' }} />
|
||||
|
||||
// Or CSS modules
|
||||
import styles from './MyComponent.module.css'
|
||||
<div className={styles.container}>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Working with Prisma
|
||||
|
||||
### Common Queries
|
||||
|
||||
**Find all notes for a user:**
|
||||
```typescript
|
||||
const notes = await prisma.note.findMany({
|
||||
where: { userId: session.user.id },
|
||||
orderBy: { updatedAt: 'desc' }
|
||||
})
|
||||
```
|
||||
|
||||
**Create a note:**
|
||||
```typescript
|
||||
const note = await prisma.note.create({
|
||||
data: {
|
||||
title: 'My Note',
|
||||
content: 'Note content',
|
||||
color: 'blue',
|
||||
userId: session.user.id
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Update a note:**
|
||||
```typescript
|
||||
const note = await prisma.note.update({
|
||||
where: { id: noteId },
|
||||
data: {
|
||||
title: 'Updated Title',
|
||||
content: 'Updated content'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**Delete a note:**
|
||||
```typescript
|
||||
await prisma.note.delete({
|
||||
where: { id: noteId }
|
||||
})
|
||||
```
|
||||
|
||||
**Search notes:**
|
||||
```typescript
|
||||
const notes = await prisma.note.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ title: { contains: query, mode: 'insensitive' } },
|
||||
{ content: { contains: query, mode: 'insensitive' } }
|
||||
]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Transaction Support
|
||||
|
||||
```typescript
|
||||
await prisma.$transaction(async (tx) => {
|
||||
// Multiple operations
|
||||
await tx.note.create({ data: note1 })
|
||||
await tx.note.create({ data: note2 })
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication Development
|
||||
|
||||
### NextAuth Configuration
|
||||
|
||||
**Config File:** `auth.config.ts`
|
||||
|
||||
**Add OAuth Provider:**
|
||||
```typescript
|
||||
export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
providers: [
|
||||
Google({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
}),
|
||||
// ... other providers
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
### Protected Routes
|
||||
|
||||
**Server Component:**
|
||||
```tsx
|
||||
import { auth } from '@/auth'
|
||||
import { redirect } from 'next/navigation'
|
||||
|
||||
export default async function ProtectedPage() {
|
||||
const session = await auth()
|
||||
|
||||
if (!session) {
|
||||
redirect('/login')
|
||||
}
|
||||
|
||||
return <div>Welcome {session.user.name}</div>
|
||||
}
|
||||
```
|
||||
|
||||
**API Route:**
|
||||
```typescript
|
||||
import { auth } from '@/auth'
|
||||
|
||||
export async function GET() {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
return NextResponse.json({ data: 'secret' })
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AI Integration Development
|
||||
|
||||
### Add New AI Provider
|
||||
|
||||
**1. Create Provider File:**
|
||||
```bash
|
||||
touch lib/ai/providers/my-provider.ts
|
||||
```
|
||||
|
||||
**2. Implement Provider:**
|
||||
```typescript
|
||||
// lib/ai/providers/my-provider.ts
|
||||
export function createMyProvider() {
|
||||
return {
|
||||
generateText: async (prompt) => {
|
||||
// Call AI API
|
||||
return response
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**3. Register in Factory:**
|
||||
```typescript
|
||||
// lib/ai/factory.ts
|
||||
export function getProvider(provider: string) {
|
||||
switch (provider) {
|
||||
case 'my-provider':
|
||||
return createMyProvider()
|
||||
// ... existing providers
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Use AI SDK
|
||||
|
||||
```typescript
|
||||
import { generateText } from 'ai'
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
|
||||
const response = await generateText({
|
||||
model: openai('gpt-4'),
|
||||
prompt: 'Generate tags for this note...',
|
||||
})
|
||||
|
||||
console.log(response.text)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### 1. Image Optimization
|
||||
|
||||
```tsx
|
||||
import Image from 'next/image'
|
||||
|
||||
<Image
|
||||
src="/image.png"
|
||||
alt="Description"
|
||||
width={500}
|
||||
height={300}
|
||||
priority // For above-fold images
|
||||
/>
|
||||
```
|
||||
|
||||
### 2. Code Splitting
|
||||
|
||||
```tsx
|
||||
// Dynamic import for heavy components
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
|
||||
loading: () => <div>Loading...</div>,
|
||||
ssr: false // Client-only
|
||||
})
|
||||
```
|
||||
|
||||
### 3. Server Components (Default)
|
||||
|
||||
```tsx
|
||||
// Server components are default (no 'use client')
|
||||
export default async function Page() {
|
||||
const data = await fetch('https://api.example.com/data')
|
||||
return <div>{data}</div>
|
||||
}
|
||||
```
|
||||
|
||||
**Client Component:**
|
||||
```tsx
|
||||
'use client' // Required for interactivity
|
||||
|
||||
export default function InteractiveComponent() {
|
||||
const [count, setCount] = useState(0)
|
||||
return <button onClick={() => setCount(count + 1)}>{count}</button>
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Guide
|
||||
|
||||
### Write E2E Test
|
||||
|
||||
**File:** `tests/my-feature.spec.ts`
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('my feature test', async ({ page }) => {
|
||||
await page.goto('http://localhost:3000')
|
||||
|
||||
await page.fill('input[name="email"]', 'test@example.com')
|
||||
await page.click('button[type="submit"]')
|
||||
|
||||
await expect(page).toHaveURL('/dashboard')
|
||||
})
|
||||
```
|
||||
|
||||
### Run Specific Test
|
||||
|
||||
```bash
|
||||
npx playwright test tests/my-feature.spec.ts
|
||||
```
|
||||
|
||||
### Debug Tests
|
||||
|
||||
```bash
|
||||
# Run with UI
|
||||
npm run test:ui
|
||||
|
||||
# Run headed mode
|
||||
npm run test:headed
|
||||
|
||||
# Debug mode
|
||||
npx playwright test --debug
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Issues & Solutions
|
||||
|
||||
### Issue: Prisma Client Not Generated
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
npm run db:generate
|
||||
```
|
||||
|
||||
### Issue: Port Already in Use
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Kill process on port 3000
|
||||
npx kill-port 3000
|
||||
|
||||
# Or find and kill manually
|
||||
lsof -ti:3000 | xargs kill -9
|
||||
```
|
||||
|
||||
### Issue: Module Not Found
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Clear cache and reinstall
|
||||
rm -rf node_modules .next
|
||||
npm install
|
||||
```
|
||||
|
||||
### Issue: Database Locked
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Close Prisma Studio or other DB connections
|
||||
# Or wait for SQLite to release lock
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build & Production
|
||||
|
||||
### Build for Production
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
**Output:** `.next/` directory
|
||||
|
||||
### Start Production Server
|
||||
|
||||
```bash
|
||||
npm start
|
||||
# Runs on port 3000 (or PORT env var)
|
||||
```
|
||||
|
||||
### Environment Variables for Production
|
||||
|
||||
```bash
|
||||
# .env.production
|
||||
DATABASE_URL="file:./prisma/dev.db"
|
||||
NEXTAUTH_SECRET="production-secret"
|
||||
NEXTAUTH_URL="https://your-domain.com"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Tips
|
||||
|
||||
### 1. Use TypeScript Strict Mode
|
||||
|
||||
Already enabled in `tsconfig.json`:
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. ESLint & Prettier
|
||||
|
||||
```bash
|
||||
# Lint code
|
||||
npm run lint
|
||||
|
||||
# Fix linting issues
|
||||
npm run lint -- --fix
|
||||
```
|
||||
|
||||
### 3. Git Hooks (Optional)
|
||||
|
||||
Install husky for pre-commit hooks:
|
||||
```bash
|
||||
npm install -D husky lint-staged
|
||||
npx husky install
|
||||
```
|
||||
|
||||
### 4. VS Code Extensions
|
||||
|
||||
Recommended:
|
||||
- Prisma
|
||||
- ESLint
|
||||
- Prettier
|
||||
- Tailwind CSS IntelliSense
|
||||
- TypeScript Vue Plugin (Volar)
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
### Documentation
|
||||
- Next.js: https://nextjs.org/docs
|
||||
- Prisma: https://www.prisma.io/docs
|
||||
- React: https://react.dev
|
||||
- Tailwind CSS: https://tailwindcss.com/docs
|
||||
- Radix UI: https://www.radix-ui.com/primitives
|
||||
|
||||
### Community
|
||||
- Next.js GitHub Discussions
|
||||
- Prisma Slack
|
||||
- Stack Overflow
|
||||
|
||||
### Project-Specific
|
||||
- API Contracts: `docs/api-contracts-keep-notes.md`
|
||||
- Data Models: `docs/data-models.md`
|
||||
- Component Inventory: `docs/component-inventory.md`
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The Memento web application uses a modern Next.js 16 stack with:
|
||||
- **App Router** for routing
|
||||
- **Server Components** by default
|
||||
- **Prisma ORM** for database access
|
||||
- **NextAuth** for authentication
|
||||
- **Tailwind CSS** for styling
|
||||
- **Playwright** for E2E testing
|
||||
|
||||
This guide provides everything needed for local development, debugging, and testing.
|
||||
272
docs/index.md
Normal file
272
docs/index.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# Memento - Project Documentation Index
|
||||
|
||||
## Project Overview
|
||||
|
||||
- **Type:** Multi-part with 2 parts
|
||||
- **Primary Language:** TypeScript (keep-notes), JavaScript (mcp-server)
|
||||
- **Architecture:** Full-stack JAMstack with Microservice Extension
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### keep-notes (Memento Web App)
|
||||
- **Type:** Web Application
|
||||
- **Tech Stack:** Next.js 16 + React 19 + TypeScript 5 + Prisma + SQLite
|
||||
- **Entry Point:** keep-notes/app/layout.tsx
|
||||
- **Architecture Pattern:** Full-stack JAMstack with App Router
|
||||
|
||||
### mcp-server (MCP Server)
|
||||
- **Type:** Backend API
|
||||
- **Tech Stack:** Express 4 + MCP SDK 1.0.4 + Prisma + SQLite (shared)
|
||||
- **Entry Point:** mcp-server/index.js
|
||||
- **Architecture Pattern:** Microservice API
|
||||
|
||||
---
|
||||
|
||||
## Generated Documentation
|
||||
|
||||
### Core Documentation
|
||||
- [Project Overview](./project-overview.md)
|
||||
- [Source Tree Analysis](./source-tree-analysis.md) _(To be generated)_
|
||||
- [Component Inventory](./component-inventory.md) _(To be generated)_
|
||||
|
||||
### API Documentation
|
||||
- [API Contracts - keep-notes](./api-contracts-keep-notes.md)
|
||||
- [API Contracts - mcp-server](./api-contracts-mcp-server.md)
|
||||
|
||||
### Data & Architecture
|
||||
- [Data Models](./data-models.md)
|
||||
- [Architecture - keep-notes](./architecture-keep-notes.md) _(To be generated)_
|
||||
- [Architecture - mcp-server](./architecture-mcp-server.md) _(To be generated)_
|
||||
- [Integration Architecture](./integration-architecture.md) _(To be generated)_
|
||||
|
||||
### Development Guides
|
||||
- [Development Guide - keep-notes](./development-guide-keep-notes.md) _(To be generated)_
|
||||
- [Deployment Guide](./deployment-guide.md) _(To be generated)_
|
||||
|
||||
---
|
||||
|
||||
## Existing Documentation
|
||||
|
||||
### Root Documentation
|
||||
- [README.md](../README.md) - Main project README
|
||||
- [CHANGELOG.md](../CHANGELOG.md) - Version history and changes
|
||||
- [COMPLETED-FEATURES.md](../COMPLETED-FEATURES.md) - Completed features list
|
||||
|
||||
### Technical Documentation
|
||||
- [MCP-GUIDE.md](../MCP-GUIDE.md) - MCP integration guide
|
||||
- [MCP-LIGHTWEIGHT-TEST.md](../MCP-LIGHTWEIGHT-TEST.md) - MCP testing notes
|
||||
- [MCP-SSE-ANALYSIS.md](../MCP-SSE-ANALYSIS.md) - Server-Sent Events implementation
|
||||
- [N8N-MCP-SETUP.md](../N8N-MCP-SETUP.md) - N8N workflow integration
|
||||
- [N8N-TECH-NEWS.md](../N8N-TECH-NEWS.md) - N8N technical news workflow
|
||||
|
||||
### Component Documentation
|
||||
- [keep-notes/README.md](../keep-notes/README.md) - Web app README
|
||||
- [mcp-server/README.md](../mcp-server/README.md) - MCP server README
|
||||
- [mcp-server/N8N-CONFIG.md](../mcp-server/N8N-CONFIG.md) - N8N configuration
|
||||
- [mcp-server/README-SSE.md](../mcp-server/README-SSE.md) - SSE variant documentation
|
||||
|
||||
---
|
||||
|
||||
## Planning Artifacts
|
||||
|
||||
### Product Planning
|
||||
- [PRD](../_bmad-output/planning-artifacts/prd.md) - Product Requirements Document
|
||||
- [PRD - Web App Requirements](../_bmad-output/planning-artifacts/prd-web-app-requirements.md)
|
||||
- [PRD - Executive Summary](../_bmad-output/planning-artifacts/prd-executive-summary.md)
|
||||
- [PRD - Auth/Admin](../_bmad-output/planning-artifacts/prd-auth-admin.md)
|
||||
|
||||
### Development Planning
|
||||
- [Epics](../_bmad-output/planning-artifacts/epics.md) - Epic definitions
|
||||
- [Implementation Readiness Report](../_bmad-output/planning-artifacts/implementation-readiness-report-2026-01-09.md)
|
||||
|
||||
### Implementation Artifacts
|
||||
- [Stories](../_bmad-output/implementation-artifacts/) - User stories and implementation details
|
||||
- Infrastructure setup stories
|
||||
- AI abstraction stories
|
||||
- Search and tagging features
|
||||
- Vector indexing and semantic search
|
||||
- Model configuration interface
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 20+
|
||||
- npm or yarn
|
||||
- SQLite3 (included)
|
||||
|
||||
### Installation
|
||||
|
||||
**Web Application:**
|
||||
```bash
|
||||
cd keep-notes
|
||||
npm install
|
||||
npm run db:generate
|
||||
npm run dev
|
||||
# Access at http://localhost:3000
|
||||
```
|
||||
|
||||
**MCP Server:**
|
||||
```bash
|
||||
cd mcp-server
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
### Development Commands
|
||||
|
||||
**Web App:**
|
||||
- `npm run dev` - Start development server
|
||||
- `npm run build` - Build for production
|
||||
- `npm start` - Start production server
|
||||
- `npm test` - Run E2E tests
|
||||
- `npm run test:ui` - Run tests with UI
|
||||
- `npm run db:generate` - Regenerate Prisma client
|
||||
|
||||
**MCP Server:**
|
||||
- `npm start` - Start MCP server (stdio)
|
||||
- `npm run start:sse` - Start SSE variant
|
||||
|
||||
---
|
||||
|
||||
## Architecture Summary
|
||||
|
||||
### Multi-Part Project Structure
|
||||
|
||||
**Parts:**
|
||||
1. **keep-notes/** - Next.js web application (main user interface)
|
||||
2. **mcp-server/** - Express-based MCP server (N8N integration)
|
||||
|
||||
**Integration:**
|
||||
- Shared SQLite database (`keep-notes/prisma/dev.db`)
|
||||
- Database-mediated communication
|
||||
- Independent deployment capability
|
||||
|
||||
### Technology Stack
|
||||
|
||||
**Frontend:**
|
||||
- Next.js 16.1.1 (App Router)
|
||||
- React 19.2.3
|
||||
- TypeScript 5
|
||||
- Tailwind CSS 4
|
||||
- Radix UI
|
||||
|
||||
**Backend:**
|
||||
- Next.js API Routes (keep-notes)
|
||||
- Express 4.22.1 (mcp-server)
|
||||
- Prisma 5.22.0 (ORM)
|
||||
- SQLite (database)
|
||||
|
||||
**Integration:**
|
||||
- MCP SDK 1.0.4
|
||||
- NextAuth.js 5.0.0-beta.30
|
||||
- Vercel AI SDK 6.0.23
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### User Features
|
||||
- Rich text notes with markdown support
|
||||
- Checklist notes
|
||||
- Color-coded notes
|
||||
- Labeling/tagging system
|
||||
- Pinning and archiving
|
||||
- Image attachments
|
||||
- Reminders with recurrence
|
||||
- Drag-and-drop grid layout
|
||||
- Semantic search (AI-powered)
|
||||
- Auto-tagging (AI-powered)
|
||||
- User authentication
|
||||
- Admin panel
|
||||
|
||||
### Technical Features
|
||||
- Progressive Web App (PWA)
|
||||
- Responsive design
|
||||
- E2E testing (Playwright)
|
||||
- MCP integration
|
||||
- Multiple AI providers (OpenAI, Ollama)
|
||||
- Email notifications
|
||||
|
||||
---
|
||||
|
||||
## Current Status
|
||||
|
||||
**Development Stage:** Active Development
|
||||
**Branch:** `bmad-features`
|
||||
**Version:** 0.2.0
|
||||
|
||||
**Completed:**
|
||||
- ✅ 6 user stories implemented
|
||||
- ✅ PRD and Epics defined
|
||||
- ✅ Sprint tracking active
|
||||
- ✅ Core features functional
|
||||
|
||||
**In Progress:**
|
||||
- 🔄 Docker setup
|
||||
- 🔄 Documentation completion
|
||||
- 🔄 Code review and cleanup
|
||||
- 🔄 Monetization planning
|
||||
|
||||
---
|
||||
|
||||
## Documentation for AI Agents
|
||||
|
||||
When working with this codebase, AI agents should reference:
|
||||
|
||||
1. **Project Context:** Read [project-overview.md](./project-overview.md) first
|
||||
2. **API Contracts:** Reference [api-contracts-keep-notes.md](./api-contracts-keep-notes.md) and [api-contracts-mcp-server.md](./api-contracts-mcp-server.md)
|
||||
3. **Data Models:** Understand schema from [data-models.md](./data-models.md)
|
||||
4. **PRD:** Review [prd.md](../_bmad-output/planning-artifacts/prd.md) for product context
|
||||
5. **Epics:** Check [epics.md](../_bmad-output/planning-artifacts/epics.md) for planned features
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
**Immediate:**
|
||||
1. Complete Docker setup
|
||||
2. Finish documentation
|
||||
3. Code review
|
||||
4. Test cleanup
|
||||
|
||||
**Short-term:**
|
||||
1. Implement monitization ("Pay me a coffee")
|
||||
2. Business model analysis
|
||||
3. GitHub release preparation
|
||||
|
||||
**Long-term:**
|
||||
1. Feature enhancements
|
||||
2. Community building
|
||||
3. Integration marketplace
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
**Current Status:** Pre-release, not accepting external contributions yet
|
||||
|
||||
**Future:** After GitHub release, contribution guidelines will be added
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
**Status:** To be determined (MIT/Apache/etc.)
|
||||
**Business Model:** Open source with optional paid features
|
||||
|
||||
---
|
||||
|
||||
## Contact & Support
|
||||
|
||||
**Issues:** GitHub Issues (once published)
|
||||
**Documentation:** This index and linked files
|
||||
**Technical Guides:** Root-level markdown files
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: 2026-01-09*
|
||||
*Documentation Generated by: BMAD Document Project Workflow*
|
||||
682
docs/integration-architecture.md
Normal file
682
docs/integration-architecture.md
Normal file
@@ -0,0 +1,682 @@
|
||||
# Integration Architecture - Memento Project
|
||||
|
||||
## Overview
|
||||
|
||||
Document describing how the two parts of the Memento project (keep-notes web application and mcp-server) integrate and communicate with each other and external systems.
|
||||
|
||||
---
|
||||
|
||||
## System Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ External Systems │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
|
||||
│ │ User │ │ AI │ │ N8N │ │ Email │ │
|
||||
│ │ Browser │ │Assistant │ │ Workflow │ │ Service │ │
|
||||
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │
|
||||
│ │ │ │ │ │
|
||||
└───────┼─────────────┼─────────────┼──────────────┼─────────┘
|
||||
│ │ │ │
|
||||
↓ ↓ ↓ ↓
|
||||
┌───────────────────────────────────────────────────────────────┐
|
||||
│ Memento System │
|
||||
├───────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ keep-notes (Next.js Web App) │ │
|
||||
│ │ │ │
|
||||
│ │ Frontend (React/Next.js) │ │
|
||||
│ │ ├─ User Interface (20+ components) │ │
|
||||
│ │ ├─ State Management (Context + Hooks) │ │
|
||||
│ │ └─ Client-Side Routing │ │
|
||||
│ │ │ │
|
||||
│ │ Backend (Next.js API Routes + Server Actions) │ │
|
||||
│ │ ├─ REST API Endpoints (12 routes) │ │
|
||||
│ │ ├─ Server Actions (mutations) │ │
|
||||
│ │ ├─ Authentication (NextAuth) │ │
|
||||
│ │ ├─ AI Integration (Vercel AI SDK) │ │
|
||||
│ │ └─ Cron Jobs (reminders) │ │
|
||||
│ │ │ │
|
||||
│ │ ┌──────────────────────────────────────────────┐ │ │
|
||||
│ │ │ Prisma ORM Layer │ │ │
|
||||
│ │ │ ┌──────────────────────────────────────┐ │ │ │
|
||||
│ │ │ │ SQLite Database (dev.db) │ │ │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ │ │ - User │ │ │ │
|
||||
│ │ │ │ - Note │ │ │ │
|
||||
│ │ │ │ - Label │ │ │ │
|
||||
│ │ │ │ - Account, Session, etc. │ │ │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ │ └──────────────────────────────────────┘ │ │ │
|
||||
│ │ └──────────────────────────────────────────────┘ │ │
|
||||
│ └────────────────────────────────────────────────────┘ │
|
||||
│ ↕ │
|
||||
│ Shared Data │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ mcp-server (Express MCP Server) │ │
|
||||
│ │ │ │
|
||||
│ │ MCP Protocol Layer │ │
|
||||
│ │ ├─ Tools (9 tools: create_note, search, etc.) │ │
|
||||
│ │ ├─ Request/Response Handling │ │
|
||||
│ │ └─ Error Handling │ │
|
||||
│ │ │ │
|
||||
│ │ ┌──────────────────────────────────────────────┐ │ │
|
||||
│ │ │ Prisma Client (Shared) │ │ │
|
||||
│ │ └──────────────┬───────────────────────────────┘ │ │
|
||||
│ │ │ Direct Access │ │
|
||||
│ │ ↓ │ │
|
||||
│ │ ┌──────────────────────────────────────────────┐ │ │
|
||||
│ │ │ ../keep-notes/prisma/dev.db (Same File) │◄───┼────┘
|
||||
│ │ └──────────────────────────────────────────────┘ │
|
||||
│ └────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### 1. Database Integration (Primary)
|
||||
|
||||
**Type:** Direct File Access
|
||||
**Protocol:** SQLite file sharing
|
||||
**Direction:** Both read/write
|
||||
|
||||
**keep-notes → Database:**
|
||||
```typescript
|
||||
// lib/prisma.ts
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
const prisma = new PrismaClient()
|
||||
// Direct connection to prisma/dev.db
|
||||
```
|
||||
|
||||
**mcp-server → Database:**
|
||||
```javascript
|
||||
// index.js
|
||||
const prisma = new PrismaClient({
|
||||
datasources: {
|
||||
db: {
|
||||
url: `file:${join(__dirname, '../keep-notes/prisma/dev.db')}`
|
||||
}
|
||||
}
|
||||
});
|
||||
// Connects to SAME database file
|
||||
```
|
||||
|
||||
**Data Consistency:**
|
||||
- Both parts see same data immediately
|
||||
- No replication lag
|
||||
- Single source of truth
|
||||
- SQLite handles concurrent reads
|
||||
- Single writer limitation (acceptable for current scale)
|
||||
|
||||
**Implications:**
|
||||
- ✅ Real-time data sync
|
||||
- ✅ Simple architecture
|
||||
- ✅ No API needed between parts
|
||||
- ⚠️ Must be on same filesystem (or network mount)
|
||||
- ⚠️ SQLite concurrency limits
|
||||
- ⚠️ Single point of failure (database file)
|
||||
|
||||
---
|
||||
|
||||
### 2. HTTP Integration (Future/Optional)
|
||||
|
||||
**Current:** No HTTP communication between keep-notes and mcp-server
|
||||
|
||||
**Potential HTTP Integration:**
|
||||
```
|
||||
keep-notes → HTTP → mcp-server → Prisma → DB
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- Remote deployment (separate servers)
|
||||
- MCP server as API gateway
|
||||
- Webhook forwarding
|
||||
|
||||
**Current State:** Not implemented (database-mediated preferred)
|
||||
|
||||
---
|
||||
|
||||
### 3. User Authentication Integration
|
||||
|
||||
**keep-notes:**
|
||||
- NextAuth.js v5 for authentication
|
||||
- Session stored in `Session` table (DB)
|
||||
- Protected routes via middleware
|
||||
|
||||
**mcp-server:**
|
||||
- **NO authentication** currently
|
||||
- Direct database access
|
||||
- Trusts client environment
|
||||
|
||||
**Security Implications:**
|
||||
- ⚠️ MCP server has full DB access
|
||||
- ⚠️ No authentication layer
|
||||
- ✅ Acceptable for local/localhost
|
||||
- ❌ Not secure for public deployment
|
||||
|
||||
**Recommendation:** Add API key auth for MCP server in production
|
||||
|
||||
---
|
||||
|
||||
## Data Flow Patterns
|
||||
|
||||
### Pattern 1: Web App Data Flow
|
||||
|
||||
```
|
||||
User Browser
|
||||
↓ HTTP Request
|
||||
Next.js Route Handler
|
||||
↓
|
||||
Server Action or API Route
|
||||
↓
|
||||
Prisma Query (read/write)
|
||||
↓
|
||||
SQLite Database
|
||||
↓
|
||||
Prisma Response
|
||||
↓
|
||||
UI Update (React re-render)
|
||||
```
|
||||
|
||||
### Pattern 2: MCP Server Data Flow
|
||||
|
||||
```
|
||||
AI Assistant / N8N
|
||||
↓ MCP Protocol (stdio)
|
||||
MCP Server (index.js)
|
||||
↓ Tool Invocation
|
||||
Prisma Query (read/write)
|
||||
↓
|
||||
SQLite Database (shared file)
|
||||
↓
|
||||
Parse & Format Data
|
||||
↓ MCP Response (stdio)
|
||||
AI Assistant / N8N
|
||||
```
|
||||
|
||||
### Pattern 3: External Integrations
|
||||
|
||||
**Email Service:**
|
||||
```
|
||||
keep-notes → nodemailer → SMTP Server → User Email
|
||||
```
|
||||
|
||||
**AI Provider:**
|
||||
```
|
||||
keep-notes → Vercel AI SDK → OpenAI/Ollama API → AI Response
|
||||
```
|
||||
|
||||
**N8N Workflow:**
|
||||
```
|
||||
N8N → MCP Protocol → mcp-server → Prisma → DB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service Boundaries
|
||||
|
||||
### keep-notes Responsibilities
|
||||
|
||||
**User-Facing:**
|
||||
- Web UI (React components)
|
||||
- User authentication
|
||||
- Note management UI
|
||||
- Label management UI
|
||||
- Settings & admin panel
|
||||
|
||||
**Business Logic:**
|
||||
- Note CRUD operations
|
||||
- Label CRUD operations
|
||||
- Auto-tagging (AI)
|
||||
- Search functionality
|
||||
- Reminder scheduling
|
||||
|
||||
**Data Access:**
|
||||
- Prisma ORM
|
||||
- SQLite queries
|
||||
- File uploads
|
||||
- AI integrations
|
||||
|
||||
**External Communication:**
|
||||
- Email sending (nodemailer)
|
||||
- AI provider APIs (OpenAI, Ollama)
|
||||
- User authentication (NextAuth)
|
||||
|
||||
### mcp-server Responsibilities
|
||||
|
||||
**Protocol-Specific:**
|
||||
- MCP protocol implementation
|
||||
- Tool registration
|
||||
- Request/response handling
|
||||
- Error handling
|
||||
|
||||
**Data Access:**
|
||||
- Direct Prisma access
|
||||
- Note operations via MCP tools
|
||||
- Label queries
|
||||
- Search operations
|
||||
|
||||
**No Direct User Interface** - Protocol-only service
|
||||
|
||||
---
|
||||
|
||||
## Communication Protocols
|
||||
|
||||
### keep-nets → User
|
||||
|
||||
**Protocol:** HTTP/WebSocket
|
||||
**Format:** HTML/JSON
|
||||
**Authentication:** NextAuth session (cookies)
|
||||
|
||||
**Examples:**
|
||||
- Browser → `GET /` → Next.js SSR → HTML
|
||||
- Browser → `POST /api/notes` → JSON response
|
||||
- Browser → Server Action → Mutation → Revalidate
|
||||
|
||||
### keep-notes → External Services
|
||||
|
||||
**Email:**
|
||||
- Protocol: SMTP
|
||||
- Library: nodemailer
|
||||
- Purpose: Password reset, reminders
|
||||
|
||||
**AI Providers:**
|
||||
- Protocol: HTTP
|
||||
- Libraries: Vercel AI SDK
|
||||
- Providers: OpenAI API, Ollama (local)
|
||||
|
||||
### mcp-server → MCP Clients
|
||||
|
||||
**Protocol:** Model Context Protocol (MCP)
|
||||
**Transport:** Stdio (standard input/output)
|
||||
**Format:** JSON-RPC over stdio
|
||||
**Authentication:** None (currently)
|
||||
|
||||
**Clients:**
|
||||
- AI Assistants (ChatGPT, Claude)
|
||||
- N8N workflows
|
||||
- Custom automation scripts
|
||||
|
||||
---
|
||||
|
||||
## Deployment Topologies
|
||||
|
||||
### Current: Local Development
|
||||
|
||||
```
|
||||
Same Machine
|
||||
├── keep-notes (npm run dev)
|
||||
│ └── http://localhost:3000
|
||||
├── mcp-server (npm start)
|
||||
│ └── stdio://
|
||||
└── SQLite DB (shared file)
|
||||
└── keep-notes/prisma/dev.db
|
||||
```
|
||||
|
||||
### Production Option 1: Single Server
|
||||
|
||||
```
|
||||
Single Server (Docker/VM)
|
||||
├── keep-notes (Node.js process)
|
||||
├── mcp-server (Node.js process)
|
||||
└── SQLite DB (shared file)
|
||||
```
|
||||
|
||||
**Pros:** Simple, low latency
|
||||
**Cons:** Single point of failure
|
||||
|
||||
### Production Option 2: Microservices
|
||||
|
||||
```
|
||||
├── Web Server (keep-notes)
|
||||
│ └── Docker container
|
||||
├── MCP Server (mcp-server)
|
||||
│ └── Docker container
|
||||
└── Database Server (PostgreSQL)
|
||||
└── Connection pooling
|
||||
```
|
||||
|
||||
**Pros:** Scalable, resilient
|
||||
**Cons:** More complex, requires PostgreSQL migration
|
||||
|
||||
### Production Option 3: Cloud Native
|
||||
|
||||
```
|
||||
├── Vercel/Netlify (keep-notes frontend)
|
||||
├── Cloud Run/AWS Lambda (MCP server)
|
||||
└── Cloud SQL (PostgreSQL)
|
||||
```
|
||||
|
||||
**Pros:** Highly scalable, managed
|
||||
**Cons:** Vendor lock-in, higher cost
|
||||
|
||||
---
|
||||
|
||||
## API Contract Between Parts
|
||||
|
||||
### Currently: NO Direct HTTP API
|
||||
|
||||
**Integration Method:** Shared database
|
||||
**Communication:** Database-mediated
|
||||
**Synchronization:** Immediate (via shared DB)
|
||||
|
||||
**Future HTTP API (if needed):**
|
||||
|
||||
```
|
||||
keep-notes exposes internal API:
|
||||
GET /api/notes
|
||||
POST /api/notes
|
||||
etc.
|
||||
|
||||
mcp-server could call these:
|
||||
fetch('http://localhost:3000/api/notes')
|
||||
```
|
||||
|
||||
**Current Preference:** Database sharing (simpler, faster)
|
||||
|
||||
---
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
### User Authentication (keep-notes)
|
||||
|
||||
```
|
||||
1. User enters credentials in LoginForm
|
||||
2. POST /api/auth/signin
|
||||
3. NextAuth validates credentials
|
||||
4. Creates session in DB
|
||||
5. Sets HTTP-only cookie
|
||||
6. Redirects to dashboard
|
||||
```
|
||||
|
||||
### MCP Authentication (mcp-server)
|
||||
|
||||
```
|
||||
1. MCP client connects via stdio
|
||||
2. No authentication required
|
||||
3. Full database access granted
|
||||
4. Executes tools directly
|
||||
```
|
||||
|
||||
**Security Note:** This is acceptable for local/trusted environments but should be enhanced for production deployment.
|
||||
|
||||
---
|
||||
|
||||
## Data Synchronization
|
||||
|
||||
### Consistency Model
|
||||
|
||||
**Type:** Strong consistency via shared database
|
||||
**Mechanism:** SQLite ACID properties
|
||||
**Lag:** Zero (immediate)
|
||||
|
||||
**Conflict Resolution:**
|
||||
- Last write wins (SQLite default)
|
||||
- Application-level locking for critical operations
|
||||
|
||||
**Caching:**
|
||||
- React Cache (server components)
|
||||
- No explicit cache invalidation needed (DB is source of truth)
|
||||
|
||||
---
|
||||
|
||||
## Error Handling Across Parts
|
||||
|
||||
### keep-notes Errors
|
||||
|
||||
**Database Errors:**
|
||||
```typescript
|
||||
try {
|
||||
const note = await prisma.note.create({ ... })
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Failed to create note' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Action Errors:**
|
||||
- Form validation errors (Zod)
|
||||
- User-facing error messages
|
||||
- Graceful degradation
|
||||
|
||||
### mcp-server Errors
|
||||
|
||||
**Tool Execution Errors:**
|
||||
```javascript
|
||||
try {
|
||||
const note = await prisma.note.create({ ... })
|
||||
} catch (error) {
|
||||
throw new McpError(
|
||||
ErrorCode.InternalError,
|
||||
`Tool execution failed: ${error.message}`
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Error Types:**
|
||||
- `InvalidRequest`: Bad parameters
|
||||
- `InternalError`: DB/Server errors
|
||||
- `MethodNotFound`: Unknown tool
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
### Current State: Minimal
|
||||
|
||||
**keep-notes:**
|
||||
- Console logging
|
||||
- Playwright test reports
|
||||
|
||||
**mcp-server:**
|
||||
- Stderr logging
|
||||
- No structured logging
|
||||
|
||||
### Recommended Enhancements
|
||||
|
||||
**1. Distributed Tracing**
|
||||
- Trace requests across both parts
|
||||
- Correlation IDs
|
||||
- Performance monitoring
|
||||
|
||||
**2. Centralized Logging**
|
||||
- Structured JSON logs
|
||||
- Log aggregation (ELK, Loki)
|
||||
- Error tracking (Sentry)
|
||||
|
||||
**3. Metrics**
|
||||
- Request/response times
|
||||
- Database query performance
|
||||
- Tool execution statistics
|
||||
|
||||
**4. Health Checks**
|
||||
- `/health` endpoint for keep-notes
|
||||
- Health check for mcp-server
|
||||
- Database connectivity checks
|
||||
|
||||
---
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
### Current Limitations (SQLite)
|
||||
|
||||
**Concurrency:**
|
||||
- Multiple readers OK
|
||||
- Single writer (limitation)
|
||||
- Lock contention possible under load
|
||||
|
||||
**Capacity:**
|
||||
- File-based storage
|
||||
- Manual backups required
|
||||
- No automatic failover
|
||||
|
||||
### Scaling Strategies
|
||||
|
||||
**Horizontal Scaling:**
|
||||
- **Web App:** Multiple instances behind load balancer
|
||||
- **MCP Server:** Multiple instances (round-robin)
|
||||
- **Database:** Migrate to PostgreSQL
|
||||
|
||||
**Vertical Scaling:**
|
||||
- More CPU cores
|
||||
- More RAM (for caching)
|
||||
- Faster SSD (for I/O)
|
||||
|
||||
**Database Migration:**
|
||||
```prisma
|
||||
// Change datasource in schema.prisma
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// Update adapters
|
||||
// - @prisma/adapter-pg
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Architecture
|
||||
|
||||
### Current Security Posture
|
||||
|
||||
**keep-notes:**
|
||||
- ✅ NextAuth authentication
|
||||
- ✅ Password hashing (bcrypt)
|
||||
- ✅ Session management
|
||||
- ✅ Protected routes
|
||||
- ✅ CSRF protection (NextAuth)
|
||||
- ⚠️ No rate limiting
|
||||
- ⚠️ No brute force protection
|
||||
|
||||
**mcp-server:**
|
||||
- ✅ Input validation (schemas)
|
||||
- ✅ SQL injection protection (Prisma)
|
||||
- ❌ No authentication
|
||||
- ❌ No authorization
|
||||
- ❌ No rate limiting
|
||||
|
||||
### Security Recommendations
|
||||
|
||||
**Immediate:**
|
||||
1. Add API key authentication to mcp-server
|
||||
2. Restrict mcp-server to localhost/VPN
|
||||
3. Add rate limiting to both services
|
||||
4. Implement brute force protection
|
||||
|
||||
**Future:**
|
||||
1. HTTPS/TLS for all communications
|
||||
2. Input sanitization
|
||||
3. Output encoding
|
||||
4. Security headers (CSP, HSTS, etc.)
|
||||
5. Regular security audits
|
||||
|
||||
---
|
||||
|
||||
## Integration Testing
|
||||
|
||||
### Test Scenarios
|
||||
|
||||
**1. Data Consistency**
|
||||
- Create note in keep-notes → Verify visible in mcp-server
|
||||
- Update via mcp-server → Verify visible in keep-notes
|
||||
|
||||
**2. Concurrent Access**
|
||||
- Simultaneous writes to same note
|
||||
- Race condition testing
|
||||
- Lock behavior verification
|
||||
|
||||
**3. Error Propagation**
|
||||
- Database connection failures
|
||||
- Invalid data handling
|
||||
- Graceful degradation
|
||||
|
||||
### Testing Tools
|
||||
|
||||
**Integration Tests:**
|
||||
- Playwright (E2E for keep-notes)
|
||||
- Custom MCP client tests
|
||||
- Database state verification
|
||||
|
||||
**Load Tests:**
|
||||
- Concurrent tool execution
|
||||
- Database query performance
|
||||
- Memory leak detection
|
||||
|
||||
---
|
||||
|
||||
## Deployment Integration
|
||||
|
||||
### Docker Compose (Recommended)
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
keep-notes:
|
||||
build: ./keep-notes
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- db-data:/app/prisma
|
||||
environment:
|
||||
- DATABASE_URL=file:/app/prisma/dev.db
|
||||
|
||||
mcp-server:
|
||||
build: ./mcp-server
|
||||
volumes:
|
||||
- db-data:/app/db
|
||||
depends_on:
|
||||
- keep-notes
|
||||
environment:
|
||||
- DATABASE_URL=file:/app/db/dev.db
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Single command deployment
|
||||
- Shared volume for database
|
||||
- Environment configuration
|
||||
- Easy local development
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The Memento project uses a **database-mediated integration pattern**:
|
||||
|
||||
**Strengths:**
|
||||
- ✅ Simple architecture
|
||||
- ✅ Real-time data sync
|
||||
- ✅ No API complexity
|
||||
- ✅ Easy local development
|
||||
- ✅ Strong consistency
|
||||
|
||||
**Considerations:**
|
||||
- ⚠️ Single database file (scalability)
|
||||
- ⚠️ No authentication in MCP server
|
||||
- ⚠️ SQLite concurrency limits
|
||||
- ⚠️ Manual backup required
|
||||
|
||||
**Ideal For:**
|
||||
- Single-user or small team deployments
|
||||
- Local/self-hosted environments
|
||||
- Applications with modest write volume
|
||||
- Projects prioritizing simplicity
|
||||
|
||||
**Future Evolution:**
|
||||
- Add authentication layer
|
||||
- Migrate to PostgreSQL for scaling
|
||||
- Implement HTTP API between parts
|
||||
- Add caching layer (Redis)
|
||||
- Implement message queue for async ops
|
||||
1438
docs/monetization-analysis.md
Normal file
1438
docs/monetization-analysis.md
Normal file
File diff suppressed because it is too large
Load Diff
347
docs/project-overview.md
Normal file
347
docs/project-overview.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# Memento - Project Overview
|
||||
|
||||
## Project Summary
|
||||
|
||||
**Memento** is a Google Keep-inspired note-taking application with AI-powered features, semantic search, and MCP (Model Context Protocol) integration for workflow automation.
|
||||
|
||||
**Name:** Memento
|
||||
**Version:** 0.2.0
|
||||
**Type:** Multi-part Web Application + MCP Server
|
||||
**Repository Type:** Monorepo/Multi-part
|
||||
**License:** Open Source (to be published on GitHub)
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Aspect | Details |
|
||||
|--------|---------|
|
||||
| **Primary Language** | TypeScript (keep-notes), JavaScript (mcp-server) |
|
||||
| **Architecture** | Full-stack JAMstack (Next.js) + Microservice API (Express) |
|
||||
| **Database** | SQLite with Prisma ORM |
|
||||
| **Authentication** | NextAuth.js v5 with email/password |
|
||||
| **AI Integration** | Vercel AI SDK (OpenAI, Ollama) |
|
||||
| **State Management** | React Context + Custom Hooks |
|
||||
| **Testing** | Playwright (E2E) |
|
||||
| **Deployment** | Docker (planned) |
|
||||
|
||||
---
|
||||
|
||||
## Tech Stack Summary
|
||||
|
||||
### keep-notes (Web Application)
|
||||
|
||||
**Frontend:**
|
||||
- Next.js 16.1.1 (App Router)
|
||||
- React 19.2.3
|
||||
- TypeScript 5
|
||||
- Tailwind CSS 4
|
||||
- Radix UI (component library)
|
||||
- Lucide React (icons)
|
||||
|
||||
**Backend (Integrated):**
|
||||
- Next.js API Routes
|
||||
- Prisma 5.22.0 (ORM)
|
||||
- SQLite (better-sqlite3)
|
||||
|
||||
**Auth:**
|
||||
- NextAuth.js 5.0.0-beta.30
|
||||
- bcryptjs (password hashing)
|
||||
|
||||
**AI/LLM:**
|
||||
- Vercel AI SDK 6.0.23
|
||||
- OpenAI Provider
|
||||
- Ollama Provider (local models)
|
||||
|
||||
**Features:**
|
||||
- PWA (@ducanh2912/next-pwa)
|
||||
- Markdown (react-markdown)
|
||||
- Drag & Drop (@dnd-kit)
|
||||
- Grid Layout (Muuri, react-grid-layout)
|
||||
- Email (nodemailer)
|
||||
|
||||
### mcp-server (Backend API)
|
||||
|
||||
**Backend:**
|
||||
- Express.js 4.22.1
|
||||
- Node.js (ES modules)
|
||||
- Prisma 5.22.0 (ORM)
|
||||
|
||||
**Protocol:**
|
||||
- MCP SDK 1.0.4 (Model Context Protocol)
|
||||
- Stdio transport
|
||||
- Shared SQLite database
|
||||
|
||||
---
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
D:/dev_new_pc/Keep/
|
||||
├── keep-notes/ # Next.js web application
|
||||
│ ├── app/ # Next.js App Router
|
||||
│ │ ├── (auth)/ # Authentication routes
|
||||
│ │ ├── (main)/ # Main application routes
|
||||
│ │ ├── api/ # API endpoints
|
||||
│ │ ├── actions/ # Server actions
|
||||
│ │ ├── components/ # UI components
|
||||
│ │ ├── context/ # React contexts
|
||||
│ │ ├── hooks/ # Custom hooks
|
||||
│ │ └── lib/ # Utilities
|
||||
│ ├── components/ # Shared components
|
||||
│ ├── prisma/ # Database schema & migrations
|
||||
│ ├── tests/ # Playwright E2E tests
|
||||
│ └── public/ # Static assets
|
||||
│
|
||||
├── mcp-server/ # MCP integration server
|
||||
│ ├── index.js # Main MCP server (stdio)
|
||||
│ ├── index-sse.js # SSE variant
|
||||
│ └── prisma/ # Shared DB client
|
||||
│
|
||||
├── docs/ # Generated documentation
|
||||
├── _bmad/ # BMAD framework artifacts
|
||||
├── _bmad-output/ # BMAD workflow outputs
|
||||
│ ├── planning-artifacts/ # PRD, epics, architecture
|
||||
│ └── implementation-artifacts/ # Stories, sprint status
|
||||
│
|
||||
└── [Root files]
|
||||
├── README.md
|
||||
├── CHANGELOG.md
|
||||
├── MCP-GUIDE.md
|
||||
└── Various technical docs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Parts
|
||||
|
||||
### 1. keep-notes (Web App)
|
||||
- **Path:** `D:/dev_new_pc/Keep/keep-notes`
|
||||
- **Type:** Web Application (Next.js)
|
||||
- **Purpose:** Main user interface for note-taking
|
||||
- **Technology:** Next.js + React + TypeScript
|
||||
- **Entry Point:** `app/layout.tsx`
|
||||
|
||||
### 2. mcp-server (Backend)
|
||||
- **Path:** `D:/dev_new_pc/Keep/mcp-server`
|
||||
- **Type:** Backend API (Express)
|
||||
- **Purpose:** MCP protocol integration for N8N and AI assistants
|
||||
- **Technology:** Express + MCP SDK + Prisma
|
||||
- **Entry Point:** `index.js`
|
||||
|
||||
---
|
||||
|
||||
## Architecture Type
|
||||
|
||||
**Pattern:** Full-stack Monolith with Microservice Extension
|
||||
|
||||
**keep-notes:**
|
||||
- JAMstack architecture with Next.js App Router
|
||||
- Server-side rendering (SSR)
|
||||
- API routes integrated
|
||||
- Server Actions for mutations
|
||||
- Client-side state with React Context
|
||||
|
||||
**mcp-server:**
|
||||
- Separate microservice
|
||||
- Protocol-based API (MCP)
|
||||
- Shared database layer
|
||||
- Standalone execution
|
||||
|
||||
---
|
||||
|
||||
## Integration Between Parts
|
||||
|
||||
**Database Sharing:**
|
||||
- Both parts connect to the same SQLite database
|
||||
- `keep-notes/prisma/dev.db` is the single source of truth
|
||||
- MCP server reads/writes directly to this file
|
||||
|
||||
**Communication:**
|
||||
- Web app uses REST/Next.js API routes
|
||||
- MCP server exposes MCP protocol tools
|
||||
- No direct HTTP calls between parts
|
||||
- Communication is database-mediated
|
||||
|
||||
**Deployment:**
|
||||
- Can be deployed together or separately
|
||||
- Docker Compose can orchestrate both services
|
||||
- Environment variables control configuration
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### User Features
|
||||
- ✅ Rich text notes with markdown support
|
||||
- ✅ Checklist notes
|
||||
- ✅ Color-coded notes
|
||||
- ✅ Labeling/tagging system
|
||||
- ✅ Pinning and archiving
|
||||
- ✅ Image attachments
|
||||
- ✅ Reminders with recurrence
|
||||
- ✅ Drag-and-drop grid layout
|
||||
- ✅ Semantic search (vector embeddings)
|
||||
- ✅ AI-powered auto-tagging
|
||||
- ✅ User authentication (email/password)
|
||||
- ✅ User profile management
|
||||
- ✅ Admin panel
|
||||
|
||||
### Technical Features
|
||||
- ✅ PWA (Progressive Web App)
|
||||
- ✅ Responsive design
|
||||
- ✅ E2E testing (Playwright)
|
||||
- ✅ MCP integration (N8N workflows)
|
||||
- ✅ Multiple AI providers (OpenAI, Ollama)
|
||||
- ✅ Email notifications
|
||||
- ✅ Cron job support (reminders)
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 20+
|
||||
- npm or yarn
|
||||
- SQLite3 (included via better-sqlite3)
|
||||
|
||||
### Installation (Current)
|
||||
```bash
|
||||
# Install dependencies
|
||||
cd keep-notes
|
||||
npm install
|
||||
|
||||
# Generate Prisma client
|
||||
npm run db:generate
|
||||
|
||||
# Run development server
|
||||
npm run dev
|
||||
|
||||
# Access app at http://localhost:3000
|
||||
```
|
||||
|
||||
### MCP Server
|
||||
```bash
|
||||
cd mcp-server
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
**Current Status:**
|
||||
- Active development on `bmad-features` branch
|
||||
- Sprint status tracking implemented
|
||||
- 6 stories completed
|
||||
- PRD and Epics defined
|
||||
- Implementation readiness reviewed
|
||||
|
||||
**Next Steps:**
|
||||
1. Docker containerization
|
||||
2. Complete documentation
|
||||
3. Code review and cleanup
|
||||
4. Monetization strategy
|
||||
5. GitHub release preparation
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
**Generated Documentation:**
|
||||
- [API Contracts - keep-notes](./api-contracts-keep-notes.md)
|
||||
- [API Contracts - mcp-server](./api-contracts-mcp-server.md)
|
||||
- [Data Models](./data-models.md)
|
||||
- [Project Overview](./project-overview.md) (this file)
|
||||
|
||||
**Existing Documentation:**
|
||||
- [README.md](../README.md) - Main project README
|
||||
- [CHANGELOG.md](../CHANGELOG.md) - Version history
|
||||
- [COMPLETED-FEATURES.md](../COMPLETED-FEATURES.md) - Feature list
|
||||
- [MCP-GUIDE.md](../MCP-GUIDE.md) - MCP setup guide
|
||||
- [MCP-SSE-ANALYSIS.md](../MCP-SSE-ANALYSIS.md) - SSE implementation notes
|
||||
- [N8N-MCP-SETUP.md](../N8N-MCP-SETUP.md) - N8N integration guide
|
||||
|
||||
**Planning Artifacts:**
|
||||
- `_bmad-output/planning-artifacts/prd.md` - Product Requirements Document
|
||||
- `_bmad-output/planning-artifacts/epics.md` - Epic definitions
|
||||
- `_bmad-output/implementation-artifacts/` - User stories and sprint tracking
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
**E2E Tests:** Playwright
|
||||
```bash
|
||||
cd keep-notes
|
||||
npm test # Run all tests
|
||||
npm run test:ui # Run with UI
|
||||
npm run test:headed # Run in headed mode
|
||||
```
|
||||
|
||||
**Test Results:** `keep-notes/test-results/`
|
||||
**Playwright Report:** `keep-notes/playwright-report/`
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
**Environment Variables:** `.env` (root, keep-notes/, mcp-server/)
|
||||
|
||||
**Key Variables:**
|
||||
- `DATABASE_URL` - SQLite database path
|
||||
- `NEXTAUTH_SECRET` - Auth session secret
|
||||
- `NEXTAUTH_URL` - Application URL
|
||||
- Email configuration (SMTP)
|
||||
- AI provider API keys (OpenAI, Ollama)
|
||||
|
||||
**See:** `.env.example` (if available) or ask for setup details
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
**Current:** Manual deployment
|
||||
**Planned:** Docker Compose setup
|
||||
|
||||
**Target:** GitHub release with:
|
||||
- Docker images for both services
|
||||
- Docker Compose orchestration
|
||||
- Environment configuration guide
|
||||
- Deployment documentation
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
**Requested Features:**
|
||||
1. Complete Docker setup (docker-compose.yml)
|
||||
2. Comprehensive installation documentation
|
||||
3. Code review and test code cleanup
|
||||
4. "Pay me a coffee" monitization
|
||||
5. Business model analysis (open source monetization)
|
||||
6. MCP feature restoration and enhancement
|
||||
|
||||
**Technical Debt:**
|
||||
- Remove test/debug code before release
|
||||
- Improve error handling
|
||||
- Add comprehensive logging
|
||||
- Implement rate limiting
|
||||
- Add monitoring/observability
|
||||
|
||||
---
|
||||
|
||||
## License & Business Model
|
||||
|
||||
**License:** Open Source (to be determined - MIT/Apache/etc.)
|
||||
**Monetization:** Under evaluation
|
||||
**Status:** Preparing for GitHub public release
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
**Issues:** GitHub Issues (once published)
|
||||
**Documentation:** See `/docs` folder
|
||||
**Technical Guides:** Root-level markdown files
|
||||
237
docs/project-scan-report.json
Normal file
237
docs/project-scan-report.json
Normal file
@@ -0,0 +1,237 @@
|
||||
{
|
||||
"workflow_version": "1.2.0",
|
||||
"timestamps": {
|
||||
"started": "2026-01-09T12:00:00Z",
|
||||
"last_updated": "2026-01-09T14:00:00Z",
|
||||
"completed": "2026-01-09T14:00:00Z"
|
||||
},
|
||||
"mode": "initial_scan",
|
||||
"scan_level": "deep",
|
||||
"project_root": "D:/dev_new_pc/Keep",
|
||||
"output_folder": "D:/dev_new_pc/Keep/docs",
|
||||
"completed_steps": [
|
||||
{
|
||||
"step": "step_1",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-01-09T12:15:00Z",
|
||||
"summary": "Classified as multi-part with 2 parts: web (keep-notes) and backend (mcp-server)"
|
||||
},
|
||||
{
|
||||
"step": "step_2",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-01-09T12:20:00Z",
|
||||
"summary": "Found 11 existing docs: 3 READMEs, 8 MCP/technical docs"
|
||||
},
|
||||
{
|
||||
"step": "step_3",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-01-09T12:30:00Z",
|
||||
"summary": "Tech stack: Next.js 16 + React 19 + Prisma + SQLite (keep-notes), Express + MCP SDK (mcp-server)"
|
||||
},
|
||||
{
|
||||
"step": "step_4",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-01-09T13:30:00Z",
|
||||
"summary": "Conditional analysis complete: API contracts, data models generated for both parts"
|
||||
},
|
||||
{
|
||||
"step": "step_10",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-01-09T14:00:00Z",
|
||||
"summary": "Master index and project overview generated with incomplete doc markers"
|
||||
},
|
||||
{
|
||||
"step": "step_12",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-01-09T14:00:00Z",
|
||||
"summary": "Workflow complete - core documentation generated"
|
||||
}
|
||||
],
|
||||
"current_step": "completed",
|
||||
"findings": {
|
||||
"project_classification": {
|
||||
"repository_type": "multi-part",
|
||||
"total_parts": 2,
|
||||
"primary_tech": "Next.js + Express + Prisma"
|
||||
},
|
||||
"existing_docs_count": 11,
|
||||
"technology_stack": {
|
||||
"keep-notes": {
|
||||
"framework": "Next.js 16.1.1",
|
||||
"language": "TypeScript 5",
|
||||
"database": "SQLite via Prisma 5.22.0",
|
||||
"architecture_pattern": "Full-stack JAMstack with App Router"
|
||||
},
|
||||
"mcp-server": {
|
||||
"framework": "Express 4.22.1",
|
||||
"language": "JavaScript (ES modules)",
|
||||
"database": "Prisma 5.22.0 (shared)",
|
||||
"architecture_pattern": "Microservice API"
|
||||
}
|
||||
},
|
||||
"api_endpoints_discovered": {
|
||||
"keep-notes": 12,
|
||||
"mcp-server": 8
|
||||
},
|
||||
"components_inventory": {
|
||||
"keep-notes": "20+ UI components"
|
||||
}
|
||||
},
|
||||
"existing_docs": [
|
||||
{
|
||||
"file_path": "README.md",
|
||||
"type": "readme",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "CHANGELOG.md",
|
||||
"type": "changelog",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "COMPLETED-FEATURES.md",
|
||||
"type": "documentation",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "MCP-GUIDE.md",
|
||||
"type": "technical",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "MCP-LIGHTWEIGHT-TEST.md",
|
||||
"type": "technical",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "MCP-SSE-ANALYSIS.md",
|
||||
"type": "technical",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "N8N-MCP-SETUP.md",
|
||||
"type": "technical",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "N8N-TECH-NEWS.md",
|
||||
"type": "technical",
|
||||
"part": "root"
|
||||
},
|
||||
{
|
||||
"file_path": "keep-notes/README.md",
|
||||
"type": "readme",
|
||||
"part": "keep-notes"
|
||||
},
|
||||
{
|
||||
"file_path": "mcp-server/README.md",
|
||||
"type": "readme",
|
||||
"part": "mcp-server"
|
||||
},
|
||||
{
|
||||
"file_path": "mcp-server/N8N-CONFIG.md",
|
||||
"type": "technical",
|
||||
"part": "mcp-server"
|
||||
}
|
||||
],
|
||||
"project_types": [
|
||||
{
|
||||
"part_id": "keep-notes",
|
||||
"project_type_id": "web",
|
||||
"display_name": "Web Application (Next.js)"
|
||||
},
|
||||
{
|
||||
"part_id": "mcp-server",
|
||||
"project_type_id": "backend",
|
||||
"display_name": "Backend API (Express)"
|
||||
}
|
||||
],
|
||||
"project_parts": [
|
||||
{
|
||||
"part_id": "keep-notes",
|
||||
"part_name": "keep-notes",
|
||||
"root_path": "D:/dev_new_pc/Keep/keep-notes",
|
||||
"project_type_id": "web",
|
||||
"display_name": "Memento Web App",
|
||||
"indicators": [
|
||||
"package.json",
|
||||
"tsconfig.json",
|
||||
"next.config.ts",
|
||||
"playwright.config.ts",
|
||||
"auth.config.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"part_id": "mcp-server",
|
||||
"part_name": "mcp-server",
|
||||
"root_path": "D:/dev_new_pc/Keep/mcp-server",
|
||||
"project_type_id": "backend",
|
||||
"display_name": "MCP Server",
|
||||
"indicators": [
|
||||
"package.json",
|
||||
"index.js",
|
||||
"Express.js",
|
||||
"MCP SDK"
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs_generated": [
|
||||
"project-scan-report.json",
|
||||
"api-contracts-keep-notes.md",
|
||||
"api-contracts-mcp-server.md",
|
||||
"data-models.md",
|
||||
"project-overview.md",
|
||||
"index.md"
|
||||
],
|
||||
"incomplete_docs": [
|
||||
{
|
||||
"title": "Source Tree Analysis",
|
||||
"file_path": "./source-tree-analysis.md",
|
||||
"doc_type": "analysis",
|
||||
"reason": "Not generated in accelerated workflow"
|
||||
},
|
||||
{
|
||||
"title": "Component Inventory",
|
||||
"file_path": "./component-inventory.md",
|
||||
"doc_type": "inventory",
|
||||
"reason": "Not generated in accelerated workflow"
|
||||
},
|
||||
{
|
||||
"title": "Architecture - keep-notes",
|
||||
"file_path": "./architecture-keep-notes.md",
|
||||
"doc_type": "architecture",
|
||||
"part_id": "keep-notes",
|
||||
"reason": "Not generated in accelerated workflow"
|
||||
},
|
||||
{
|
||||
"title": "Architecture - mcp-server",
|
||||
"file_path": "./architecture-mcp-server.md",
|
||||
"doc_type": "architecture",
|
||||
"part_id": "mcp-server",
|
||||
"reason": "Not generated in accelerated workflow"
|
||||
},
|
||||
{
|
||||
"title": "Integration Architecture",
|
||||
"file_path": "./integration-architecture.md",
|
||||
"doc_type": "integration",
|
||||
"reason": "Not generated in accelerated workflow"
|
||||
},
|
||||
{
|
||||
"title": "Development Guide - keep-notes",
|
||||
"file_path": "./development-guide-keep-notes.md",
|
||||
"doc_type": "development",
|
||||
"part_id": "keep-notes",
|
||||
"reason": "Not generated in accelerated workflow"
|
||||
},
|
||||
{
|
||||
"title": "Deployment Guide",
|
||||
"file_path": "./deployment-guide.md",
|
||||
"doc_type": "deployment",
|
||||
"reason": "Not generated in accelerated workflow - PLANNED FOR FUTURE"
|
||||
}
|
||||
],
|
||||
"resume_instructions": "Workflow completed successfully",
|
||||
"verification_summary": "Deep scan completed with API contracts, data models, and project overview generated. 6 files written to /docs folder.",
|
||||
"open_risks": "Several documentation files marked incomplete (source tree, component inventory, architecture docs). Deployment guide not yet created.",
|
||||
"next_checks": "1. Review generated documentation for accuracy\n2. Generate incomplete docs if needed\n3. Create deployment guide with Docker setup\n4. Perform code review for test code cleanup"
|
||||
}
|
||||
378
docs/source-tree-analysis.md
Normal file
378
docs/source-tree-analysis.md
Normal file
@@ -0,0 +1,378 @@
|
||||
# Source Tree Analysis - Memento Project
|
||||
|
||||
## Overview
|
||||
|
||||
Complete directory structure analysis for the Memento note-taking application, a multi-part project consisting of a Next.js web application and an Express-based MCP server.
|
||||
|
||||
---
|
||||
|
||||
## Repository Root Structure
|
||||
|
||||
```
|
||||
D:/dev_new_pc/Keep/
|
||||
├── keep-notes/ # Main Next.js web application
|
||||
├── mcp-server/ # MCP integration server
|
||||
├── docs/ # Generated documentation
|
||||
├── _bmad/ # BMAD framework configuration
|
||||
├── _bmad-output/ # BMAD workflow artifacts
|
||||
│ ├── planning-artifacts/ # PRD, epics, architecture docs
|
||||
│ └── implementation-artifacts/ # Stories, sprint tracking
|
||||
├── node_modules/ # Root dependencies
|
||||
├── package-lock.json # Root lock file
|
||||
├── .git/ # Git repository
|
||||
├── .github/ # GitHub-specific files
|
||||
└── [Root level docs] # README.md, CHANGELOG.md, etc.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## keep-notes/ - Web Application
|
||||
|
||||
### Application Structure (Next.js App Router)
|
||||
|
||||
```
|
||||
keep-notes/
|
||||
├── app/ # Next.js App Router directory
|
||||
│ ├── (auth)/ # Auth route group
|
||||
│ │ ├── forgot-password/ # Password reset flow
|
||||
│ │ ├── login/ # Login page
|
||||
│ │ ├── register/ # Registration page
|
||||
│ │ └── reset-password/ # Reset password page
|
||||
│ ├── (main)/ # Main app route group
|
||||
│ │ ├── admin/ # Admin panel
|
||||
│ │ │ └── settings/ # Admin settings page
|
||||
│ │ ├── archive/ # Archived notes view
|
||||
│ │ ├── settings/ # User settings
|
||||
│ │ │ └── profile/ # User profile settings
|
||||
│ │ ├── page.tsx # Home/main page
|
||||
│ │ └── layout.tsx # Main layout
|
||||
│ ├── debug-search/ # Debug search interface
|
||||
│ ├── actions/ # Server actions
|
||||
│ │ ├── notes.ts # Note mutations
|
||||
│ │ ├── register.ts # User registration
|
||||
│ │ ├── scrape.ts # Web scraping
|
||||
│ │ └── [other actions]
|
||||
│ ├── api/ # API routes
|
||||
│ │ ├── admin/ # Admin endpoints
|
||||
│ │ │ ├── randomize-labels/ # Label randomization
|
||||
│ │ │ └── sync-labels/ # Label sync
|
||||
│ │ ├── ai/ # AI endpoints
|
||||
│ │ │ ├── tags/ # Auto-tagging
|
||||
│ │ │ └── test/ # AI testing
|
||||
│ │ ├── auth/ # Authentication
|
||||
│ │ │ └── [...nextauth]/ # NextAuth handler
|
||||
│ │ ├── cron/ # Scheduled jobs
|
||||
│ │ │ └── reminders/ # Reminder cron
|
||||
│ │ ├── debug/ # Debug endpoints
|
||||
│ │ │ └── search/ # Search debug
|
||||
│ │ ├── labels/ # Label CRUD
|
||||
│ │ │ └── [id]/ # Single label ops
|
||||
│ │ ├── notes/ # Note CRUD
|
||||
│ │ │ └── [id]/ # Single note ops
|
||||
│ │ └── upload/ # File uploads
|
||||
│ ├── globals.css # Global styles
|
||||
│ └── layout.tsx # Root layout
|
||||
│
|
||||
├── components/ # React components
|
||||
│ ├── ui/ # Radix UI components
|
||||
│ ├── editor-images.tsx # Image editor
|
||||
│ ├── ghost-tags.tsx # Tag display
|
||||
│ ├── header-wrapper.tsx # Header wrapper
|
||||
│ ├── header.tsx # Main header
|
||||
│ ├── label-badge.tsx # Label badges
|
||||
│ ├── label-filter.tsx # Label filtering
|
||||
│ ├── label-management-dialog.tsx # Label manager
|
||||
│ ├── label-manager.tsx # Label management
|
||||
│ ├── label-selector.tsx # Label selection
|
||||
│ ├── login-form.tsx # Login form
|
||||
│ ├── markdown-content.tsx # Markdown renderer
|
||||
│ ├── masonry-grid.tsx # Masonry layout
|
||||
│ ├── note-actions.tsx # Note actions menu
|
||||
│ ├── note-card.tsx # Note card component
|
||||
│ ├── note-checklist.tsx # Checklist component
|
||||
│ ├── note-editor.tsx # Note editor
|
||||
│ ├── note-images.tsx # Note images
|
||||
│ ├── note-input.tsx # Note input
|
||||
│ ├── register-form.tsx # Registration form
|
||||
│ ├── reminder-dialog.tsx # Reminder dialog
|
||||
│ ├── sidebar.tsx # Sidebar
|
||||
│ └── [20+ more components]
|
||||
│
|
||||
├── context/ # React Context providers
|
||||
│ └── [Context files]
|
||||
│
|
||||
├── hooks/ # Custom React hooks
|
||||
│ └── [Hook files]
|
||||
│
|
||||
├── lib/ # Utilities and libraries
|
||||
│ ├── ai/ # AI integration
|
||||
│ │ ├── providers/ # AI provider implementations
|
||||
│ │ │ ├── ollama.ts # Ollama provider
|
||||
│ │ │ └── [other providers]
|
||||
│ │ ├── factory.ts # Provider factory
|
||||
│ │ └── types.ts # AI types
|
||||
│ ├── prisma.ts # Prisma client
|
||||
│ ├── types.ts # TypeScript types
|
||||
│ └── utils.ts # Utility functions
|
||||
│
|
||||
├── prisma/ # Database schema and migrations
|
||||
│ ├── schema.prisma # Database schema
|
||||
│ ├── dev.db # SQLite database
|
||||
│ ├── client-generated/ # Generated Prisma client
|
||||
│ └── migrations/ # Database migrations
|
||||
│ ├── 20260104094125_init # Initial schema
|
||||
│ ├── 20260104102002_init # Additional init
|
||||
│ ├── 20260104102801_add_order # Note ordering
|
||||
│ ├── 20260104105155_add_images # Image support
|
||||
│ ├── 20260104140638_add_reminder # Reminders
|
||||
│ ├── 20260104144627_add_markdown # Markdown
|
||||
│ ├── 20260104145004_add_reminder_recurrence # Recurrence
|
||||
│ ├── 20260104145141_add_auth_models # Auth models
|
||||
│ ├── 20260104203746_add_labels_table # Labels
|
||||
│ ├── 20260106201929_add_reminder_done # Reminder done flag
|
||||
│ ├── 20260106213349_add_links # Links field
|
||||
│ ├── 20260106215037_add_auth # Additional auth
|
||||
│ └── 20260108220408_add_embedding # Vector embeddings
|
||||
│
|
||||
├── tests/ # Playwright E2E tests
|
||||
│ └── search-quality/ # Search quality tests
|
||||
│ └── search-quality.spec.ts
|
||||
│
|
||||
├── playwright-report/ # Playwright test reports
|
||||
│ └── index.html
|
||||
│
|
||||
├── test-results/ # Test execution results
|
||||
│ └── .last-run.json
|
||||
│
|
||||
├── public/ # Static assets
|
||||
│ ├── icons/ # Icon files
|
||||
│ ├── manifest.json # PWA manifest
|
||||
│ └── uploads/ # User uploads
|
||||
│ └── notes/ # Note attachments
|
||||
│
|
||||
├── scripts/ # Utility scripts
|
||||
│ ├── check-labels-userid.js # Label migration
|
||||
│ ├── debug-smtp.js # SMTP debug
|
||||
│ ├── diagnose-mail.js # Mail diagnosis
|
||||
│ ├── fix-labels-userid.js # Fix labels
|
||||
│ ├── promote-admin.js # Admin promotion
|
||||
│ └── [other scripts]
|
||||
│
|
||||
├── types/ # TypeScript type definitions
|
||||
│ └── [Type files]
|
||||
│
|
||||
├── auth.config.ts # NextAuth configuration
|
||||
├── auth.ts # Auth export
|
||||
├── next.config.ts # Next.js configuration
|
||||
├── package.json # Dependencies
|
||||
├── playwright.config.ts # Playwright E2E config
|
||||
├── postcss.config.mjs # PostCSS config
|
||||
├── tsconfig.json # TypeScript config
|
||||
└── [config files]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## mcp-server/ - MCP Integration Server
|
||||
|
||||
```
|
||||
mcp-server/
|
||||
├── index.js # Main MCP server (stdio transport)
|
||||
├── index-sse.js # SSE variant (Server-Sent Events)
|
||||
├── package.json # Dependencies
|
||||
├── README.md # Server documentation
|
||||
├── README-SSE.md # SSE documentation
|
||||
├── N8N-CONFIG.md # N8N configuration guide
|
||||
├── prisma/ # Shared Prisma client
|
||||
│ └── [Prisma client files]
|
||||
└── [server files]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Critical Directories Explained
|
||||
|
||||
### Application Routes (app/)
|
||||
- **(auth)/**: Authentication pages (login, register, password reset)
|
||||
- **(main)/**: Main application interface after auth
|
||||
- **actions/**: Server actions for mutations (notes, labels, auth)
|
||||
- **api/**: REST API endpoints
|
||||
|
||||
### Components (components/)
|
||||
- **ui/**: Reusable Radix UI primitives
|
||||
- **20+ domain components**: Note-related, label-related, auth-related
|
||||
|
||||
### State Management (context/ & hooks/)
|
||||
- React Context providers for global state
|
||||
- Custom hooks for component logic
|
||||
|
||||
### Database (prisma/)
|
||||
- Schema definition in schema.prisma
|
||||
- 13 migrations showing schema evolution
|
||||
- Generated client for type-safe DB access
|
||||
|
||||
### Testing (tests/ & playwright-report/)
|
||||
- E2E tests with Playwright
|
||||
- Test reports and results
|
||||
|
||||
---
|
||||
|
||||
## File Organization Patterns
|
||||
|
||||
**Route Groups:** Parentheses in folder names `(auth)`, `(main)` create route groups without affecting URL structure
|
||||
|
||||
**Dynamic Routes:** Square brackets `[id]`, `[...nextauth]` indicate dynamic routes
|
||||
|
||||
**API Routes:** `app/api/` follows RESTful conventions
|
||||
- Resource: `/api/notes`
|
||||
- Single item: `/api/notes/[id]`
|
||||
|
||||
**Server Actions:** `app/actions/` contain server-side mutations
|
||||
|
||||
**Component Organization:** Domain-driven (note-*, label-*, auth-*)
|
||||
|
||||
---
|
||||
|
||||
## Entry Points
|
||||
|
||||
**Web Application:**
|
||||
- Entry: `keep-notes/app/layout.tsx`
|
||||
- Home: `keep-notes/app/(main)/page.tsx`
|
||||
- Dev: `npm run dev` → http://localhost:3000
|
||||
|
||||
**MCP Server:**
|
||||
- Entry: `mcp-server/index.js`
|
||||
- SSE: `mcp-server/index-sse.js`
|
||||
- Run: `npm start`
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
**Database Sharing:**
|
||||
- Both parts connect to: `keep-notes/prisma/dev.db`
|
||||
- MCP server path: `../keep-notes/prisma/dev.db`
|
||||
|
||||
**Communication:**
|
||||
- No direct HTTP between parts
|
||||
- Database-mediated communication
|
||||
- Independent deployment possible
|
||||
|
||||
---
|
||||
|
||||
## Build Artifacts (Excluded from Analysis)
|
||||
|
||||
- `node_modules/` - Dependencies
|
||||
- `.next/` - Next.js build output
|
||||
- `prisma/client-generated/` - Generated Prisma client
|
||||
- `playwright-report/` - Test reports
|
||||
- `test-results/` - Test execution data
|
||||
|
||||
---
|
||||
|
||||
## Configuration Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `package.json` | Dependencies and scripts |
|
||||
| `tsconfig.json` | TypeScript configuration |
|
||||
| `next.config.ts` | Next.js framework config |
|
||||
| `playwright.config.ts` | E2E test configuration |
|
||||
| `auth.config.ts` | NextAuth authentication setup |
|
||||
| `postcss.config.mjs` | PostCSS/Tailwind config |
|
||||
| `schema.prisma` | Database schema definition |
|
||||
|
||||
---
|
||||
|
||||
## Migration History
|
||||
|
||||
The `prisma/migrations/` directory shows the evolution of the data model:
|
||||
|
||||
1. Initial schema (User, Note basics)
|
||||
2. Order field for drag-and-drop
|
||||
3. Image attachments
|
||||
4. Reminders
|
||||
5. Markdown support
|
||||
6. Reminder recurrence
|
||||
7. Authentication models (NextAuth)
|
||||
8. Labels table
|
||||
9. Reminder done flag
|
||||
10. Links field
|
||||
11. Additional auth fields
|
||||
12. Vector embeddings (AI search)
|
||||
|
||||
**Total Migrations:** 13
|
||||
**Latest:** Vector embeddings for semantic search
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
**Directory Access Patterns:**
|
||||
- Components import from: `@/components/*`, `@/lib/*`
|
||||
- Server actions: `@/app/actions/*`
|
||||
- API routes: `@/app/api/*`
|
||||
- Types: `@/lib/types`, `@/types`
|
||||
- Utils: `@/lib/utils`
|
||||
|
||||
**Import Aliases:**
|
||||
- `@/` → Project root (`keep-notes/`)
|
||||
|
||||
---
|
||||
|
||||
## Static Assets
|
||||
|
||||
**Public Files:** `keep-notes/public/`
|
||||
- PWA manifest: `manifest.json`
|
||||
- Icons: `icons/`
|
||||
- User uploads: `uploads/notes/`
|
||||
|
||||
**Note Images:** Base64 encoded in DB or uploaded to `public/uploads/notes/`
|
||||
|
||||
---
|
||||
|
||||
## Testing Structure
|
||||
|
||||
**Test Files:** `keep-notes/tests/`
|
||||
- Located at: `tests/search-quality/search-quality.spec.ts`
|
||||
- Config: `keep-notes/playwright.config.ts`
|
||||
|
||||
**Test Results:**
|
||||
- Execution: `keep-notes/test-results/.last-run.json`
|
||||
- Reports: `keep-notes/playwright-report/index.html`
|
||||
|
||||
---
|
||||
|
||||
## Key Observations
|
||||
|
||||
1. **Monorepo Structure:** Two distinct parts sharing database
|
||||
2. **Route Organization:** Clear separation between auth and main app
|
||||
3. **Component Count:** 20+ React components for notes, labels, auth
|
||||
4. **API Design:** RESTful with Next.js App Router conventions
|
||||
5. **Database Evolution:** 13 migrations showing feature growth
|
||||
6. **Testing:** E2E coverage with Playwright
|
||||
7. **State Management:** Context + hooks (no Redux/Zustand)
|
||||
8. **AI Integration:** Provider pattern in `lib/ai/providers/`
|
||||
9. **Authentication:** NextAuth v5 with Prisma adapter
|
||||
10. **PWA Support:** Progressive Web App capabilities
|
||||
|
||||
---
|
||||
|
||||
## Next Steps for Development
|
||||
|
||||
**For Feature Development:**
|
||||
1. Add new components in `components/`
|
||||
2. Create server actions in `app/actions/`
|
||||
3. Add API routes in `app/api/`
|
||||
4. Update Prisma schema and migrate
|
||||
|
||||
**For Docker Deployment:**
|
||||
1. Create Dockerfile for keep-notes
|
||||
2. Create Dockerfile for mcp-server
|
||||
3. Create docker-compose.yml
|
||||
4. Configure environment variables
|
||||
|
||||
**For Documentation:**
|
||||
1. Reference component-inventory.md for component details
|
||||
2. Reference api-contracts-*.md for API details
|
||||
3. Reference data-models.md for database schema
|
||||
Reference in New Issue
Block a user