105 lines
4.4 KiB
Markdown
105 lines
4.4 KiB
Markdown
|
|
# admin-api
|
||
|
|
|
||
|
|
Admin-only HTTP service for ProofedMesh. Currently covers one concern:
|
||
|
|
Verwaltung der Per-Diem-Pauschalen (`per_diem_rates`), die vom
|
||
|
|
`agent-per-diem-calculator` deterministisch angewandt werden
|
||
|
|
(siehe `docs/architecture/v1.1.md` §6.2 und ADR-0003).
|
||
|
|
|
||
|
|
**Status: Skelett.** Datenbankanbindung (pgx) und Signing-Service-Call sind
|
||
|
|
Stubs mit expliziten Fehlern; HTTP-Handler, HTML-Templates, Modell-Typen und
|
||
|
|
Store-Interface sind vollständig und getestet. Prod-Deployment folgt nach
|
||
|
|
Phase-1-Trust-Core.
|
||
|
|
|
||
|
|
## Scope
|
||
|
|
|
||
|
|
- Admin-Oberfläche `/admin/per-diem-rates` — Liste + Neuanlage + „Retire" (`valid_to` setzen) über HTML + HTMX-ähnlichen simple-POST-Flow.
|
||
|
|
- JSON-API hinter denselben Pfaden für Automatisierung (`Accept: application/json`).
|
||
|
|
- Jede Create/Retire-Operation erzeugt eine **Rate Change Attestation** über den Signing Service — predicateType `https://basicstack.de/attestations/rate_change/v1`. Rückgabe-Hash wird in `per_diem_rates.rate_change_attestation_ref` sowie in `per_diem_rate_changes` persistiert.
|
||
|
|
- Keine Delete-Operation. Historie ist unveränderlich (Schema-Trigger erzwingt das).
|
||
|
|
|
||
|
|
## Auth
|
||
|
|
|
||
|
|
- OIDC via Pocket ID (Authorization-Code-Flow, Session-Cookie).
|
||
|
|
- Autorisierung: Gruppenmitgliedschaft `proofedmesh-admin` wird aus dem ID-Token gelesen und ist Pflicht für alle Endpunkte außer Login.
|
||
|
|
- Hintergrund-Dienste rufen die API nicht — Admin-API ist Human-only. Deshalb kein `client_credentials`-Pfad.
|
||
|
|
|
||
|
|
## HTTP-Endpunkte (geplant)
|
||
|
|
|
||
|
|
| Methode | Pfad | Beschreibung |
|
||
|
|
| ------- | ---------------------------------------- | -------------------------------------------- |
|
||
|
|
| GET | `/admin/per-diem-rates/` | Liste aller Rates (gefiltert nach Country, aktiv/retired) |
|
||
|
|
| GET | `/admin/per-diem-rates/{rate_id}` | Detailansicht einer Rate |
|
||
|
|
| POST | `/admin/per-diem-rates/` | Neue Rate anlegen (JSON oder Form) |
|
||
|
|
| POST | `/admin/per-diem-rates/{rate_id}/retire` | `valid_to` setzen (Rate ablaufen lassen) |
|
||
|
|
|
||
|
|
Content-Negotiation per `Accept`-Header: `text/html` → Templates, `application/json` → JSON.
|
||
|
|
|
||
|
|
## Layout
|
||
|
|
|
||
|
|
```
|
||
|
|
services/admin-api/
|
||
|
|
├── README.md — diese Datei
|
||
|
|
├── go.mod
|
||
|
|
├── cmd/admin-api/main.go — HTTP-Entry (bind + router + graceful shutdown)
|
||
|
|
├── internal/
|
||
|
|
│ ├── model/rate.go — Rate struct, validation
|
||
|
|
│ ├── store/
|
||
|
|
│ │ ├── store.go — RateStore interface
|
||
|
|
│ │ ├── memory.go — in-memory impl (für Tests + Dev)
|
||
|
|
│ │ ├── memory_test.go
|
||
|
|
│ │ └── postgres.go — pgx impl, derzeit Stub
|
||
|
|
│ ├── httpapi/
|
||
|
|
│ │ ├── rates.go — Handler
|
||
|
|
│ │ └── rates_test.go — Handler-Tests gegen in-memory store
|
||
|
|
│ └── attest/
|
||
|
|
│ └── ratechange.go — Signing-Service-Client, derzeit Stub
|
||
|
|
└── web/
|
||
|
|
└── templates/per_diem_rates.html
|
||
|
|
```
|
||
|
|
|
||
|
|
## Lokal bauen (sobald Code vollständig)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd services/admin-api
|
||
|
|
go test ./...
|
||
|
|
# Dev-Modus mit in-memory store, kein Postgres:
|
||
|
|
go run ./cmd/admin-api -store=memory -listen=:8080
|
||
|
|
# Prod-Modus (sobald postgres.go fertig):
|
||
|
|
go run ./cmd/admin-api -store=postgres \
|
||
|
|
-db="postgres://trust:…@trust-postgres:5432/trust?sslmode=verify-full"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Rate Change Attestation (Entwurf)
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"_type": "https://in-toto.io/Statement/v1",
|
||
|
|
"subject": [
|
||
|
|
{ "name": "per_diem_rate/PDR-42", "digest": { "sha256": "<content hash>" } }
|
||
|
|
],
|
||
|
|
"predicateType": "https://basicstack.de/attestations/rate_change/v1",
|
||
|
|
"predicate": {
|
||
|
|
"change_kind": "create",
|
||
|
|
"rate_id": "PDR-42",
|
||
|
|
"country": "DE",
|
||
|
|
"city": null,
|
||
|
|
"currency": "EUR",
|
||
|
|
"full_day": "28.00",
|
||
|
|
"partial_day_min8h": "14.00",
|
||
|
|
"arrival_day": "14.00",
|
||
|
|
"departure_day": "14.00",
|
||
|
|
"valid_from": "2026-01-01",
|
||
|
|
"valid_to": null,
|
||
|
|
"source_regulation": "BMF-Schreiben …",
|
||
|
|
"performed_by": {
|
||
|
|
"iss": "https://auth.basicstack.de",
|
||
|
|
"sub": "user-admin-42",
|
||
|
|
"session_id": "SES-admin-…"
|
||
|
|
},
|
||
|
|
"performed_at": "2026-10-25T18:30:00Z"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Signiert vom Signing Service, Attestations-Hash wandert zurück in die Tabellen `per_diem_rates.rate_change_attestation_ref` und `per_diem_rate_changes.rate_change_attestation_ref`.
|