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:
671
docs/architecture-keep-notes.md
Normal file
671
docs/architecture-keep-notes.md
Normal file
@@ -0,0 +1,671 @@
|
||||
# Architecture - keep-notes (Memento Web App)
|
||||
|
||||
## Overview
|
||||
|
||||
Complete system architecture for the Memento web application, a Next.js 16 full-stack application using the App Router architecture pattern.
|
||||
|
||||
**Architecture Pattern:** Full-stack JAMstack with Server-Side Rendering (SSR)
|
||||
**Framework:** Next.js 16.1.1 (App Router)
|
||||
**Language:** TypeScript 5
|
||||
**Database:** SQLite via Prisma ORM
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Frontend
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| React | 19.2.3 | UI library |
|
||||
| Next.js | 16.1.1 | Full-stack framework |
|
||||
| TypeScript | 5.x | Type safety |
|
||||
| Tailwind CSS | 4.x | Styling |
|
||||
| Radix UI | Multiple | Component primitives |
|
||||
| Lucide React | 0.562.0 | Icons |
|
||||
|
||||
### Backend (Integrated)
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| Next.js API Routes | Built-in | REST API |
|
||||
| Prisma | 5.22.0 | ORM |
|
||||
| better-sqlite3 | 12.5.0 | SQLite driver |
|
||||
| @libsql/client | 0.15.15 | Alternative DB client |
|
||||
| NextAuth | 5.0.0-beta.30 | Authentication |
|
||||
|
||||
### AI/LLM
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| Vercel AI SDK | 6.0.23 | AI integration |
|
||||
| OpenAI Provider | 3.0.7 | GPT models |
|
||||
| Ollama Provider | 1.2.0 | Local models |
|
||||
|
||||
### Additional
|
||||
- @dnd-kit (drag and drop)
|
||||
- Muuri (masonry grid)
|
||||
- react-markdown (markdown rendering)
|
||||
- nodemailer (email)
|
||||
- bcryptjs (password hashing)
|
||||
- Zod (validation)
|
||||
- Playwright (testing)
|
||||
|
||||
---
|
||||
|
||||
## Architecture Pattern: JAMstack with App Router
|
||||
|
||||
### Request Flow
|
||||
|
||||
```
|
||||
User Browser
|
||||
↓
|
||||
Next.js App Router
|
||||
↓
|
||||
├─────────────────┬─────────────────┐
|
||||
│ │ │
|
||||
React Server API Routes Server Actions
|
||||
Components (REST) (Mutations)
|
||||
│ │ │
|
||||
└─────────────────┴─────────────────┘
|
||||
↓
|
||||
Prisma ORM
|
||||
↓
|
||||
SQLite Database
|
||||
```
|
||||
|
||||
### Rendering Strategy
|
||||
- **Server Components:** Default (faster initial load, SEO friendly)
|
||||
- **Client Components:** Interactive features (drag-drop, forms)
|
||||
- **Streaming:** Progressive rendering with Suspense
|
||||
- **ISR:** Not used (dynamic content)
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure (App Router)
|
||||
|
||||
```
|
||||
app/
|
||||
├── (auth)/ # Auth route group
|
||||
│ ├── layout.tsx # Auth layout
|
||||
│ ├── login/page.tsx # Login page
|
||||
│ ├── register/page.tsx # Register page
|
||||
│ └── [reset flows]/ # Password reset
|
||||
│
|
||||
├── (main)/ # Main app route group
|
||||
│ ├── layout.tsx # Main layout
|
||||
│ ├── page.tsx # Home/dashboard
|
||||
│ ├── admin/ # Admin panel
|
||||
│ ├── archive/ # Archived notes
|
||||
│ └── settings/ # User settings
|
||||
│
|
||||
├── actions/ # Server actions
|
||||
│ ├── notes.ts # Note mutations
|
||||
│ ├── register.ts # User registration
|
||||
│ └── [other actions] # Additional mutations
|
||||
│
|
||||
├── api/ # REST API
|
||||
│ ├── auth/[...nextauth]/ # NextAuth handler
|
||||
│ ├── notes/ # Note CRUD
|
||||
│ ├── labels/ # Label CRUD
|
||||
│ ├── ai/ # AI endpoints
|
||||
│ ├── admin/ # Admin endpoints
|
||||
│ └── [other routes] # Additional endpoints
|
||||
│
|
||||
├── globals.css # Global styles
|
||||
└── layout.tsx # Root layout
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Architecture
|
||||
|
||||
### Component Hierarchy
|
||||
|
||||
```
|
||||
layout.tsx (Root)
|
||||
├── HeaderWrapper
|
||||
│ ├── Header
|
||||
│ │ ├── Logo/Title
|
||||
│ │ └── UserNav
|
||||
│ └── [Auth providers]
|
||||
│
|
||||
├── Sidebar (collapsible)
|
||||
│ ├── Navigation
|
||||
│ └── Filters
|
||||
│
|
||||
└── Page Content
|
||||
└── MasonryGrid
|
||||
└── NoteCard[n]
|
||||
├── NoteEditor
|
||||
├── NoteChecklist
|
||||
├── NoteImages
|
||||
└── NoteActions
|
||||
```
|
||||
|
||||
### State Management
|
||||
|
||||
**No Global State Library** (Redux, Zustand, etc.)
|
||||
|
||||
**State Strategies:**
|
||||
1. **Server State:** Fetched from API, cached with React Cache
|
||||
2. **URL State:** Search params, route params
|
||||
3. **Form State:** Controlled components with useState
|
||||
4. **Context:** User session, theme preference
|
||||
5. **Server Actions:** Mutations that update DB
|
||||
|
||||
**Data Flow:**
|
||||
```
|
||||
User Action
|
||||
↓
|
||||
Server Action / API Call
|
||||
↓
|
||||
Prisma Mutation
|
||||
↓
|
||||
Database Update
|
||||
↓
|
||||
Revalidate / Refetch
|
||||
↓
|
||||
UI Update
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Architecture
|
||||
|
||||
### REST Endpoints
|
||||
|
||||
**Base URL:** `/api`
|
||||
|
||||
**Authentication:** NextAuth session (most endpoints)
|
||||
|
||||
**Endpoints:**
|
||||
|
||||
| Method | Endpoint | Purpose | Auth |
|
||||
|--------|----------|---------|------|
|
||||
| GET | `/api/notes` | List notes | No (currently) |
|
||||
| POST | `/api/notes` | Create note | No (currently) |
|
||||
| PUT | `/api/notes` | Update note | No (currently) |
|
||||
| DELETE | `/api/notes` | Delete note | No (currently) |
|
||||
| GET | `/api/labels` | List labels | Yes |
|
||||
| POST | `/api/labels` | Create label | Yes |
|
||||
| DELETE | `/api/labels/{id}` | Delete label | Yes |
|
||||
| GET/POST | `/api/auth/[...nextauth]` | Auth handler | No (this is auth) |
|
||||
| POST | `/api/ai/tags` | Auto-tagging | TBD |
|
||||
| POST | `/api/upload` | File upload | TBD |
|
||||
| POST | `/api/admin/*` | Admin ops | Yes (admin) |
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
{
|
||||
"success": true|false,
|
||||
"data": any,
|
||||
"error": string // only when success: false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Server Actions Architecture
|
||||
|
||||
**Location:** `app/actions/`
|
||||
|
||||
**Purpose:** Mutations that bypass REST, direct server-side execution
|
||||
|
||||
**Examples:**
|
||||
- `notes.ts`: Create, update, delete notes
|
||||
- `register.ts`: User registration
|
||||
- `scrape.ts`: Web scraping for link previews
|
||||
|
||||
**Benefits:**
|
||||
- Type-safe (from schema)
|
||||
- No API layer needed
|
||||
- Direct database access
|
||||
- Form validation (Zod)
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
// Client component
|
||||
import { createNote } from '@/app/actions/notes'
|
||||
|
||||
function NoteForm() {
|
||||
async function handleSubmit(data) {
|
||||
await createNote(data) // Server action
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database Architecture
|
||||
|
||||
### ORM: Prisma
|
||||
|
||||
**Schema Location:** `prisma/schema.prisma`
|
||||
**Migrations:** `prisma/migrations/` (13 migrations)
|
||||
**Database File:** `prisma/dev.db`
|
||||
|
||||
**Models:**
|
||||
- User (authentication, profile)
|
||||
- Account (OAuth providers)
|
||||
- Session (active sessions)
|
||||
- VerificationToken (email verification)
|
||||
- Note (core data model)
|
||||
- Label (tags/categories)
|
||||
- SystemConfig (key-value store)
|
||||
|
||||
**Connection:**
|
||||
```typescript
|
||||
// lib/prisma.ts
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import { PrismaLibSQL } from '@prisma/adapter-libsql'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
```
|
||||
|
||||
**Adapters:**
|
||||
- `@prisma/adapter-better-sqlite3` (primary - local dev)
|
||||
- `@prisma/adapter-libsql` (alternative - Turso cloud)
|
||||
|
||||
---
|
||||
|
||||
## Authentication Architecture
|
||||
|
||||
### NextAuth.js v5
|
||||
|
||||
**Configuration:** `auth.config.ts`
|
||||
**Implementation:** `auth.ts`
|
||||
|
||||
**Providers:**
|
||||
- Credentials (email/password)
|
||||
- OAuth options (Google, GitHub, etc.)
|
||||
|
||||
**Strategy:**
|
||||
1. User submits credentials
|
||||
2. NextAuth validates against database
|
||||
3. Session created in `Session` table
|
||||
4. JWT token issued
|
||||
5. Session stored in HTTP-only cookie
|
||||
|
||||
**Session Management:**
|
||||
- Server-side sessions in database
|
||||
- HTTP-only cookies for security
|
||||
- Automatic token refresh
|
||||
|
||||
**Password Security:**
|
||||
- bcryptjs hashing (cost factor: default)
|
||||
- Password reset flow with tokens
|
||||
- Reset token stored in `User.resetToken`
|
||||
|
||||
**User Roles:**
|
||||
- `USER` (default)
|
||||
- `ADMIN` (elevated permissions)
|
||||
- Role-based access control in API routes
|
||||
|
||||
---
|
||||
|
||||
## AI Integration Architecture
|
||||
|
||||
### Provider Pattern
|
||||
|
||||
**Location:** `lib/ai/providers/`
|
||||
|
||||
**Providers:**
|
||||
- OpenAI (`ollama.ts` is misnamed, should be `openai.ts` or separate)
|
||||
- Ollama (`ollama.ts` - local models)
|
||||
|
||||
**Factory Pattern:**
|
||||
```typescript
|
||||
// lib/ai/factory.ts
|
||||
export function createProvider(provider: string) {
|
||||
switch (provider) {
|
||||
case 'openai': return new OpenAIProvider()
|
||||
case 'ollama': return new OllamaProvider()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Auto-tagging (suggest labels for notes)
|
||||
- Semantic search (vector embeddings)
|
||||
- Content summarization (future)
|
||||
- Smart categorization (future)
|
||||
|
||||
**AI SDK Usage:**
|
||||
```typescript
|
||||
import { generateText } from 'ai'
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
|
||||
const response = await generateText({
|
||||
model: openai('gpt-4'),
|
||||
prompt: note.content
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Feature Architecture
|
||||
|
||||
### Note Management
|
||||
|
||||
**Data Flow:**
|
||||
1. User creates note → `NoteInput` component
|
||||
2. Server action → `app/actions/notes.ts`
|
||||
3. Prisma create → `Note` table
|
||||
4. Revalidate → UI updates
|
||||
5. Real-time → No WebSocket currently
|
||||
|
||||
**Search:**
|
||||
- Text search: SQL `LIKE` queries (case-insensitive)
|
||||
- Semantic search: Vector embeddings (JSON field)
|
||||
- Filtering: By labels, archived status, pinned status
|
||||
|
||||
**Organization:**
|
||||
- Pinning: `isPinned` boolean
|
||||
- Archiving: `isArchived` boolean
|
||||
- Ordering: `order` field (drag-drop)
|
||||
- Colors: `color` string
|
||||
- Size: `size` (small, medium, large)
|
||||
|
||||
### Label System
|
||||
|
||||
**Two Approaches:**
|
||||
1. **Label Table:** `Label` model with user ownership
|
||||
2. **Note Labels:** JSON array in `Note.labels`
|
||||
|
||||
**Current State:** Both exist (migration artifact)
|
||||
- `Label` table: User-managed labels
|
||||
- `Note.labels`: JSON array of label names
|
||||
|
||||
**Future:** Consolidate to one approach
|
||||
|
||||
### Reminder System
|
||||
|
||||
**Fields:**
|
||||
- `reminder`: DateTime for reminder
|
||||
- `isReminderDone`: Completed flag
|
||||
- `reminderRecurrence`: none, daily, weekly, monthly, custom
|
||||
- `reminderLocation`: Location-based (future)
|
||||
|
||||
**Cron Job:**
|
||||
- Route: `/api/cron/reminders`
|
||||
- Triggered by external cron service
|
||||
- Checks due reminders
|
||||
- Sends notifications (nodemailer)
|
||||
|
||||
### Image Handling
|
||||
|
||||
**Storage Options:**
|
||||
1. Base64 encoded in `Note.images` JSON array
|
||||
2. File uploads to `public/uploads/notes/`
|
||||
|
||||
**Current:** Both supported
|
||||
- Base64 for small images
|
||||
- File uploads for larger images
|
||||
|
||||
**Future:** Move to CDN (S3, Cloudinary, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Performance Architecture
|
||||
|
||||
### Server-Side Rendering (SSR)
|
||||
- Faster initial page load
|
||||
- SEO friendly
|
||||
- Progressive enhancement
|
||||
|
||||
### Code Splitting
|
||||
- Route-based splitting (automatic)
|
||||
- Dynamic imports for heavy components
|
||||
|
||||
### Data Fetching
|
||||
- React Cache for deduplication
|
||||
- Server Actions for mutations
|
||||
- Streaming responses
|
||||
|
||||
### Database Optimization
|
||||
- Indexed fields (isPinned, isArchived, order, reminder, userId)
|
||||
- Efficient queries with Prisma
|
||||
- Connection pooling (limited in SQLite)
|
||||
|
||||
---
|
||||
|
||||
## Security Architecture
|
||||
|
||||
### Authentication
|
||||
- NextAuth session management
|
||||
- HTTP-only cookies
|
||||
- CSRF protection (NextAuth built-in)
|
||||
- Password hashing (bcrypt)
|
||||
|
||||
### Authorization
|
||||
- Role-based access control (USER, ADMIN)
|
||||
- Session validation in API routes
|
||||
- Protected routes (middleware)
|
||||
|
||||
### Data Validation
|
||||
- Zod schemas for input validation
|
||||
- TypeScript for type safety
|
||||
- SQL injection prevention (Prisma)
|
||||
- XSS protection (React escaping)
|
||||
|
||||
### Future Security Enhancements
|
||||
- Rate limiting
|
||||
- CSRF tokens for forms
|
||||
- Content Security Policy (CSP)
|
||||
- HTTPS enforcement in production
|
||||
|
||||
---
|
||||
|
||||
## Deployment Architecture
|
||||
|
||||
### Current: Local Development
|
||||
```bash
|
||||
npm run dev # Next.js dev server
|
||||
# Runs on http://localhost:3000
|
||||
```
|
||||
|
||||
### Production Deployment (Planned)
|
||||
**Container:** Docker
|
||||
**Orchestration:** Docker Compose
|
||||
**Process:**
|
||||
1. Build Next.js app: `npm run build`
|
||||
2. Start production server: `npm start`
|
||||
3. Serve with Node.js or Docker
|
||||
|
||||
**Environment Variables:**
|
||||
- `DATABASE_URL`: SQLite file path
|
||||
- `NEXTAUTH_SECRET`: Session secret
|
||||
- `NEXTAUTH_URL`: Application URL
|
||||
- Email configuration (SMTP)
|
||||
- AI provider API keys
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
### Current: Basic
|
||||
- Console logging
|
||||
- Playwright test reports
|
||||
- Prisma query logging (development)
|
||||
|
||||
### Future Needs
|
||||
- Application monitoring (Sentry, LogRocket)
|
||||
- Error tracking
|
||||
- Performance monitoring
|
||||
- Database query analysis
|
||||
- User analytics
|
||||
|
||||
---
|
||||
|
||||
## Scalability Considerations
|
||||
|
||||
### Current Limitations (SQLite)
|
||||
- Single writer (concurrent writes limited)
|
||||
- File-based storage
|
||||
- No automatic replication
|
||||
- Manual backups needed
|
||||
|
||||
### Future Scaling Options
|
||||
1. **PostgreSQL:** Replace SQLite with Postgres
|
||||
2. **Connection Pooling:** PgBouncer
|
||||
3. **Caching:** Redis for sessions and cache
|
||||
4. **CDN:** CloudFlare, AWS CloudFront
|
||||
5. **Object Storage:** S3 for images
|
||||
6. **Load Balancing:** Multiple app instances
|
||||
|
||||
---
|
||||
|
||||
## Testing Architecture
|
||||
|
||||
### E2E Testing: Playwright
|
||||
**Location:** `tests/search-quality.spec.ts`
|
||||
**Coverage:** Search functionality
|
||||
**Commands:**
|
||||
- `npm test` - Run all tests
|
||||
- `npm run test:ui` - UI mode
|
||||
- `npm run test:headed` - Headed mode
|
||||
|
||||
### Test Reports
|
||||
**Location:** `playwright-report/index.html`
|
||||
**Results:** `test-results/.last-run.json`
|
||||
|
||||
---
|
||||
|
||||
## Web Vitals & Performance
|
||||
|
||||
### Core Web Vitals
|
||||
- **LCP (Largest Contentful Paint):** Target < 2.5s
|
||||
- **FID (First Input Delay):** Target < 100ms
|
||||
- **CLS (Cumulative Layout Shift):** Target < 0.1
|
||||
|
||||
### Optimizations
|
||||
- Next.js Image optimization
|
||||
- Code splitting
|
||||
- Server components (reduce JS bundle)
|
||||
- Streaming responses
|
||||
- Lazy loading images
|
||||
|
||||
---
|
||||
|
||||
## PWA Architecture
|
||||
|
||||
### Progressive Web App Features
|
||||
**Package:** `@ducanh2912/next-pwa`
|
||||
**Manifest:** `public/manifest.json`
|
||||
|
||||
**Features:**
|
||||
- Offline support (future)
|
||||
- Install as app (future)
|
||||
- Push notifications (future)
|
||||
- App shortcuts (future)
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### MCP Server
|
||||
**Connection:** Database-mediated (shared SQLite)
|
||||
**Location:** `../mcp-server/index.js`
|
||||
**Protocol:** MCP (Model Context Protocol)
|
||||
|
||||
### Third-Party Services
|
||||
- **Email:** nodemailer (SMTP)
|
||||
- **AI:** OpenAI API, Ollama (local)
|
||||
- **Future:** N8N workflows via MCP
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
cd keep-notes
|
||||
npm install
|
||||
npm run db:generate # Generate Prisma client
|
||||
npm run dev # Start dev server
|
||||
```
|
||||
|
||||
### Database Migrations
|
||||
```bash
|
||||
npx prisma migrate dev
|
||||
npx prisma migrate deploy # Production
|
||||
```
|
||||
|
||||
### Type Checking
|
||||
```bash
|
||||
npx tsc --noEmit # Type check only
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `next.config.ts` | Next.js configuration |
|
||||
| `tsconfig.json` | TypeScript configuration |
|
||||
| `tailwind.config.ts` | Tailwind CSS (if present) |
|
||||
| `playwright.config.ts` | E2E test configuration |
|
||||
| `auth.config.ts` | NextAuth configuration |
|
||||
| `.env` | Environment variables |
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decision Records
|
||||
|
||||
### Why Next.js App Router?
|
||||
- Modern React features (Server Components)
|
||||
- Built-in API routes
|
||||
- File-based routing
|
||||
- Excellent performance
|
||||
- Strong community
|
||||
|
||||
### Why Prisma?
|
||||
- Type-safe database access
|
||||
- Excellent migration system
|
||||
- Multiple database support
|
||||
- Great developer experience
|
||||
|
||||
### Why SQLite?
|
||||
- Zero configuration
|
||||
- Portable (single file)
|
||||
- Sufficient for single-user/small teams
|
||||
- Easy local development
|
||||
|
||||
### Why No Redux/Zustand?
|
||||
- Server Components reduce need for global state
|
||||
- React Context sufficient for app state
|
||||
- Server Actions simplify mutations
|
||||
- Reduced bundle size
|
||||
|
||||
---
|
||||
|
||||
## Future Architecture Enhancements
|
||||
|
||||
### Short Term
|
||||
1. Add Redis for caching
|
||||
2. Implement rate limiting
|
||||
3. Add error boundaries
|
||||
4. Improve error logging
|
||||
5. Add request tracing
|
||||
|
||||
### Long Term
|
||||
1. Migrate to PostgreSQL
|
||||
2. Add read replicas
|
||||
3. Implement event sourcing
|
||||
4. Add real-time features (WebSocket)
|
||||
5. Microservices architecture
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The keep-notes application uses a modern JAMstack architecture with:
|
||||
- **Next.js 16** for full-stack development
|
||||
- **App Router** for routing and server components
|
||||
- **Prisma** for type-safe database access
|
||||
- **SQLite** for embedded database
|
||||
- **NextAuth** for authentication
|
||||
- **Radix UI** for accessible components
|
||||
- **Vercel AI SDK** for AI features
|
||||
- **Playwright** for E2E testing
|
||||
|
||||
This architecture provides a solid foundation for the Memento note-taking application with room for scaling and enhancement.
|
||||
Reference in New Issue
Block a user