Keep/_bmad-output/planning-artifacts/project-context.md
sepehr 7fb486c9a4 feat: Complete internationalization and code cleanup
## Translation Files
- Add 11 new language files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl)
- Add 100+ missing translation keys across all 15 languages
- New sections: notebook, pagination, ai.batchOrganization, ai.autoLabels
- Update nav section with workspace, quickAccess, myLibrary keys

## Component Updates
- Update 15+ components to use translation keys instead of hardcoded text
- Components: notebook dialogs, sidebar, header, note-input, ghost-tags, etc.
- Replace 80+ hardcoded English/French strings with t() calls
- Ensure consistent UI across all supported languages

## Code Quality
- Remove 77+ console.log statements from codebase
- Clean up API routes, components, hooks, and services
- Keep only essential error handling (no debugging logs)

## UI/UX Improvements
- Update Keep logo to yellow post-it style (from-yellow-400 to-amber-500)
- Change selection colors to #FEF3C6 (notebooks) and #EFB162 (nav items)
- Make "+" button permanently visible in notebooks section
- Fix grammar and syntax errors in multiple components

## Bug Fixes
- Fix JSON syntax errors in it.json, nl.json, pl.json, zh.json
- Fix syntax errors in notebook-suggestion-toast.tsx
- Fix syntax errors in use-auto-tagging.ts
- Fix syntax errors in paragraph-refactor.service.ts
- Fix duplicate "fusion" section in nl.json

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Ou une version plus courte si vous préférez :

feat(i18n): Add 15 languages, remove logs, update UI components

