Keep/docs/architecture-keep-notes.md
sepehr 640fcb26f7 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
2026-01-09 22:13:49 +01:00

672 lines
16 KiB
Markdown

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