This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Spanish flashcard app for vocabulary learning with spaced repetition (SM-2 algorithm). Uses Claude API for translations and context sentence generation.
- Sentence Analysis: Enter Spanish sentence/word, Claude detects phrases/idioms and individual words
- Verb Conjugations: Single verbs show present, preterite, and imperative conjugations with example sentences
- Multi-step Card Creation: Analyze sentence → select words/phrases/conjugations → preview cards (enable/disable) → save
- Disambiguating Translations: Synonyms get specific translations (e.g., "meter" = "to put (into enclosed space)" vs "poner" = "to put (place on surface)")
- Review Cards: SM-2 spaced repetition with cloze-style cards, randomized order, English-only hints
- Deck Organization: Group cards into decks, filter reviews by deck
- Export: Download deck as Anki-importable file
- Chat Assistant: WhatsApp conversation helper with natural language input, session persistence, and card creation flow
pnpm dev # Start development server (http://localhost:3000)
pnpm build # Production build
pnpm lint # Run ESLint
pnpm build-test # Build and test everythingpnpm sentence "Spanish sentence" # Analyze sentence, show cards
pnpm sentence --extra 2 "sentence" # Generate 2 extra example sentences per word
pnpm sentence --save "sentence" # Save cards to default deck
pnpm sentence --save --deck "Movies" "sent" # Save to specific deck
pnpm sentence -e 2 -s -d "Movies" "sent" # Combined: extra + save + deck
pnpm test:translate hola # Test single word translation
pnpm test:db # Test database operationsNote: After cloning, run cd node_modules/better-sqlite3 && npm run build-release to compile the native SQLite bindings.
- Next.js 16 (App Router) + TypeScript
- SQLite via better-sqlite3 (stored at
data/spanish.db) - Claude API (claude-sonnet-4-20250514) for AI translations
- Tailwind CSS v4 with dark mode support
All database queries and business logic MUST live in reusable lib/ functions. API routes (app/api/) should only handle HTTP concerns (parsing request, returning response) and delegate to lib/ functions. Never put DB queries, Claude API calls, prompt construction, or domain logic directly in route handlers.
- db.ts: Database layer. Exports
Card,Deck,ReviewSession,ChatSession,ChatExchangetypes plus CRUD functions. - claude-helpers.ts: Shared Claude API utilities. Exports
anthropicclient,callClaudeJson<T>(prompt, maxTokens?)for prompt→parsed JSON in one call,extractJsonFromResponse(text),getTextFromResponse(message),CLAUDE_MODELconstant, andDISAMBIGUATING_TRANSLATION_INSTRUCTIONSshared prompt fragment. - sentence-analyzer.ts:
analyzeSentence(sentence)analyzes a Spanish word or sentence via Claude, returning translations, phrases, words, and verb conjugations. - card-generation.ts:
generateCards(originalSentence, selectedWords, options?)generates cloze cards with optional extra sentences via Claude. Also exportsgenerateCloze()andgenerateExtraSentences(). - card-spacing.ts:
shuffleWithSpacing(cards)shuffles review cards while spacing related words apart. Also exportsshuffleArray()andgetBaseWord(). - chat-assistant.ts:
chatAssist(input, sessionId?)handles chat intent detection, Claude API call, and exchange persistence. Also exportsbuildConversationContext(exchanges)for formatting chat history. - vocab-extraction.ts:
extractVocab(question, title?)extracts Spanish vocabulary from natural language questions via Claude. - sm2.ts: SM-2 spaced repetition algorithm. Use
reviewCard(card, 'again'|'hard'|'good'|'easy')to calculate next review date. - claude.ts:
translateWord(spanishWord)returns translation + context sentence + cloze format via Claude API. - anki-export.ts:
exportToAnki({ deckId?, format, includeContext })generates Anki-importable text files.
Deck: id, name, created_at
Card: id, deck_id, spanish_word, translation, context_sentence, cloze_sentence,
interval, ease_factor, next_review, review_count, created_at
ChatSession: id, name, created_at, updated_at
ChatExchange: id, session_id, input, intent, response_main, response_json, created_at
POST /api/translate- Analyze sentence/word via Claude (returns phrases, words, conjugations)POST /api/generate-cards- Generate cloze cards for selected words with optional extra sentencesGET/POST/DELETE /api/cards- Card CRUDGET/POST/DELETE /api/decks- Deck CRUD (GET includes stats)POST /api/review- Submit card review (updates SM-2 scheduling)GET /api/export- Export deck to Anki formatPOST /api/chat-assist- Smart assistant with intent detection (english_to_spanish, spanish_to_english, lookup, validation)GET/POST/PATCH/DELETE /api/chat-sessions- Chat session CRUDGET/DELETE /api/chat-exchanges- Chat exchange listing and deletion
- Home (
/): List decks with Review/Add/Delete buttons, stats (due cards, total cards, deck count) - Add (
/add?deck=id&sentence=text): Multi-step flow - enter sentence → select words/phrases/conjugations with checkboxes → preview cards with enable/disable toggles → save to deck. Supportssentencequery param for pre-population from Chat. - Review (
/review?deck=id): Cloze cards with English hint only, randomized order, Again/Hard/Good/Easy buttons with interval preview - Deck (
/deck/[id]): Browse cards in a deck, delete individual cards - Export (
/export): Select deck, download Anki file - Chat (
/chat): WhatsApp conversation assistant - natural language input ("How do you say...", paste Spanish, "Is this correct:"), session management, conversation context, "Make Cards" links to /add flow
Uses custom regex for Spanish word boundaries (handles accented characters like "estiró"):
const regex = new RegExp(`(^|[\\s¿¡])${escaped}([\\s.,!?;:]|$)`, 'gi');The review page has fallback logic to create cloze on-the-fly for cards without {{c1::...}} markers.
- No try-catch: Let errors propagate naturally. Don't wrap code in try-catch blocks.
- Dark mode: Uses CSS custom properties with
prefers-color-scheme: darkmedia query - Lib-first: All DB queries, Claude API calls, prompt construction, and business logic belong in
lib/files. API routes should only parse requests and return responses — delegate everything else to lib functions. This keeps logic reusable across routes, CLI scripts, and tests.
ANTHROPIC_API_KEY=sk-ant-...
DATABASE_URL=postgres://... # Neon Postgres connection string
Git worktrees don't share .env.local with the main repo. You must symlink env vars immediately after creating a worktree, otherwise pnpm build and pnpm dev will fail with "No database connection string" errors:
ln -s /Users/danoved/Source/spanish-anki/.env.local <worktree-path>/.env.local