Commit graph

86 commits

Author SHA1 Message Date
lila
bc38137a12 feat: add production deployment config
- Add docker-compose.prod.yml and Caddyfile for Caddy reverse proxy
- Add production stages to frontend Dockerfile (nginx for static files)
- Fix monorepo package exports for production builds (dist/src paths)
- Add CORS_ORIGIN env var for cross-origin config
- Add Better Auth baseURL, cookie domain, and trusted origins from env
- Use VITE_API_URL for API calls in auth-client and play route
- Add credentials: include for cross-origin fetch requests
- Remove unused users table from schema
2026-04-14 11:38:40 +02:00
lila
3f7bc4111e chore: rename project from glossa to lila
- Update all package names from @glossa/* to @lila/*
- Update all imports, container names, volume names
- Update documentation references
- Recreate database with new credentials
2026-04-13 10:00:52 +02:00
lila
1699f78f0b updating current state, phase 3 is done 2026-04-12 13:41:09 +02:00
lila
a3685a9e68 feat(api): add auth middleware to protect game endpoints
- Add requireAuth middleware using Better Auth session validation
- Apply to all game routes (start, answer)
- Unauthenticated requests return 401
2026-04-12 13:38:32 +02:00
lila
91a3112d8b feat(api): integrate Better Auth with Drizzle adapter and social providers
- Add Better Auth config with Google + GitHub social providers
- Mount auth handler on /api/auth/* in Express
- Generate and migrate auth tables (user, session, account, verification)
- Deduplicate term_glosses data for tighter unique constraint
- Drop legacy users table
2026-04-12 11:46:38 +02:00
lila
cbe638b1af docs: update auth references from OpenAuth to Better Auth 2026-04-12 10:18:16 +02:00
lila
2058d0d542 updating docs 2026-04-12 09:35:14 +02:00
lila
047196c973 updating documentation, formatting 2026-04-12 09:28:35 +02:00
lila
e320f43d8e test(api): add unit and integration tests for game service and endpoints
- Unit tests for createGameSession and evaluateAnswer (14 tests)
- Endpoint tests for POST /game/start and /game/answer via supertest (8 tests)
- Mock @glossa/db — no real database dependency
2026-04-12 09:04:41 +02:00
lila
48457936e8 feat(api): add global error handler with typed error classes
- Add AppError base class, ValidationError (400), NotFoundError (404)
- Add central error middleware in app.ts
- Remove inline safeParse error handling from controllers
- Replace plain Error throws with NotFoundError in gameService
2026-04-12 08:48:43 +02:00
lila
dd6c2b0118 updating documentation 2026-04-11 21:32:13 +02:00
lila
bc7977463e feat(web): add game settings screen and submit confirmation
- Add GameSetup component with Duolingo-style button selectors for
  language pair, POS, difficulty, and rounds
- Language swap: selecting the same language for source and target
  automatically swaps them instead of allowing duplicates
- Add selection-before-submission flow: user clicks an option to
  highlight it, then confirms with a Submit button to prevent misclicks
- Add selected state to OptionButton (purple ring highlight)
- Play Again on score screen returns to settings instead of
  auto-restarting with the same configuration
- Remove hardcoded GAME_SETTINGS, game configuration is now user-driven
2026-04-11 21:18:35 +02:00
lila
b7b1cd383f refactoring ui into separate components, updating ui, adding color scheme 2026-04-11 20:53:10 +02:00
lila
ea33b7fcc8 feat(web): add minimal playable quiz at /play
- Add Vite proxy for /api → localhost:3000 (no CORS needed in dev)
- Create /play route with hardcoded game settings (en→it, nouns, easy)
- Three-phase state machine: loading → playing → finished
- Show prompt, optional gloss, and 4 answer buttons per question
- Submit answers to /api/v1/game/answer, show correct/wrong feedback
- Manual Next button to advance after answering
- Score screen on completion
- Add selectedOptionId to AnswerResult schema (discovered during
  frontend work that the result needs to be self-contained for
  rendering feedback without separate client state)

Intentionally unstyled — component extraction and polish come next.
2026-04-11 12:56:03 +02:00
lila
075a691849 feat(api): add answer evaluation endpoint
Complete the game answer flow:

- Add evaluateAnswer service function: looks up the session in the
  GameSessionStore, compares the submitted optionId against the stored
  correct answer, returns an AnswerResult.
- Add submitAnswer controller with safeParse validation and error
  handling (session/question not found → 404).
- Add POST /api/v1/game/answer route.
- Fix createGameSession: was missing the answerKey tracking and the
  gameSessionStore.create() call, so sessions were never persisted.

The full singleplayer game loop now works end-to-end:
POST /game/start → GameSession, POST /game/answer → AnswerResult.
2026-04-11 12:12:54 +02:00
lila
0755c57439 feat(api): wire GameSessionStore into createGameSession
The service now tracks the correct optionId for each question and
stores the answer key in the GameSessionStore after building the
session. The client response is unchanged — the store is invisible
to the outside.

- Build answerKey (questionId → correctOptionId) during question
  assembly by finding the correct answer's position after shuffle
- Store the answer key via gameSessionStore.create() before returning
- Add excludeText parameter to getDistractors to prevent a distractor
  from having identical text to the correct answer (different term,
  same translation). Solved at the query level, not with post-filtering.
- Module-level InMemoryGameSessionStore singleton in the service
2026-04-11 11:52:38 +02:00
lila
1940ff3965 feat(api): add in-memory GameSessionStore
Add the session storage infrastructure for tracking correct answers
during a game. Designed for easy swap to Valkey in Phase 4.

- GameSessionStore interface with create/get/delete methods, all async
  to match the eventual Valkey implementation
- InMemoryGameSessionStore backed by a Map
- GameSessionData holds only the answer key (questionId → correctOptionId)
- Also fix root build script to build packages in dependency order
2026-04-11 11:42:13 +02:00
lila
f53ac618bb feat(api): assemble full GameSession with shuffled answer options
Extend the game flow from raw term rows to a complete GameSession
matching the shared schema:

- Add getDistractors model query: fetches N same-POS, same-difficulty,
  same-target-language terms excluding a given termId. Returns bare
  strings since distractors only need their display text.
- Fix getGameTerms select clause to use the neutral field names
  (sourceText, targetText, sourceGloss) that the type already declared.
- Rename gameService entry point to createGameSession; signature now
  takes a GameRequest and returns a GameSession.
- Per question: fetch 3 distractors, combine with the correct answer,
  shuffle (Fisher-Yates), assign optionIds 0-3 by post-shuffle index,
  and assemble into a GameQuestion with a fresh UUID.
- Wrap the questions in a GameSession with its own UUID.
- Run per-question distractor fetches in parallel via Promise.all.

Known gap: the correct option is not yet remembered server-side, so
/game/answer cannot evaluate submissions. SessionStore lands next.
2026-04-10 21:44:36 +02:00
lila
0cf6a852b2 adjusting output schema 2026-04-10 21:44:09 +02:00
lila
ce6dc4fa32 feat(shared): add quiz session Zod schemas
Add the shared schemas for the quiz request/response cycle, defining
the contract between the API and the frontend.

- Reorganise packages/shared: move schemas into a schemas/ subdirectory
  grouped by domain. Delete the old flat schema.ts.
- Add AnswerOption, GameQuestion, GameSession, AnswerSubmission, and
  AnswerResult alongside the existing GameRequest.
- optionId is an integer 0-3 (positional, shuffled at session-build
  time so position carries no information).
- questionId and sessionId are UUIDs (globally unique, opaque, natural
  keys for Valkey storage later).
- gloss is  rather than optional, for a predictable
  shape on the frontend.
- options array enforced to exactly 4 elements at the schema level.
2026-04-10 21:43:53 +02:00
lila
2bcf9d7a97 formatting 2026-04-10 20:20:09 +02:00
lila
b3b32167c9 formatting 2026-04-10 20:09:46 +02:00
lila
b59fac493d feat(api): implement game terms query with double join
- Add double join on translations for source/target languages
- Left join term_glosses for optional source-language glosses
- Filter difficulty on target side only (intentionally asymmetric:
  a word's difficulty can differ between languages, and what matters
  is the difficulty of the word being learned)
- Return neutral field names (sourceText, targetText, sourceGloss)
  instead of quiz semantics; service layer maps to prompt/answer
- Tighten term_glosses unique constraint to (term_id, language_code)
  to prevent the left join from multiplying question rows
- Add TODO for ORDER BY RANDOM() scaling post-MVP
2026-04-10 18:02:03 +02:00
lila
9fc3ba375a feat: scaffold quiz API vertical slice
- Add GameRequestSchema and derived types to packages/shared
- Add SupportedLanguageCode, SupportedPos, DifficultyLevel type exports
- Add getGameTerms() model to packages/db with pos/language/difficulty/limit filters
- Add prepareGameQuestions() service skeleton in apps/api
- Add createGame controller with Zod safeParse validation
- Wire POST /api/v1/game/start route
- Add scripts/gametest/test-game.ts for manual end-to-end testing
2026-04-09 13:47:01 +02:00
lila
13cc709b09 adding script to check cefr coverage between json files and database, adding script to write cefr levels from json to db 2026-04-09 10:25:20 +02:00
lila
3374bd8b20 feat(scripts): add Italian CEFR data pipeline
- Add extractors for Italian sources: it_m3.xls and italian.json
- Add comparison script (compare-italian.py) to report source overlaps and conflicts
- Add merge script (merge-italian-json.py) with priority order ['italian', 'it_m3']
- Output authoritative dataset to datafiles/italian-merged.json
- Update README to document both English and Italian pipelines
2026-04-08 18:32:03 +02:00
lila
59152950d6 extraction, comparison and merging scripts for english are done, final english.json exists 2026-04-08 17:50:25 +02:00
lila
3596f76492 extraction datafiles with cefr annotations 2026-04-08 13:09:47 +02:00
lila
e79fa6922b updating schema 2026-04-07 01:03:22 +02:00
lila
0cb9fe1485 adding datafiles + updating documentation 2026-04-07 00:00:58 +02:00
lila
60cf48ef97 updating documentation 2026-04-06 17:01:34 +02:00
lila
570dbff25e updating seeding script 2026-04-06 17:01:17 +02:00
lila
aa1a332226 removing files 2026-04-06 17:01:04 +02:00
lila
6cb0068d1a adding datafiles for all english and italian nousn and verbs 2026-04-05 19:35:52 +02:00
lila
88691a345e extracted all english and italian nouns and verbs from own 2026-04-05 19:34:11 +02:00
lila
2a8630660e generating and migrating new schema 2026-04-05 19:30:05 +02:00
lila
e3c05b5596 updating seeding pipeline 2026-04-05 19:29:47 +02:00
lila
dfeb6a4cb0 updating seeding pipeline 2026-04-05 19:29:17 +02:00
lila
c49c2fe2c3 updating docs 2026-04-05 19:28:53 +02:00
lila
e80f291c41 refactoring data model 2026-04-05 18:57:09 +02:00
lila
b16b5db3f7 updating data models 2026-04-05 01:21:32 +02:00
lila
bfc09180f1 updating documentation 2026-04-05 01:21:18 +02:00
lila
7d80b20390 wip version of the api 2026-04-05 00:33:34 +02:00
lila
c24967dc74 updating docs 2026-04-05 00:33:05 +02:00
lila
1accb10f49 typo 2026-04-04 03:37:58 +02:00
lila
5180ecc864 installing zod + adding zod schemas 2026-04-02 20:02:26 +02:00
lila
874dd5e4c7 adding documentation and roadmap for the most minimal mvp 2026-04-02 18:28:44 +02:00
lila
a9cbcb719c refactoring schema + generate + migrate 2026-04-02 15:48:48 +02:00
lila
38a62ca3a4 refactoring 2026-04-02 15:48:31 +02:00
lila
cdedbc44cd refactoring 2026-04-02 13:37:54 +02:00