No description
Every rejection in the German run was the same rule: a translation ranked below its own sense. The model tags a sense "medium" while correctly tagging some translations "easy" — the translations are right and the derived sense label is wrong, but the whole entry was discarded. The prompt defines sense difficulty as the easiest translation difficulty in that sense, so it is a derived value rather than an independent judgement. validate.ts now recomputes it via applySenseDifficultyFloor. The floor only ever lowers. Raising a sense to match its translations would gate a concept out of levels it belongs in and collapse the concept-vs-word distinction the two difficulty columns exist to express (design-doc section 4). - validate.ts: drop the cross-field rejection, add the floor; the valid result now carries "normalizations" so repairs are reported, not silent - pipeline.ts: count and print normalizations per batch and in the summary - replay.ts: new, re-validates responses/ with the current rules and no API calls; --write stages recovered entries, --langs and --verbose - tests: six cases covering the floor, replacing the old rejection test Replaying all 38 saved responses took the reject rate from 20 entries to zero. staging.db now holds 746 words / 774 senses / 3,436 translations with no sense ranked above its easiest translation. Docs also record the API quota ceiling found today: the free tier allows about 20 requests/day, not the 1,000 previously assumed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| .husky | ||
| apps | ||
| data-pipeline | ||
| documentation | ||
| packages | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc | ||
| Caddyfile | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| eslint.config.mjs | ||
| mise.toml | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| tsconfig.base.json | ||
| tsconfig.json | ||
| vitest.config.ts | ||
Lila
Learn words. Beat friends.
Lila is a vocabulary trainer that turns the media you love into language practice. Learn vocabulary from a Shakira song, the first chapter of Harry Potter, or an episode of Breaking Bad — then challenge your friends in real-time multiplayer quizzes.
Live at lilastudy.com.
Quickstart
# 1. Clone and install
git clone git@git.lilastudy.com:forgejo-lila/lila.git
cd lila
pnpm install
# 2. Environment
cp .env.example .env
# 3. Start local services (PostgreSQL, Valkey)
docker compose up -d
# 4. Build shared packages
pnpm --filter @lila/shared build
pnpm --filter @lila/db build
# 5. Run migrations
pnpm --filter @lila/db migrate
# 6. Start dev servers
pnpm dev
API: http://localhost:3000 · Web: http://localhost:5173
See DEPLOYMENT.md for production infrastructure details.
Documentation Index
| Document | What you'll find there |
|---|---|
| STATUS.md | Current state — what's working, what's blocked, what we're building now |
| BACKLOG.md | Prioritized task list: now / next / later / changelog |
| ARCHITECTURE.md | Monorepo structure, layered architecture, data flow |
| DECISIONS.md | Why we chose X over Y — tool choices, schema design, trade-offs |
| DATA_PIPELINE.md | Gemini → SQLite staging → PostgreSQL: flow, current state, phase status |
| pipeline/design-doc.md | Schema design, difficulty model, query patterns, Gemini JSON contract |
| pipeline/roadmap.md | Phase plan for the pipeline and schema migration |
| DEPLOYMENT.md | Hetzner VPS, Caddy, Docker Compose, CI/CD, backups |
| design/GAME_MODES.md | Planned multiplayer and singleplayer game modes |
| archive/ | Superseded docs — the removed local-LLM pipeline, CEFR voter strategy |
Stack
| Layer | Technology |
|---|---|
| Monorepo | pnpm workspaces |
| Frontend | React 19, Vite, TanStack Router, Tailwind CSS |
| Backend | Node.js, Express, TypeScript, WebSockets (ws) |
| Database | PostgreSQL + Drizzle ORM |
| Auth | Better Auth (Google + GitHub) |
| Validation | Zod (shared between frontend and backend) |
| Testing | Vitest, supertest |
| Deployment | Docker Compose, Caddy, Hetzner VPS |
| CI/CD | Forgejo Actions |
Current Status
- ✅ Singleplayer quiz (5 language pairs: en↔it/de/es/fr)
- ✅ Multiplayer lobby + real-time game (2–4 players, simultaneous answers, 15s timer)
- ✅ Auth (Google + GitHub)
- ✅ Live deployment with CI/CD
- 🔄 Rewriting the vocabulary data pipeline around Gemini + a sense-based schema
- 🔄 Phase 7 hardening (rate limiting, error boundaries, monitoring)
See STATUS.md for the full picture.
Repository Structure
lila/
├── apps/
│ ├── api/ — Express backend
│ └── web/ — React frontend
├── packages/
│ ├── shared/ — Zod schemas + constants (API/web contract)
│ └── db/ — Drizzle schema, migrations, models, seeding
├── data-pipeline/ — Gemini generation → SQLite staging → PostgreSQL
├── documentation/ — Project docs (this directory)
└── Caddyfile, docker-compose.yml, etc.