Jens Reinemann
045a4b7674
feat: Migration-Safety – Room v7, AutoMigration, Flyway, kein fallbackToDestructiveMigration ( #99 )
...
- fallbackToDestructiveMigration() aus DatabaseModule entfernt
- BollwerkDatabase auf Version 7 gebumpt
- AutoMigration(from=5, to=6) und (from=6, to=7) definiert
- MigrationTestHelper-Test migrate6To7_preservesData implementiert
- 7.json Schema-Export generiert
- Server: Flyway 9.22.3 integriert (baselineOnMigrate=true)
- V1__initial_schema.sql + V2__cleanup_user_id.sql angelegt
- Skill android-db-migration erstellt
- versionCode 5 / versionName 1.4
2026-05-17 21:17:24 +02:00
Jens Reinemann
a5f89e6a69
rename: Krisenvorrat -> Bollwerk
...
- Package: de.krisenvorrat.* -> de.bollwerk.*
- Klassen: KrisenvorratApp/Database/Theme -> Bollwerk*
- ApplicationId: de.bollwerk.app
- Server: BOLLWERK_* Env-Vars, bollwerk HOCON-Config
- Docker: bollwerk-server/db/backup Container-Namen
- Room DB: bollwerk.db, SharedPrefs: bollwerk_secure_prefs
- Export-Dateien: bollwerk_export/inventar
- UI-Strings, HTML, Admin-UI: alle auf Bollwerk
- Docs, Skills, README angepasst
- Alle Tests gruen, Build erfolgreich
2026-05-17 17:44:02 +02:00
Jens Reinemann
7c17f8ea2f
feat(server): Rate-Limiting auf alle API-Endpoints
...
Ktor RateLimit-Plugin mit abgestuften Limits pro Endpoint-Gruppe:
- Auth (/api/auth/*): 10 req/min per IP (Brute-Force-Schutz)
- Messages (/api/messages/*): 30 req/min per IP (Spam-Schutz)
- Inventory (/api/inventory/*): 60 req/min per IP (DoS-Schutz)
- Admin (/api/admin/*): 20 req/min per IP
Neue Dateien:
- RateLimiting.kt: Plugin-Konfiguration mit 4 benannten Limitern
- RateLimitingTest.kt: 5 Tests (Limit-Ueberschreitung, Within-Limit,
Health-Endpoint ohne Limit, Retry-After-Header)
Geaenderte Dateien:
- Routing.kt: rateLimit()-Wrapper um Route-Gruppen
- Application.kt: configureRateLimiting() in Plugin-Pipeline
- libs.versions.toml + build.gradle.kts: ktor-server-rate-limit Dep
Closes #75
2026-05-17 03:31:57 +02:00
Jens Reinemann
f792213b1e
refactor(server): H2 durch PostgreSQL ersetzen
...
- DatabaseFactory: HikariCP Connection-Pool fuer PostgreSQL (10 Connections,
REPEATABLE_READ), H2 weiterhin ohne Pool (fuer Tests)
- Dependencies: postgresql-Treiber + HikariCP hinzugefuegt, H2 nur noch
testImplementation
- Migration-SQL: uppercase Tabellennamen auf lowercase normalisiert
(dialect-agnostisch fuer H2 und PostgreSQL)
- docker-compose.yml: PostgreSQL 17 + Krisenvorrat-Server mit DB-Env-Vars
- Env-Var-Konfiguration: KRISENVORRAT_DB_URL, _DB_USER, _DB_PASSWORD,
_DB_DRIVER (Defaults auf PostgreSQL localhost)
- Alle 554 Tests gruen (H2 in-memory fuer Tests beibehalten)
Closes #70
2026-05-17 02:35:08 +02:00
Jens Reinemann
56ac9b1425
feat: Messaging-System mit Offline-First und WebSocket-Push ( #58 )
...
## Server
- Messages-Tabelle (id, sender_id, receiver_id, body, sent_at, delivered_at)
- MessageRepository: save/getUndelivered/getConversation/markDelivered (JOIN statt N+1)
- POST /api/messages, GET /api/messages/{userId}: Nachrichten senden/abrufen
- GET /api/users: User-Liste fuer authentifizierte User (ohne eigenen Account)
- WebSocketManager: notifyNewMessage() + isOnline()
- WebSocketRoutes: unzugestellte Nachrichten bei Reconnect pushen
- LoginResponse: userId + username ergaenzt
- Server-Dependency: kotlinx.serialization fuer shared
## App
- MessageEntity + MessageDao (Room, Migration 3->4)
- KrisenvorratDatabase v4, Migrations.MIGRATION_3_4
- MessageRepositoryImpl: Offline-First (isPending), drain bei WebSocket-Connect
- WebSocketEvent.NewMessage -> MessageDto aus shared
- WebSocketClientImpl: new_message-Event parsen
- AUTH_USER_ID in SettingsKeys, SyncServiceImpl speichert userId bei Login
- UserListScreen + UserListViewModel: User-Liste anzeigen
- ChatScreen + ChatViewModel: WhatsApp-Style Chat (links/rechts, Zeitstempel)
- Navigation: Screen.UserList, Screen.Chat, MESSAGES in Bottom-Nav
- RepositoryModule: MessageRepository gebunden
## Tests
- 234 Tests, 0 Fehler
2026-05-16 23:35:25 +02:00
Jens Reinemann
14631c7327
feat(server): User-Konzept Auth, JWT, Admin-CRUD, WebSocket-Push, Admin-UI ( #57 )
...
- Users-Tabelle mit bcrypt-Passwort-Hash
- JWT-Auth (Access + Refresh Token) ersetzt API-Key
- POST /api/auth/login + /api/auth/refresh
- Admin-Endpoints: GET/POST/DELETE/PUT /api/admin/users
- Seed-Admin beim Start (KRISENVORRAT_ADMIN_PASSWORD)
- Inventar-Endpoints user-spezifisch (userId aus JWT)
- PATCH /api/inventory/items/{id} fuer Einzel-Updates
- WebSocket /ws/sync mit Push-Events (inventoryUpdated, fullSyncRequired)
- Minimale Admin-Web-UI unter /admin/ (XSS-sicher)
- Categories/Locations: Surrogate-PK fuer User-Isolation
- Alle Server-Tests gruen (43 Tests)
2026-05-16 19:28:03 +02:00
Jens Reinemann
cb9bd2bdf4
feat(server): add API-Key authentication for REST endpoints
...
server/plugins/Authentication.kt:
- Custom Ktor AuthenticationProvider supporting both X-API-Key header
and Authorization: Bearer <key> for API-Key validation
- ApiKeyPrincipal data class implementing Principal interface
- 401 Unauthorized with ErrorResponse body for missing/invalid keys
server/plugins/Routing.kt:
- Inventory routes wrapped in authenticate(api-key) block
- Health endpoint remains public (no auth required)
server/src/main/resources/application.conf:
- API key configurable via krisenvorrat.apiKey property
- Environment variable override via KRISENVORRAT_API_KEY
server/tests:
- 7 new AuthenticationTest cases (valid bearer, valid X-API-Key,
missing key, invalid bearer, invalid X-API-Key, PUT without key,
health without key)
- All existing ApplicationTest cases updated with bearer auth header
Closes #43
2026-05-14 20:50:16 +02:00
Jens Reinemann
5974144621
feat(server): add REST-API endpoints for inventory sync & CRUD
...
server/src/main/kotlin/.../routes/InventoryRoutes.kt:
- GET /api/inventory: returns full inventory as JSON
- PUT /api/inventory: full-sync replaces entire server inventory
server/src/main/kotlin/.../plugins/StatusPages.kt:
- Structured error handling via Ktor StatusPages plugin
- BadRequestException, SerializationException, IllegalArgumentException → 400
- Unhandled exceptions → 500 with logging
server/src/main/kotlin/.../plugins/CallLogging.kt:
- Request logging via Ktor CallLogging plugin (INFO level)
server/src/main/kotlin/.../model/ErrorResponse.kt:
- Serializable error response DTO (status + message)
server/src/main/kotlin/.../plugins/Routing.kt:
- Health endpoint moved from /health to /api/health
- Inventory routes mounted under /api/inventory
server/src/main/kotlin/.../Application.kt:
- Added configurePlugins() for testability (DB init separate)
- StatusPages and CallLogging plugins configured
server/src/test/.../ApplicationTest.kt:
- 8 endpoint tests using Ktor TestApplication with in-memory H2
- Tests: health, 404, empty GET, PUT valid, PUT+GET roundtrip,
invalid JSON → 400, data replacement, JSON content type
Closes #42
2026-05-14 20:30:34 +02:00
Jens Reinemann
2387c6ee5a
feat(server): add Exposed ORM database layer with H2
...
server/db/Tables.kt:
- Exposed table definitions for Categories, Locations, Items, Settings
- Schema mirrors Room entities from app module
- Foreign keys on Items referencing Categories and Locations
server/db/DatabaseFactory.kt:
- H2 file-based DB initialization (jdbc:h2:file:./data/krisenvorrat)
- Parameterized for testability (in-memory DB for tests)
- Schema auto-creation via SchemaUtils.create()
server/repository/InventoryRepository.kt:
- Full CRUD: saveInventory() and loadInventory()
- Atomic replace via transaction (deleteAll + insert)
- Direct mapping between Exposed rows and shared DTOs
4 repository tests with H2 in-memory covering:
- Empty DB, full round-trip, overwrite, nullable fields
Closes #41
2026-05-14 20:15:07 +02:00
Jens Reinemann
cb190e61e9
feat(server): add Ktor server module with health endpoint
...
New Gradle module :server (Kotlin/JVM) with Ktor 3.1.2 framework,
configured as an embedded Netty HTTP server.
server/src/main/kotlin/de/krisenvorrat/server/:
- Application.kt: entry point using EngineMain for HOCON config
- plugins/Routing.kt: GET /health endpoint returning 200 OK
- plugins/Serialization.kt: ContentNegotiation with kotlinx.json
Configuration:
- application.conf (HOCON): host 0.0.0.0, port 8080, module reference
- logback.xml: SLF4J/Logback console logging
Build config:
- server/build.gradle.kts: Ktor plugin with Fat JAR (server.jar)
- libs.versions.toml: Ktor 3.1.2, Logback 1.5.18 dependencies
- settings.gradle.kts: include(:server)
- :server depends on :shared for common DTO models
Tests: 2 tests (health endpoint, 404 on unknown route) via
Ktor testApplication.
Closes #40
2026-05-14 20:06:40 +02:00