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

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
technology_stack
language_rules
framework_rules
testing_rules
quality_rules
workflow_rules
anti_patterns
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 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:

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

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

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

'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 (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:

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

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