## 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>
18 KiB
| project_name | user_name | date | sections_completed | status | rule_count | optimized_for_llm | workflow_type | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Keep (Memento Phase 1 MVP AI) | Ramez | 2026-01-10 |
|
complete | 50 | true | 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:
{
"strict": true,
"target": "ES2017",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"paths": {
"@/*": ["./*"]
}
}
CRITICAL RULES:
- ✅ All files MUST be typed (no
anywithout explicit reason) - ✅ Use
interfacefor object shapes,typefor unions/primitives - ✅ Import from
@/alias (not relative paths like../) - ✅ Props MUST be typed with interfaces (PascalCase names)
Example:
// ✅ 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:
// 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:
// ✅ 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:
// 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:
// 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/catchwithconsole.error()logging - ✅ Throw
Errorobjects (not strings) - ✅ Return
{ success: true, data }or throw error
API Routes Pattern
CRITICAL: All API routes MUST follow this pattern:
// 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
ZodErrorseparately (400 status) - ✅ Log errors with
console.error() - ✅ NEVER expose stack traces to clients
Response Format:
// 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
// ✅ 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}Idformat:userId,noteId - ✅ Booleans: prefix
isfor flags:isPinned,isArchived - ✅ Timestamps: suffix
Atfor 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:
'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:
// 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 (notconsole.log) - ✅ Human-readable error messages (no technical jargon)
- ✅ NEVER expose stack traces to users
- ✅ NEVER expose internal error details
Import Rules
ALWAYS use @/ alias:
// ✅ 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:
// ✅ 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:
// 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:
// 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-testidattributes 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:
// ✅ 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:
- Title Suggestions - 3 suggestions after 50+ words
- Semantic Search - Hybrid keyword + vector search with RRF
- Paragraph Reformulation - Clarify, Shorten, Improve Style options
- Memory Echo - Daily proactive note connections (background job)
- AI Settings - Granular ON/OFF controls per feature
- 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:
- ✅ Read
_bmad-output/planning-artifacts/architecture.md - ✅ Check
project-context.mdfor specific rules - ✅ Follow naming patterns (camelCase, PascalCase, kebab-case)
- ✅ Use response format
{success, data, error} - ✅ Add
'use server'or'use client'directives - ✅ 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.mdfor 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:
- Technology Changes: Update when adding/removing dependencies
- Pattern Evolution: Add new patterns as they emerge
- Bug Prevention: Add rules when agents make common mistakes
- Optimization: Remove redundant or obvious rules periodically
- 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