Task module

This commit is contained in:
Marek Lenczewski
2026-04-12 10:06:17 +02:00
parent efe0cfe361
commit 27b34eb90f
39 changed files with 2454 additions and 41 deletions

View File

@@ -2,7 +2,7 @@
Basis-Software mit 3 geplanten Apps: Task Manager, Shopping List, Meal Planner.
Aktueller Stand: **Setup module** (siehe `module.md`) — minimales Symfony + Vue Gerüst, kein Feature-Code.
Aktueller Stand: **Task module** implementiert (siehe `module.md`) — Backend + Vue + Kotlin App jeweils end-to-end mit Task-CRUD, Status-Handling und Datum.
## Tech-Stack
@@ -10,7 +10,7 @@ Aktueller Stand: **Setup module** (siehe `module.md`) — minimales Symfony + Vu
|---------|------------|
| Backend | Symfony 7.4, PHP 8.3, Doctrine ORM |
| Frontend Web | Vue 3 (Composition API), Vite, Pinia, Vue Router 4 |
| Frontend Mobile | Kotlin + Jetpack Compose (noch nicht aufgesetzt) |
| Frontend Mobile | Kotlin + Jetpack Compose (Material 3), Retrofit + kotlinx.serialization |
| Datenbank | MariaDB 10.11 (utf8mb4) |
| CORS | Nelmio CORS Bundle |
| Umgebung | DDEV |
@@ -20,19 +20,85 @@ Aktueller Stand: **Setup module** (siehe `module.md`) — minimales Symfony + Vu
```
backend/
src/
Kernel.php — Standard-Symfony-Kernel, keine App-Klassen
config/ — Symfony-Config (nelmio_cors, doctrine, framework, ...)
migrations/ — leer
public/index.php — Symfony-Einstieg
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
frontend/
src/
main.js — Vue-Init mit Pinia + Router
App.vue — RouterView, kein Content
router/index.js — Router mit leerem routes-Array
style.css — leer
index.html, vite.config.js
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)
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
```
## 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
## 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/{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.
## 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.
## Dokumentation
- **`base.md`** — Vision: was gebaut wird (3 Apps, Systeme, Datenbank-Skizze)
@@ -44,6 +110,8 @@ frontend/
- **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`)
- **Frontend**: Vue 3 Composition API mit `<script setup>`
## Development
@@ -54,10 +122,15 @@ ddev start
# Backend
ddev exec "cd backend && php bin/console cache:clear"
ddev exec "cd backend && php bin/console doctrine:migrations:migrate"
# Frontend
ddev exec "cd frontend && npm install"
ddev exec "cd frontend && npm run dev -- --host 0.0.0.0"
ddev exec "cd frontend && npm run build"
# Android App (Java 17 für Gradle)
cd app && JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew :app:installDebug
# URLs
Frontend: https://haushalt.ddev.site:5173