feat: persönlichere Profilseite + iOS-App-Setup

Profil: Begrüßung in Zielsprache, Kategorie-Punkte-Übersicht,
ruhigerer Header (kein rotierender Avatar/Online-Dot), Notch-Fix
und kompaktere Aktivitäts-Heatmap. Außerdem Capacitor-iOS-Projekt
und diverse Auth/Feed/Audio-Verbesserungen aus dem Premium-Redesign.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 12:55:13 +02:00
parent 712f9a243c
commit e7b4ec571e
49 changed files with 3221 additions and 210 deletions

64
CLAUDE.md Normal file
View File

@@ -0,0 +1,64 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
```bash
npm run dev # Vite dev server (default http://localhost:5173)
npm run build # Production build → dist/
npm run preview # Serve the built dist/ locally
```
There is **no test runner and no linter** configured — `package.json` only defines `dev`, `build`, `preview`. Don't suggest `npm test`/`npm run lint`.
Deployment is a two-stage Docker build (`Dockerfile`): Node builds `dist/`, then it's served by nginx (`nginx.conf`) with SPA fallback (`try_files … /index.html`).
## Environment
`VITE_API_URL` (in `.env` / `.env.production`) points at the backend. It's the **only** runtime config — every API call in `src/api/directus.js` reads `import.meta.env.VITE_API_URL`. `.env` is gitignored.
## Architecture
React 19 + Vite SPA, **no router package**. There are no DB cards/feed entries fetched directly — the app talks to a custom backend, not Directus directly (see below).
**Routing** is `useState`-based in `src/App.jsx`: a `PAGES` map (`feed`/`game`/`pro`/`profil`) swaps the active page component, driven by `BottomNav`. `Game` and `Pro` are placeholders.
**Auth gating:** `App.jsx` renders `<AuthScreen />` unless the user has `username`, `language_native_id`, and `language_target_id`. `AuthContext` (`src/context/AuthContext.jsx`) holds the JWT (localStorage key **`hejyou_token`**), calls `getMe()` on mount, and clears the token on failure. Registration is two steps: `RegisterStep1` (email+password) → `RegisterStep2` (username + native/target language).
### The API client is misnamed
`src/api/directus.js` is **not** a Directus client anymore — the module name is kept "aus historischen Gründen". It is a thin fetch wrapper around a **custom backend (snakkimo-API)** exposing `/auth/*` endpoints:
| Function | Endpoint | Notes |
|---|---|---|
| `login` / `registerUser` | `POST /auth/login`, `/auth/register` | return `{ token, userId, needsProfile }` |
| `getMe` | `GET /auth/me` | basis for auth check + progress (EP/streak/level) |
| `checkUsername` | `GET /auth/check-username` | |
| `createProfile` | `POST /auth/profile` | username + native/target lang |
| `getLanguageOptions` | `GET /auth/languages` | merged with local `LANG_META` (flag + Web Speech code) |
| `getFeedPairs` | `GET /auth/feed?lang=&limit=` | returns "pairs", the feed unit |
| `saveProgress` | `POST /auth/progress` | books EP/streak, returns updated `total_ep` |
Several content functions (`getWords`, `getQuestions`, `getActiveLearningPair`, `assetUrl`, …) are **stubs** returning empty/null — content endpoints are not built yet. Don't assume they fetch anything.
### Feed = "pairs" → cards
`src/pages/Feed.jsx` fetches an array of *pairs* and maps each to one card by its `answer_type`:
| `answer_type` | Component | Points (`POINTS` map) |
|---|---|---|
| `text` | `PairSentenceCard` | 2 |
| `yes_no` | `PairYesNoCard` | 2 |
| `word` | `PairWordCard` | 3 |
| `question` | `PairWordCard` | 3 |
On completion, `handleComplete` adds the pair id to a local `done` set (cards are hidden, not removed) and POSTs to `saveProgress`. Target language comes from `user.language_target_short` (fallback `de`).
The **`Pair*` cards** (`PairSentenceCard`, `PairYesNoCard`, `PairWordCard`) are the live card components. The other card files (`NewWord*`, `ImagePick/ImageQuiz`, `AudioQuiz`, `LetterOrder`, `SentenceFill`, `LanguageParentCard`) are an **earlier card model** not wired into the current feed — check `Feed.jsx` before assuming a component is in use.
Several cards use the browser **Web Speech API** (`SpeechRecognition` / `speechSynthesis`) for the `speak`/`listen` flow; `src/utils/confetti.js` wraps `canvas-confetti` for correct-answer feedback.
## `knowledge/directus_struktur.md`
A detailed reference for the **backend data model** (collections, fields, relations) and the original app concept. Useful for understanding the domain and DB schema, but note it predates the custom-backend migration: its "Frontend API-Funktionen" table describes **direct Directus calls that no longer exist** — trust `src/api/directus.js` for the actual frontend contract.