187 lines
6.5 KiB
Markdown
187 lines
6.5 KiB
Markdown
# HemHubs arkitektur
|
|
|
|
Detta dokument beskriver den arkitektur som kan verifieras i repositoryts kod,
|
|
tester och konfiguration. Historiska implementationssteg finns under
|
|
[`features/`](features/) och övergripande beslut under
|
|
[`decisions/`](decisions/).
|
|
|
|
## Aktuell implementation
|
|
|
|
### Monorepo
|
|
|
|
HemHub ligger i ett Git-repository med två separata applikationer:
|
|
|
|
```text
|
|
hemhub/
|
|
├── backend/
|
|
├── frontend/
|
|
└── docs/
|
|
```
|
|
|
|
Applikationerna har egna byggverktyg och beroenden. De delar inte källkod eller
|
|
byggprocess.
|
|
|
|
### Frontend
|
|
|
|
Frontend finns i `frontend/` och använder React 19, TypeScript, Vite och pnpm.
|
|
Den ansvarar för:
|
|
|
|
- hämtning och presentation av användare och uppgifter;
|
|
- lokalt val av aktiv användare;
|
|
- formulär för att skapa användare och uppgifter;
|
|
- klientnära validering och begripliga felmeddelanden;
|
|
- uppgiftsbrädan med kolumnerna Väntande, Pågående och Klart.
|
|
|
|
Tillståndet hanteras lokalt i React-komponenter. Ingen router eller separat
|
|
global state-lösning används.
|
|
|
|
### Backend
|
|
|
|
Backend finns i `backend/` och använder Java 21, Spring Boot 4.1.0, Maven,
|
|
Spring Web, Spring Data JPA och Flyway. Maven Wrapper ingår i repositoryt.
|
|
|
|
Backend ansvarar för API, slutlig validering, skapande av UUID och tidsstämplar,
|
|
persistens samt sortering av returnerade användare och uppgifter.
|
|
|
|
### Kommunikation
|
|
|
|
Alla applikationsendpoints ligger under `/api`. Frontend använder enbart
|
|
relativa adresser, exempelvis `/api/users` och `/api/tasks`.
|
|
|
|
Vid lokal utveckling kör Vite normalt på port 5173 och proxar `/api` till
|
|
`http://localhost:8080`, där Spring Boot körs. Ingen generell
|
|
CORS-konfiguration finns i backend. Webbläsaren anropar därmed Vites origin,
|
|
och utvecklingsservern vidarebefordrar API-anropen.
|
|
|
|
Aktuella endpoints:
|
|
|
|
- `GET /api/health`
|
|
- `GET /api/users`
|
|
- `POST /api/users`
|
|
- `GET /api/tasks`
|
|
- `POST /api/tasks`
|
|
|
|
### Databas och migreringar
|
|
|
|
Lokal körning använder en H2-databas i minnet. Databasen finns under
|
|
backendprocessens livstid och lokal utvecklingsdata återställs när backend
|
|
startas om. Automatiska backendtester använder en separat H2-databas i minnet.
|
|
|
|
Båda anslutningarna använder H2:s `MODE=PostgreSQL`,
|
|
`DATABASE_TO_LOWER=TRUE` och `DEFAULT_NULL_ORDERING=HIGH`. Det är en verifierbar
|
|
kompatibilitetsinställning, inte samma sak som att applikationen har verifierats
|
|
mot PostgreSQL.
|
|
|
|
Flyway kör migreringarna:
|
|
|
|
- `V1__create_users.sql`
|
|
- `V2__create_tasks.sql`
|
|
- `V3__add_task_points.sql`
|
|
|
|
Hibernate är konfigurerat med `ddl-auto=validate`; Flyway skapar schemat och
|
|
Hibernate validerar entiteterna mot det.
|
|
|
|
### Domänmodell
|
|
|
|
#### Användare
|
|
|
|
En användare lagras i tabellen `app_user` med:
|
|
|
|
- `id`: UUID;
|
|
- `name`: visningsnamn, högst 50 tecken;
|
|
- `normalized_name`: trimmat namn i gemener, internt och unikt;
|
|
- `created_at`: en `Instant`, lagrad som `TIMESTAMP WITH TIME ZONE`.
|
|
|
|
`normalized_name` exponeras inte via API. Användare returneras alfabetiskt efter
|
|
visningsnamn med deterministiska sekundära jämförelser.
|
|
|
|
#### Uppgift
|
|
|
|
En uppgift lagras i tabellen `task` med:
|
|
|
|
- `id`: UUID;
|
|
- `title`: obligatorisk titel, högst 100 tecken;
|
|
- `description`: valfri beskrivning, högst 500 tecken;
|
|
- `status`: `WAITING`, `IN_PROGRESS` eller `COMPLETED`;
|
|
- `points`: obligatoriskt heltal mellan 1 och 99;
|
|
- `created_at`: en `Instant`, lagrad som `TIMESTAMP WITH TIME ZONE`.
|
|
|
|
Status lagras som enumens textvärde genom `EnumType.STRING`. Nya uppgifter får
|
|
alltid status `WAITING`. Poängintervallet skyddas i backend och med en
|
|
databasconstraint. Det finns ingen relation mellan uppgifter och användare;
|
|
alla aktiva användare ser samma uppgiftslista.
|
|
|
|
### Aktiv användare
|
|
|
|
Användarlistan hämtas från backend. Frontend lagrar endast den valda
|
|
användarens UUID i webbläsarens `localStorage` under nyckeln
|
|
`hemhub.activeUserId`.
|
|
|
|
Vid start verifieras det lagrade id:t mot backendens aktuella användarlista. Ett
|
|
giltigt val återanvänds i samma browser. Ett ogiltigt val tas bort. Valet är
|
|
lokalt per browser och utgör inte autentisering eller behörighetskontroll.
|
|
|
|
### Felhantering
|
|
|
|
Backend använder ett litet gemensamt JSON-format med `code` och `message`.
|
|
`ApiExceptionHandler` översätter kända valideringsfel till `400 Bad Request`
|
|
och dubbletter av användarnamn till `409 Conflict`.
|
|
|
|
Frontend skiljer mellan fel vid hämtning och skapande. Hämtfel kan
|
|
återförsökas. Formulärfel visas nära formuläret och inmatningen behålls vid
|
|
misslyckade API-anrop.
|
|
|
|
### Teststrategi
|
|
|
|
Backend har JUnit 5-tester:
|
|
|
|
- ett fristående MockMvc-test för health-endpointen;
|
|
- Spring Boot-integrationstester via MockMvc mot H2 in-memory för användar- och
|
|
uppgifts-API.
|
|
|
|
Frontend använder Vitest, jsdom och React Testing Library. `fetch` och
|
|
`localStorage` ersätts i testerna, så frontendtesterna kräver inte en körande
|
|
backend. Produktionsbygget kör TypeScript-kompilering följt av Vite.
|
|
|
|
### Produktionsdeployment
|
|
|
|
Ingen produktionsdeployment är implementerad i repositoryt. Det finns inga
|
|
Dockerfiler, pipelinefiler eller produktionsspecifika Nginx-, Watchtower- eller
|
|
databaskonfigurationer. H2 används både lokalt och i automatiska tester; någon
|
|
PostgreSQL-konfiguration finns ännu inte.
|
|
|
|
## Beslutad planerad riktning
|
|
|
|
Repositoryt anger att affärsregler även framöver ska säkerställas i backend och
|
|
att större arkitekturella beslut ska diskuteras innan de införs.
|
|
|
|
Följande produktionsriktning är beslutad men ännu inte implementerad:
|
|
|
|
- PostgreSQL ska användas som produktionsdatabas.
|
|
- Frontend och backend ska paketeras som separata Docker-images.
|
|
- Källkoden ligger i Gitea.
|
|
- Drone ska bygga och publicera images till ett privat registry.
|
|
- Watchtower ska uppdatera de körande tjänsterna när nya images publiceras.
|
|
- Nginx kan användas som reverse proxy framför tjänsterna.
|
|
- Produktionsmiljön ska köras på Ubuntu-servern Biff.
|
|
|
|
Den planerade riktningen beskrivs även i
|
|
[`005-production-deployment-direction.md`](decisions/005-production-deployment-direction.md).
|
|
Punkterna ovan beskriver målbilden och ska inte tolkas som att motsvarande
|
|
konfiguration redan finns eller har verifierats.
|
|
|
|
## Fortfarande öppna detaljer
|
|
|
|
Följande har inte fastställts i dokumentationen och ska beslutas i samband med
|
|
att produktionslösningen implementeras:
|
|
|
|
- exakt containerstruktur och tjänsteindelning;
|
|
- image-namn och taggningsstrategi;
|
|
- produktions-URL;
|
|
- hantering och distribution av secrets;
|
|
- exakt Nginx-konfiguration;
|
|
- exakt Drone-, registry-, Watchtower- och deploymentkonfiguration.
|
|
|
|
Miljöspecifika adresser, credentials och secrets ska inte lagras i dessa
|
|
arkitekturdokument.
|