diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml index a48cee1..306cc78 100644 --- a/.forgejo/workflows/deploy.yml +++ b/.forgejo/workflows/deploy.yml @@ -8,9 +8,6 @@ jobs: build-and-deploy: runs-on: docker steps: - - name: Install tools - run: apt-get update && apt-get install -y docker.io openssh-client - - name: Checkout code uses: https://data.forgejo.org/actions/checkout@v4 diff --git a/README.md b/README.md index 32af038..675d039 100644 --- a/README.md +++ b/README.md @@ -1,170 +1 @@ # lila - -**Learn words. Beat friends.** - -lila is a vocabulary trainer built around a Duolingo-style quiz loop: a word appears in one language, you pick the correct translation from four choices. It supports singleplayer and real-time multiplayer, and is designed to work across multiple language pairs without schema changes. - -Live at [lilastudy.com](https://lilastudy.com). - ---- - -## Stack - -| Layer | Technology | -|---|---| -| Monorepo | pnpm workspaces | -| Frontend | React 18, Vite, TypeScript | -| Routing | TanStack Router | -| Server state | TanStack Query | -| Styling | Tailwind CSS | -| Backend | Node.js, Express, TypeScript | -| Database | PostgreSQL + Drizzle ORM | -| Validation | Zod (shared schemas) | -| Auth | Better Auth (Google + GitHub) | -| Realtime | WebSockets (`ws` library) | -| Testing | Vitest, supertest | -| Deployment | Docker Compose, Caddy, Hetzner VPS | -| CI/CD | Forgejo Actions | - ---- - -## Repository Structure - -``` -lila/ -├── apps/ -│ ├── api/ — Express backend -│ └── web/ — React frontend -├── packages/ -│ ├── shared/ — Zod schemas and types shared between frontend and backend -│ └── db/ — Drizzle schema, migrations, models, seeding scripts -├── scripts/ — Python scripts for vocabulary data extraction -└── documentation/ — Project docs -``` - -`packages/shared` is the contract between frontend and backend. All request/response shapes are defined there as Zod schemas and never duplicated. - ---- - -## Architecture - -Requests flow through a strict layered architecture: - -``` -HTTP Request → Router → Controller → Service → Model → Database -``` - -Each layer only talks to the layer directly below it. Controllers handle HTTP only. Services contain business logic only. Models contain database queries only. All database code lives in `packages/db` — the API never imports Drizzle directly for queries. - ---- - -## Data Model - -Words are modelled as language-neutral concepts (`terms`) with per-language `translations`. Adding a new language requires no schema changes — only new rows. CEFR levels (A1–C2) are stored per translation for difficulty filtering. - -Core tables: `terms`, `translations`, `term_glosses`, `decks`, `deck_terms` -Auth tables (managed by Better Auth): `user`, `session`, `account`, `verification` - -Vocabulary data is sourced from WordNet and the Open Multilingual Wordnet (OMW). - ---- - -## API - -``` -POST /api/v1/game/start — start a quiz session (auth required) -POST /api/v1/game/answer — submit an answer (auth required) -GET /api/v1/health — health check (public) -ALL /api/auth/* — Better Auth handlers (public) -``` - -The correct answer is never sent to the frontend — all evaluation happens server-side. - ---- - -## Multiplayer - -Rooms are created via REST, then managed over WebSockets. Messages are typed via a Zod discriminated union. The host starts the game; all players answer simultaneously with a 15-second server-enforced timer. Room state is held in-memory (Valkey deferred). - ---- - -## Infrastructure - -``` -Internet → Caddy (HTTPS) - ├── lilastudy.com → web (nginx, static files) - ├── api.lilastudy.com → api (Express) - └── git.lilastudy.com → Forgejo (git + registry) -``` - -Deployed on a Hetzner VPS (Debian 13, ARM64). Images are built cross-compiled for ARM64 and pushed to the Forgejo container registry. CI/CD runs via Forgejo Actions on push to `main`. Daily database backups are synced to the dev laptop via rsync. - -See `documentation/deployment.md` for the full infrastructure setup. - ---- - -## Local Development - -### Prerequisites - -- Node.js 20+ -- pnpm 9+ -- Docker + Docker Compose - -### Setup - -```bash -# Install dependencies -pnpm install - -# Create your local env file (used by docker compose + the API) -cp .env.example .env - -# Start local services (PostgreSQL, Valkey) -docker compose up -d - -# Build shared packages -pnpm --filter @lila/shared build -pnpm --filter @lila/db build - -# Run migrations and seed data -pnpm --filter @lila/db migrate -pnpm --filter @lila/db seed - -# Start dev servers -pnpm dev -``` - -The API runs on `http://localhost:3000` and the frontend on `http://localhost:5173`. - ---- - -## Testing - -```bash -# All tests -pnpm test - -# API only -pnpm --filter api test - -# Frontend only -pnpm --filter web test -``` - ---- - -## Roadmap - -| Phase | Description | Status | -|---|---|---| -| 0 | Foundation — monorepo, tooling, dev environment | ✅ | -| 1 | Vocabulary data pipeline + REST API | ✅ | -| 2 | Singleplayer quiz UI | ✅ | -| 3 | Auth (Google + GitHub) | ✅ | -| 4 | Multiplayer lobby (WebSockets) | ✅ | -| 5 | Multiplayer game (real-time, server timer) | ✅ | -| 6 | Production deployment + CI/CD | ✅ | -| 7 | Hardening (rate limiting, error boundaries, monitoring, accessibility) | 🔄 | - -See `documentation/roadmap.md` for task-level detail. diff --git a/apps/web/src/components/game/GameSetup.tsx b/apps/web/src/components/game/GameSetup.tsx index 9315bc4..0266342 100644 --- a/apps/web/src/components/game/GameSetup.tsx +++ b/apps/web/src/components/game/GameSetup.tsx @@ -35,18 +35,16 @@ const SettingGroup = ({ onSelect, }: SettingGroupProps) => (
- {label} -
+{label}