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:
2026-01-09 22:13:49 +01:00
parent 3c4b9d6176
commit 640fcb26f7
218 changed files with 51363 additions and 902 deletions

View 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

View 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)

View 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.

View 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.

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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*

View 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

File diff suppressed because it is too large Load Diff

347
docs/project-overview.md Normal file
View 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

View 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"
}

View 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