From 168f6ba6b7336646f78856aa4e58bc9672342f2a Mon Sep 17 00:00:00 2001 From: Marek Lenczewski Date: Sun, 12 Apr 2026 16:00:26 +0200 Subject: [PATCH] update plan --- CLAUDE.md | 129 ++++++++++++++++++++++-------------------------------- base.md | 5 +-- module.md | 14 ------ 3 files changed, 54 insertions(+), 94 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 76d7b93..3869d06 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,13 +2,13 @@ Basis-Software mit 3 geplanten Apps: Task Manager, Shopping List, Meal Planner. -Aktueller Stand: **Task module** implementiert (siehe `module.md`) — Backend + Vue + Kotlin App jeweils end-to-end mit Task-CRUD, Status-Handling und Datum. +Aktueller Stand: **TaskSchema module** implementiert (siehe `module.md`). ## Tech-Stack | Schicht | Technologie | |---------|------------| -| Backend | Symfony 7.4, PHP 8.3, Doctrine ORM | +| Backend | Symfony 7.4, PHP 8.3, Doctrine ORM, Symfony Messenger + Scheduler | | Frontend Web | Vue 3 (Composition API), Vite, Pinia, Vue Router 4 | | Frontend Mobile | Kotlin + Jetpack Compose (Material 3), Retrofit + kotlinx.serialization | | Datenbank | MariaDB 10.11 (utf8mb4) | @@ -20,118 +20,93 @@ Aktueller Stand: **Task module** implementiert (siehe `module.md`) — Backend + ``` backend/ src/ - Collection/TaskCollection.php — IteratorAggregate, filterInactive/sortByDueDate* - Controller/Api/TaskController.php — REST-Routen unter /api/tasks - DTO/TaskRequest.php — readonly promoted constructor, Validator + Context(!Y-m-d) - Entity/Task.php — Doctrine entity, getStatus() derived-past - Enum/TaskStatus.php — active, done, inactive, past (past nicht user-selectable) - Repository/TaskRepository.php — currentTasks(), allTasks() → TaskCollection - Service/TaskManager.php — create/update/delete/toggle Business-Logik - Kernel.php - config/ — nelmio_cors, doctrine, framework, ... - migrations/Version20260411141650.php — tasks table - public/index.php + Collection/TaskCollection.php, TaskSchemaCollection.php + Controller/Api/TaskController.php, TaskSchemaController.php + DTO/TaskRequest.php, TaskSchemaRequest.php + Entity/Task.php (+ schema FK), TaskSchema.php + Enum/TaskStatus.php, TaskSchemaStatus.php + Message/GenerateTasksMessage.php + MessageHandler/GenerateTasksMessageHandler.php + Repository/TaskRepository.php, TaskSchemaRepository.php + Service/TaskManager.php (update/delete/toggle), TaskSchemaManager.php (create/update/delete), TaskGenerator.php (generateTasks/removeTasks/generateNewTasks) + Schedule.php — Scheduler (cron 0 3 * * *) + config/packages/messenger.yaml — scheduler_default transport + migrations/ + public/app/version.json + haushalt.apk — App-Update frontend/ src/ - components/Icon.vue — zentrales Icon-Component - router/index.js — /, /tasks, /tasks/all, /tasks/create, /tasks/:id mit breadcrumb meta - services/api.js — fetch wrapper, tasks() + statuses() Endpoints - stores/tasks.js — Pinia store: fetchCurrent, fetchAll, get, create, update, remove, toggle, fetchStatuses - views/ - Startpage.vue — Nav-Kacheln - Task.vue — /tasks (aktuelle Tasks), Card-pro-Datum mit Legend-Titel - TaskAll.vue — /tasks/all (alle Tasks, flache Liste mit Edit/Delete) - TaskCreate.vue — /tasks/create - TaskEdit.vue — /tasks/:id - App.vue — Breadcrumb-Layout + RouterView - main.js — Vue-Init (Pinia + Router) + components/Icon.vue + router/index.js — /, /tasks, /tasks/all, /tasks/:id, /schemas, /schemas/create, /schemas/:id + services/api.js — taskApi + schemaApi + stores/tasks.js, schemas.js + views/ — Startpage, Task, TaskAll, TaskEdit, SchemaCreate, SchemaAll, SchemaEdit app/app/src/main/java/de/haushalt/app/ - MainActivity.kt — Compose entry - MainScreen.kt — NavHost (start, tasks, tasks/all, tasks/create, tasks/{id}) - StartScreen.kt — Nav-Kacheln - data/ - ApiClient.kt — Retrofit + kotlinx.serialization Setup - TaskApi.kt — Retrofit interface (list, get, create, update, delete, toggle, statuses) - Task.kt — Task + TaskStatus enum - ui/task/ - TaskScreen.kt — /tasks, gleiches Card-Gruppierungs-Muster wie Vue - TaskAllScreen.kt — /tasks/all flache Liste, Edit/Delete - TaskCreateScreen.kt / TaskCreateViewModel.kt - TaskEditScreen.kt / TaskEditViewModel.kt - TaskListViewModel.kt — visibleTasks, groupedTasks, showDone, refresh, toggle - TaskAllViewModel.kt - DatePickerField.kt — Material 3 DatePickerDialog Wrapper - StatusDropdown.kt — ExposedDropdownMenuBox, Status-Labels vom Backend - DateFormat.kt — formatDate() mit dd.MM.yyyy + MainActivity.kt, MainScreen.kt, StartScreen.kt + data/ — ApiClient, TaskApi, Task, TaskSchemaApi, TaskSchema, AppUpdateApi, AppUpdater + ui/task/ — TaskScreen, TaskAllScreen, TaskEditScreen, ViewModels, DatePickerField, StatusDropdown, DateFormat + ui/schema/ — SchemaCreateScreen, SchemaEditScreen, SchemaAllScreen, ViewModels, SchemaComponents ``` ## Domänenmodell -**Task** -- `id`, `name`, `date` (nullable, ISO), `status` -- Status-Enum (`TaskStatus`): `active`, `done`, `inactive`, `past` -- `past` ist **derived** — wenn `date < today`, liefert `Task::getStatus()` automatisch `past`; der rohe gespeicherte Wert bleibt erhalten (`getRawStatus()`) -- `past` ist **nicht user-selectable** (siehe `TaskStatus::userSelectableValues()`) -- Filter `/api/tasks?filter=current` → Tasks ohne `inactive`, sortiert nach `date` aufsteigend (null-first) -- Default (`/api/tasks`) → alle Tasks, sortiert nach `date` absteigend +**Task**: id, name, date?, status (active/done/inactive/past), schema? +- `past` ist derived (date < today), nicht user-selectable + +**TaskSchema**: id, name, status (active/inactive), taskStatus, date?, repeat (json)?, start?, end? +- repeat=null → single (Task direkt, kein Schema persistiert) +- repeat={"daily":true} / {"weekly":[7 bools]} / {"monthly":[31 bools]} +- getRepeatType() → 'daily' | 'weekly' | 'monthly' | null ## REST-API | Methode | Route | Zweck | |---|---|---| -| GET | `/api/tasks?filter=current` | aktuelle Tasks (für `/tasks`) | -| GET | `/api/tasks` | alle Tasks (für `/tasks/all`) | -| GET | `/api/tasks/statuses` | user-selectable Statuswerte als `string[]` | +| GET | `/api/tasks?filter=current` | aktuelle Tasks | +| GET | `/api/tasks` | alle Tasks | +| GET | `/api/tasks/statuses` | selectable Statuswerte | | GET | `/api/tasks/{id}` | einzelner Task | -| POST | `/api/tasks` | Task anlegen | | PUT | `/api/tasks/{id}` | Task aktualisieren | | DELETE | `/api/tasks/{id}` | Task löschen | -| PATCH | `/api/tasks/{id}/toggle` | Status zwischen `active`/`done` togglen | - -Request-DTO: `TaskRequest` (name, date `!Y-m-d`, status). Deserialisiert + validiert via `#[MapRequestPayload]`. -Response-Serialisierung: Symfony Serializer mit `groups: ['task:read']`, Datum als ISO `Y-m-d` String. +| PATCH | `/api/tasks/{id}/toggle` | active↔done togglen | +| GET | `/api/task-schemas` | alle Schemas | +| GET | `/api/task-schemas/{id}` | einzelnes Schema | +| POST | `/api/task-schemas` | Schema erstellen (+ Tasks generieren) | +| PUT | `/api/task-schemas/{id}` | Schema aktualisieren (remove + regenerate Tasks) | +| DELETE | `/api/task-schemas/{id}` | Schema + nicht-past Tasks löschen | ## UI-Muster -- **`/tasks`** (Vue + Kotlin): Tasks nach Datum gruppiert in Cards. Datum sitzt als Pill auf dem Top-Border der Card (fieldset/legend-Look). No-Date-Tasks oben in titelloser Card. `showDone` default `false`. -- **`/tasks/all`** (Vue + Kotlin): Flache Liste mit Edit- und Delete-Icons. `past`-Tasks mit Opacity 0.5, `inactive` kursiv, `done` durchgestrichen. -- **Icon-Reihenfolge `/tasks` Header**: plus, list, eye, refresh. -- Kotlin-Screens refreshen auf `Lifecycle.Event.ON_RESUME` via `DisposableEffect` (gegen stale Daten nach Navigation). -- Status-Labels in Create/Edit kommen aus dem Backend (`/api/tasks/statuses`) — nicht clientseitig hardcoded. +- **`/tasks`**: Tasks nach Datum gruppiert in Cards (Legend-Titel). Icons: calendar, +, list, eye, refresh. +- **`/tasks/all`**: Flache Liste mit Edit/Delete. past=0.5 opacity, inactive=kursiv, done=durchgestrichen. +- **`/schemas`**: Schema-Liste mit Name + Repeat nebeneinander, Edit/Delete Icons. +- **Schema Create/Edit**: name, (status + taskStatus nebeneinander), repeat, weekday/monthday grid, (start + end nebeneinander). +- Kotlin: Lifecycle-Refresh via DisposableEffect ON_RESUME. +- App-Update: "Update prüfen" Button auf StartScreen, APK von Server laden. ## Dokumentation -- **`base.md`** — Vision: was gebaut wird (3 Apps, Systeme, Datenbank-Skizze) -- **`module.md`** — Implementierungs-Schritte als Feature-Module (Backend + Frontend end-to-end pro Modul) +- **`base.md`** — Vision: was gebaut wird +- **`module.md`** — Implementierungs-Schritte als Feature-Module - **`CLAUDE.md`** (diese Datei) — Ist-Zustand des Codes ## Code-Konventionen -- **Sprache Code**: Englisch (Klassen, Methoden, Variablen) -- **Sprache UI**: Deutsch -- **Enum-Werte**: Englisch in DB und Code -- **Datum im Backend**: ISO `Y-m-d` (als DTO-Input und in Response-JSON) -- **Datum im UI**: `dd.MM.yyyy` — Formatierung in Vue (`formatDate` in `Task.vue`) und Kotlin (`DateFormat.kt`) +- **Sprache Code**: Englisch, **UI**: Deutsch, **Enum-Werte**: Englisch +- **Datum**: Backend ISO `Y-m-d`, UI `dd.MM.yyyy` - **Frontend**: Vue 3 Composition API mit `