6.5 KiB
6.5 KiB
Haushalt
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.
Tech-Stack
| Schicht | Technologie |
|---|---|
| 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 (Material 3), Retrofit + kotlinx.serialization |
| Datenbank | MariaDB 10.11 (utf8mb4) |
| CORS | Nelmio CORS Bundle |
| Umgebung | DDEV |
Struktur
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
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)
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 pastist derived — wenndate < today, liefertTask::getStatus()automatischpast; der rohe gespeicherte Wert bleibt erhalten (getRawStatus())pastist nicht user-selectable (sieheTaskStatus::userSelectableValues())- Filter
/api/tasks?filter=current→ Tasks ohneinactive, sortiert nachdateaufsteigend (null-first) - Default (
/api/tasks) → alle Tasks, sortiert nachdateabsteigend
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.showDonedefaultfalse./tasks/all(Vue + Kotlin): Flache Liste mit Edit- und Delete-Icons.past-Tasks mit Opacity 0.5,inactivekursiv,donedurchgestrichen.- Icon-Reihenfolge
/tasksHeader: plus, list, eye, refresh. - Kotlin-Screens refreshen auf
Lifecycle.Event.ON_RESUMEviaDisposableEffect(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)module.md— Implementierungs-Schritte als Feature-Module (Backend + Frontend end-to-end pro Modul)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 (formatDateinTask.vue) und Kotlin (DateFormat.kt) - Frontend: Vue 3 Composition API mit
<script setup>
Development
# DDEV starten
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
API: https://haushalt.ddev.site/api