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

16 KiB

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:

{
  "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:

// 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:

// 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:

// 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:

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

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

cd keep-notes
npm install
npm run db:generate  # Generate Prisma client
npm run dev          # Start dev server

Database Migrations

npx prisma migrate dev
npx prisma migrate deploy  # Production

Type Checking

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.