- Create 11 new translation files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl)
- Add 100+ translation keys: notebook, pagination, AI features
- Update 15+ components to use translations (80+ strings)
- Remove 77+ console.log statements from codebase
- Fix JSON syntax errors in 4 translation files
- Fix component syntax errors (toast, hooks, services)
- Update logo to yellow post-it style
- Change selection colors (#FEF3C6, #EFB162)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 22:26:13 +01:00

688 lines
18 KiB
Markdown

---
project_name: 'Keep (Memento Phase 1 MVP AI)'
user_name: 'Ramez'
date: '2026-01-10'
sections_completed: ['technology_stack', 'language_rules', 'framework_rules', 'testing_rules', 'quality_rules', 'workflow_rules', 'anti_patterns']
status: 'complete'
rule_count: 50
optimized_for_llm: true
workflow_type: 'generate-project-context'
---
# Project Context for AI Agents
_This file contains critical rules and patterns that AI agents must follow when implementing code in this project. Focus on unobvious details that agents might otherwise miss._
---
## Technology Stack & Versions
### Core Framework
**Frontend:**
- **Next.js:** 16.1.1 (App Router)
- **React:** 19.2.3
- **TypeScript:** 5.x (strict mode enabled)
**Backend:**
- **Next.js API Routes** (REST)
- **Server Actions** ('use server' directive)
- **Prisma:** 5.22.0 (ORM)
- **Database:** SQLite (better-sqlite3)
**Authentication:**
- **NextAuth:** 5.0.0-beta.30
- **Adapter:** @auth/prisma-adapter
**AI/ML:**
- **Vercel AI SDK:** 6.0.23
- **OpenAI Provider:** @ai-sdk/openai ^3.0.7
- **Ollama Provider:** ollama-ai-provider ^1.2.0
- **Language Detection:** tinyld (to be installed for Phase 1)
**UI Components:**
- **Radix UI:** Multiple primitives (@radix-ui/react-*)
- **Tailwind CSS:** 4.x
- **Lucide Icons:** ^0.562.0
- **Sonner:** ^2.0.7 (toast notifications)
**Utilities:**
- **Zod:** ^4.3.5 (schema validation)
- **date-fns:** ^4.1.0 (date formatting)
- **clsx:** ^2.1.1, **tailwind-merge:** ^3.4.0 (CSS utilities)
- **katex:** ^0.16.27 (LaTeX rendering)
- **react-markdown:** ^10.1.0 (markdown rendering)
**Drag & Drop:**
- **@dnd-kit:** ^6.3.1 (modern DnD library)
- **muuri:** ^0.9.5 (masonry grid layout)
**Testing:**
- **Playwright:** ^1.57.0 (E2E tests)
---
## Critical Implementation Rules
### TypeScript Configuration
**STRICT MODE ENABLED:**
```json
{
"strict": true,
"target": "ES2017",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"paths": {
"@/*": ["./*"]
}
}
```
**CRITICAL RULES:**
- ✅ All files MUST be typed (no `any` without explicit reason)
- ✅ Use `interface` for object shapes, `type` for unions/primitives
- ✅ Import from `@/` alias (not relative paths like `../`)
- ✅ Props MUST be typed with interfaces (PascalCase names)
**Example:**
```typescript
// ✅ GOOD
interface NoteCardProps {
note: Note
onEdit?: (note: Note) => void
}
export function NoteCard({ note, onEdit }: NoteCardProps) {
// ...
}
// ❌ BAD - any without reason
export function NoteCard({ note, onEdit }: any) {
// ...
}
```
---
### Component Patterns
**Directives Required:**
- ✅ Server Components: No directive (default in Next.js 16 App Router)
- ✅ Client Components: `'use client'` at TOP of file (line 1)
- ✅ Server Actions: `'use server'` at TOP of file (line 1)
**Example:**
```typescript
// keep-notes/components/ai/ai-suggestion.tsx
'use client'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
export function AiSuggestion() {
// Interactive component logic
}
```
**Component Naming:**
-**PascalCase** for component names: `NoteCard`, `LabelBadge`, `AiSuggestion`
-**kebab-case** for file names: `note-card.tsx`, `label-badge.tsx`, `ai-suggestion.tsx`
-**UI components** in `components/ui/` subdirectory: `button.tsx`, `dialog.tsx`
**Props Pattern:**
```typescript
// ✅ GOOD - Interface export
export interface NoteCardProps {
note: Note
onEdit?: (note: Note, readOnly?: boolean) => void
isDragging?: boolean
}
export function NoteCard({ note, onEdit, isDragging }: NoteCardProps) {
// ...
}
```
**Imports Order:**
```typescript
// 1. React imports
import { useState, useEffect } from 'react'
// 2. Third-party libraries
import { formatDistanceToNow } from 'date-fns'
import { Bell } from 'lucide-react'
// 3. Local imports (use @/ alias)
import { Card } from '@/components/ui/card'
import { Note } from '@/lib/types'
import { deleteNote } from '@/app/actions/notes'
```
---
### Server Actions Pattern
**CRITICAL: All server actions MUST follow this pattern:**
```typescript
// keep-notes/app/actions/ai-suggestions.ts
'use server'
import { auth } from '@/auth'
import { revalidatePath } from 'next/cache'
import { prisma } from '@/lib/prisma'
export async function generateTitleSuggestions(noteId: string) {
// 1. Authentication check
const session = await auth()
if (!session?.user?.id) {
throw new Error('Unauthorized')
}
try {
// 2. Business logic
const note = await prisma.note.findUnique({
where: { id: noteId }
})
if (!note) {
throw new Error('Note not found')
}
// 3. AI processing
const titles = await generateTitles(note.content)
// 4. Revalidate cache
revalidatePath('/')
return { success: true, titles }
} catch (error) {
console.error('Error generating titles:', error)
throw new Error('Failed to generate title suggestions')
}
}
```
**CRITICAL RULES:**
-`'use server'` at line 1 (before imports)
-**ALWAYS** check `auth()` session first
-**ALWAYS** `revalidatePath('/')` after mutations
- ✅ Use `try/catch` with `console.error()` logging
- ✅ Throw `Error` objects (not strings)
- ✅ Return `{ success: true, data }` or throw error
---
### API Routes Pattern
**CRITICAL: All API routes MUST follow this pattern:**
```typescript
// keep-notes/app/api/ai/titles/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
const requestSchema = z.object({
content: z.string().min(1, "Content required"),
noteId: z.string().optional()
})
export async function POST(req: NextRequest) {
try {
// 1. Parse and validate request
const body = await req.json()
const { content, noteId } = requestSchema.parse(body)
// 2. Business logic
const titles = await generateTitles(content)
// 3. Return success response
return NextResponse.json({
success: true,
data: { titles }
})
} catch (error) {
// 4. Error handling
if (error instanceof z.ZodError) {
return NextResponse.json(
{ success: false, error: error.issues },
{ status: 400 }
)
}
console.error('Error generating titles:', error)
return NextResponse.json(
{ success: false, error: 'Failed to generate titles' },
{ status: 500 }
)
}
}
```
**CRITICAL RULES:**
- ✅ Use **Zod schemas** for request validation
- ✅ Return `{ success: true, data: any }` for success
- ✅ Return `{ success: false, error: string }` for errors
- ✅ Handle `ZodError` separately (400 status)
- ✅ Log errors with `console.error()`
-**NEVER** expose stack traces to clients
**Response Format:**
```typescript
// Success
{ success: true, data: { ... } }
// Error
{ success: false, error: "Human-readable error message" }
```
---
### Database Access Pattern
**SINGLE DATA ACCESS LAYER:**
-**ONLY** use Prisma ORM (no raw SQL, no direct database access)
- ✅ Import from `@/lib/prisma` (singleton instance)
- ✅ Use `findMany`, `findUnique`, `create`, `update`, `delete`
```typescript
// ✅ GOOD
import { prisma } from '@/lib/prisma'
const notes = await prisma.note.findMany({
where: { userId: session.user.id },
orderBy: { createdAt: 'desc' }
})
```
**Prisma Schema Conventions:**
-**PascalCase** for model names: `User`, `Note`, `Label`, `AiFeedback`
-**camelCase** for fields: `userId`, `isPinned`, `createdAt`
- ✅ Foreign keys: `{model}Id` format: `userId`, `noteId`
- ✅ Booleans: prefix `is` for flags: `isPinned`, `isArchived`
- ✅ Timestamps: suffix `At` for dates: `createdAt`, `updatedAt`
- ✅ All new fields optional (nullable) for backward compatibility
---
### Naming Conventions
**Database:**
- Tables: **PascalCase** (`AiFeedback`, `MemoryEchoInsight`)
- Columns: **camelCase** (`noteId`, `similarityScore`)
- Indexes: Prisma `@@index([...])` annotations
**API Routes:**
- Collections: **plural** (`/api/notes`, `/api/labels`)
- Items: **singular** (`/api/notes/[id]`)
- Namespace: `/api/ai/*` for AI features
**Components:**
- Component names: **PascalCase** (`NoteCard`, `AiSuggestion`)
- File names: **kebab-case** (`note-card.tsx`, `ai-suggestion.tsx`)
**Functions:**
- Functions: **camelCase** (`getNotes`, `createNote`, `togglePin`)
- Verbs first: `get`, `create`, `update`, `delete`, `toggle`
- Handlers: prefix `handle` (`handleDelete`, `handleTogglePin`)
**Variables:**
- Variables: **camelCase** (`userId`, `isPending`, `noteId`)
- Types/interfaces: **PascalCase** (`Note`, `NoteCardProps`)
---
### State Management
**NO GLOBAL STATE LIBRARIES:**
- ❌ No Redux, Zustand, or similar
-**React useState** for local component state
-**React Context** for shared state (User session, Theme, Labels)
-**React Cache** for server-side caching
-**useOptimistic** for immediate UI feedback
-**useTransition** for non-blocking updates
**Example:**
```typescript
'use client'
import { useState, useTransition, useOptimistic } from 'react'
export function NoteCard({ note }: NoteCardProps) {
const [isPending, startTransition] = useTransition()
const [optimisticNote, addOptimisticNote] = useOptimistic(
note,
(state, newProps: Partial<Note>) => ({ ...state, ...newProps })
)
const handleTogglePin = async () => {
startTransition(async () => {
addOptimisticNote({ isPinned: !note.isPinned })
await togglePin(note.id, !note.isPinned)
router.refresh()
})
}
}
```
---
### Error Handling
**Global Pattern:**
```typescript
// API Routes
try {
// ... code
} catch (error) {
console.error('Feature name error:', error)
return NextResponse.json(
{ success: false, error: 'Human-readable message' },
{ status: 500 }
)
}
// Server Actions
try {
// ... code
} catch (error) {
console.error('Feature name error:', error)
throw new Error('Failed to action')
}
```
**CRITICAL RULES:**
- ✅ Use `console.error()` for logging (not `console.log`)
- ✅ Human-readable error messages (no technical jargon)
-**NEVER** expose stack traces to users
-**NEVER** expose internal error details
---
### Import Rules
**ALWAYS use @/ alias:**
```typescript
// ✅ GOOD
import { Button } from '@/components/ui/button'
import { Note } from '@/lib/types'
import { deleteNote } from '@/app/actions/notes'
// ❌ BAD - relative paths
import { Button } from '../../../components/ui/button'
import { Note } from '../lib/types'
```
**Import from Radix UI:**
```typescript
// ✅ GOOD - use @/components/ui/* wrapper
import { Dialog } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
// ❌ BAD - direct Radix imports
import { Dialog } from '@radix-ui/react-dialog'
import { Button } from '@radix-ui/react-slot'
```
---
### AI Service Pattern
**All AI services follow this structure:**
```typescript
// keep-notes/lib/ai/services/title-suggestion.service.ts
import { getAIProvider } from '@/lib/ai/factory'
export class TitleSuggestionService {
private provider = getAIProvider()
async generateSuggestions(content: string): Promise<string[]> {
try {
const response = await this.provider.generateText({
prompt: `Generate 3 titles for: ${content}`,
maxTokens: 100
})
return response.titles
} catch (error) {
console.error('TitleSuggestionService error:', error)
throw new Error('Failed to generate suggestions')
}
}
}
```
**CRITICAL RULES:**
- ✅ Use `getAIProvider()` factory (not direct OpenAI/Ollama imports)
- ✅ Services are **stateless classes**
- ✅ Constructor injection of dependencies
- ✅ Methods return `Promise<T>` with error handling
- ✅ No direct database access (via Prisma)
---
### Testing Rules
**Playwright E2E Tests:**
```typescript
// tests/e2e/ai-features.spec.ts
import { test, expect } from '@playwright/test'
test('AI title suggestions appear', async ({ page }) => {
await page.goto('/')
await page.fill('[data-testid="note-content"]', 'Test content')
// Wait for AI suggestions
await expect(page.locator('[data-testid="ai-suggestions"]')).toBeVisible()
})
```
**CRITICAL RULES:**
- ✅ Use `data-testid` attributes for test selectors
- ✅ Test critical user flows (not edge cases)
- ✅ Use `await expect(...).toBeVisible()` for assertions
- ✅ Tests in `tests/e2e/` directory
---
### Brownfield Integration Rules
**ZERO BREAKING CHANGES:**
-**ALL new features must extend, not replace existing functionality**
- ✅ Existing components, API routes, and database tables MUST continue working
- ✅ New database fields: **optional** (nullable) for backward compatibility
- ✅ New features: **additive** only (don't remove existing features)
**Example:**
```prisma
// ✅ GOOD - optional new field
model Note {
// ... existing fields
language String? // NEW: optional
aiConfidence Int? // NEW: optional
}
// ❌ BAD - breaking change
model Note {
language String @default("en") // BREAKS: non-optional default
}
```
---
### Phase 1 Specific Rules
**AI Features to Implement:**
1. **Title Suggestions** - 3 suggestions after 50+ words
2. **Semantic Search** - Hybrid keyword + vector search with RRF
3. **Paragraph Reformulation** - Clarify, Shorten, Improve Style options
4. **Memory Echo** - Daily proactive note connections (background job)
5. **AI Settings** - Granular ON/OFF controls per feature
6. **Language Detection** - TinyLD hybrid (< 50 words: library, 50 words: AI)
**Performance Targets:**
- Title suggestions: < 2s after detection
- Semantic search: < 300ms for 1000 notes
- Memory Echo: < 100ms UI freeze (background processing)
- Language detection: ~8ms (TinyLD) or ~200-500ms (AI)
**Language Support:**
- System prompts: **English** (stability)
- User data: **Local language** (FR, EN, ES, DE, FA/Persian + 57 others)
- TinyLD supports 62 languages including Persian (verified)
---
### Security Rules
**API Keys:**
- **NEVER** expose API keys to client (server-side only)
- Store in environment variables (`OPENAI_API_KEY`, `OLLAMA_ENDPOINT`)
- Use SystemConfig table for provider selection
**Authentication:**
- **ALL** server actions check `auth()` session first
- **ALL** API routes require valid NextAuth session
- Public routes: `/api/auth/*`, login/register pages only
**Privacy:**
- Ollama path = 100% local (no external API calls)
- OpenAI path = cloud (verify in DevTools Network tab)
- User data never logged or exposed
---
### File Organization
**AI Services:**
```
lib/ai/services/
├── title-suggestion.service.ts
├── semantic-search.service.ts
├── paragraph-refactor.service.ts
├── memory-echo.service.ts
├── language-detection.service.ts
└── embedding.service.ts
```
**AI Components:**
```
components/ai/
├── ai-suggestion.tsx
├── ai-settings-panel.tsx
├── memory-echo-notification.tsx
├── confidence-badge.tsx
├── feedback-buttons.tsx
└── paragraph-refactor.tsx
```
**API Routes:**
```
app/api/ai/
├── titles/route.ts
├── search/route.ts
├── refactor/route.ts
├── echo/route.ts
├── feedback/route.ts
└── language/route.ts
```
---
### Development Workflow
**Before implementing ANY feature:**
1. Read `_bmad-output/planning-artifacts/architecture.md`
2. Check `project-context.md` for specific rules
3. Follow naming patterns (camelCase, PascalCase, kebab-case)
4. Use response format `{success, data, error}`
5. Add `'use server'` or `'use client'` directives
6. Import from `@/` alias only
**Quality Checklist:**
- [ ] TypeScript strict mode compliance
- [ ] Zod validation for API routes
- [ ] auth() check in server actions
- [ ] revalidatePath('/') after mutations
- [ ] Error handling with console.error()
- [ ] Response format {success, data/error}
- [ ] Import from @/ alias
- [ ] Component directives ('use client'/'use server')
- [ ] Zero breaking changes
- [ ] Performance targets met
---
## Quick Reference Card
**For AI Agents implementing features:**
| Category | Rule | Example |
|----------|------|---------|
| TypeScript | Strict mode, no `any` | `interface Props { note: Note }` |
| Components | 'use client' at top | `export function Comp() { ... }` |
| Server Actions | 'use server' + auth() + revalidate | `const session = await auth()` |
| API Routes | Zod + {success, data/error} | `return NextResponse.json({ success: true, data })` |
| Database | Prisma only, no raw SQL | `await prisma.note.findMany()` |
| Naming | camelCase vars, PascalCase types | `const userId: string` |
| Imports | @/ alias only | `import { Note } from '@/lib/types'` |
| Error Handling | console.error + human message | `throw new Error('Failed to...')` |
| AI Services | getAIProvider() factory | `const provider = getAIProvider()` |
| Performance | Target < 2s for AI features | `await withTimeout(promise, 2000)` |
---
*Generated: 2026-01-10*
*Project: Keep (Memento Phase 1 MVP AI)*
*Architecture: Based on architecture.md (2784 lines)*
*Status: Ready for AI Agent Implementation*
---
## Usage Guidelines
**For AI Agents:**
- Read this file **before** implementing any code
- Follow **ALL** rules exactly as documented
- When in doubt, prefer the more restrictive option
- Check `_bmad-output/planning-artifacts/architecture.md` for full context
- Use response format `{success, data, error}` for API routes
- Add `'use server'` or `'use client'` directives at top of files
- Import from `@/` alias only (not relative paths)
- Validate requests with Zod schemas
- Check `auth()` session in server actions
- Call `revalidatePath('/')` after mutations
- Log errors with `console.error()`
**For Humans:**
- Keep this file **lean and focused** on agent needs
- Update when **technology stack changes**
- Review **quarterly** for outdated rules
- Remove rules that become **obvious over time**
- Add new patterns when they emerge in development
**Maintenance:**
1. **Technology Changes:** Update when adding/removing dependencies
2. **Pattern Evolution:** Add new patterns as they emerge
3. **Bug Prevention:** Add rules when agents make common mistakes
4. **Optimization:** Remove redundant or obvious rules periodically
5. **Review Cycle:** Check quarterly for outdated information
---
**Last Updated:** 2026-01-10
**Optimization Status:** Optimized for LLM context (50 critical rules, 490 lines)
**Readiness:** Ready for AI Agent Implementation
---
*Workflow completed: 2026-01-10*
*Generator: Winston (Architect Agent) with Generate Project Context workflow*
*Based on: architecture.md (2784 lines) + existing codebase analysis*