Remove nginx/webapp container; single Go server serves SPA + API
- Add root Dockerfile: node build → copy dist into Go embed path → distroless binary - Update docker-compose: one service (api on :9050), DB renamed ralph→pamietnik - Remove references to RALPH/reisejournal across all docs and configs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ name: code-reviewer
|
||||
description: Prüft Codequalität, Lesbarkeit und Konsistenz. Vor Commits einsetzen.
|
||||
---
|
||||
|
||||
Du bist Code-Reviewer für das Projekt Pamietnik (RALPH).
|
||||
Du bist Code-Reviewer für das Projekt Pamietnik.
|
||||
|
||||
## Checkliste Go (Backend)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ name: dokumentar
|
||||
description: Pflegt Markdown-Dokumentation und Mermaid-Diagramme. Bei neuen Features, Architekturänderungen oder wenn Doku und Code auseinanderlaufen.
|
||||
---
|
||||
|
||||
Du bist Dokumentar für das Projekt Pamietnik (RALPH).
|
||||
Du bist Dokumentar für das Projekt Pamietnik.
|
||||
|
||||
## Zu pflegende Dokumente
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ name: programmierer
|
||||
description: Schreibt und ändert Code für Features und Bug-Fixes. Für Go-Backend und Android/Kotlin. Einsetzen bei konkreten Implementierungsaufgaben.
|
||||
---
|
||||
|
||||
Du bist Programmierer für das Projekt Pamietnik (RALPH).
|
||||
Du bist Programmierer für das Projekt Pamietnik.
|
||||
|
||||
## Stack
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ name: security-reviewer
|
||||
description: Prüft OWASP Top 10, Dependency-Schwachstellen und Secrets. Vor Releases und bei Änderungen an externen APIs oder Auth-Code einsetzen.
|
||||
---
|
||||
|
||||
Du bist Security-Reviewer für das Projekt Pamietnik (RALPH).
|
||||
Du bist Security-Reviewer für das Projekt Pamietnik.
|
||||
|
||||
## Prüf-Befehle
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ name: software-architekt
|
||||
description: Analysiert Struktur, Abhängigkeiten und Architekturentscheidungen. Einsetzen vor größeren Änderungen, neuen Modulen oder wenn Komponenten-Grenzen unklar sind.
|
||||
---
|
||||
|
||||
Du bist Software-Architekt für das Projekt Pamietnik (RALPH): Go-Backend + Android-App (Kotlin/Compose).
|
||||
Du bist Software-Architekt für das Projekt Pamietnik: Go-Backend + Android-App (Kotlin/Compose).
|
||||
|
||||
## Deine Aufgaben
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ name: tester
|
||||
description: Schreibt und führt Unit- und Integrationstests aus. Nach jeder Code-Änderung einsetzen.
|
||||
---
|
||||
|
||||
Du bist Tester für das Projekt Pamietnik (RALPH).
|
||||
Du bist Tester für das Projekt Pamietnik.
|
||||
|
||||
## Test-Befehle
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
**Pamietnik** (Codename: RALPH) is a life/travel journal consisting of three components:
|
||||
**Pamietnik** is a life/travel journal consisting of three components:
|
||||
- `app/` — Android app (Kotlin + Jetpack Compose)
|
||||
- `backend/` — Go REST API + server-side rendered Web UI
|
||||
- `README.md` — single source of truth for architecture, requirements, and backlog
|
||||
@@ -28,7 +28,7 @@ go run ./cmd/server # starts API on :8080 (default)
|
||||
```
|
||||
|
||||
**Env vars** (with defaults):
|
||||
- `DATABASE_URL` — `postgres://ralph:ralph@localhost:5432/ralph?sslmode=disable`
|
||||
- `DATABASE_URL` — `postgres://pamietnik:pamietnik@localhost:5432/pamietnik?sslmode=disable`
|
||||
- `LISTEN_ADDR` — `:8080`
|
||||
- `UPLOAD_DIR` — `./uploads`
|
||||
|
||||
@@ -93,7 +93,7 @@ cd app
|
||||
### Android Architecture
|
||||
|
||||
```
|
||||
de.jacek.reisejournal/
|
||||
de.jacek.pamietnik/
|
||||
domain/ Trackpoint domain model
|
||||
data/ Room entities, DAOs, local DB
|
||||
service/ Background location foreground service
|
||||
|
||||
24
Dockerfile
Normal file
24
Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
||||
# Stage 1: Build Vite SPA
|
||||
FROM node:22-alpine AS webapp-builder
|
||||
WORKDIR /webapp
|
||||
COPY webapp/package.json webapp/package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY webapp/ ./
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Build Go server
|
||||
FROM golang:1.25-alpine AS go-builder
|
||||
WORKDIR /app
|
||||
COPY backend/go.mod backend/go.sum ./
|
||||
RUN go mod download
|
||||
COPY backend/ ./
|
||||
# Inject built SPA into embed path
|
||||
COPY --from=webapp-builder /webapp/dist ./internal/api/webapp/
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /server ./cmd/server
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /createuser ./cmd/createuser
|
||||
|
||||
# Stage 3: Minimal runtime image
|
||||
FROM gcr.io/distroless/static-debian12
|
||||
COPY --from=go-builder /server /server
|
||||
COPY --from=go-builder /createuser /createuser
|
||||
ENTRYPOINT ["/server"]
|
||||
@@ -497,7 +497,7 @@ Nachteile:
|
||||
|
||||
Widerruf/Revocation, Rotation und Lebensdauer-Management erhöhen Komplexität.
|
||||
|
||||
Empfehlung für RALPH
|
||||
Empfehlung für Pamietnik
|
||||
Website: Session Cookie.
|
||||
|
||||
JWT optional später, falls API-first/SSO nötig wird.
|
||||
|
||||
@@ -7,11 +7,11 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "de.jacek.reisejournal"
|
||||
namespace = "de.jacek.pamietnik"
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "de.jacek.reisejournal"
|
||||
applicationId = "de.jacek.pamietnik"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal
|
||||
package de.jacek.pamietnik
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
@@ -11,6 +11,6 @@ class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("de.jacek.reisejournal", appContext.packageName)
|
||||
assertEquals("de.jacek.pamietnik", appContext.packageName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package de.jacek.reisejournal
|
||||
package de.jacek.pamietnik
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import de.jacek.reisejournal.ui.navigation.NavGraph
|
||||
import de.jacek.reisejournal.ui.theme.RalphTheme
|
||||
import de.jacek.pamietnik.ui.navigation.NavGraph
|
||||
import de.jacek.pamietnik.ui.theme.RalphTheme
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal
|
||||
package de.jacek.pamietnik
|
||||
|
||||
import android.app.Application
|
||||
import androidx.hilt.work.HiltWorkerFactory
|
||||
@@ -7,7 +7,7 @@ import dagger.hilt.android.HiltAndroidApp
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltAndroidApp
|
||||
class RalphApp : Application(), Configuration.Provider {
|
||||
class PamietnikApp : Application(), Configuration.Provider {
|
||||
|
||||
@Inject
|
||||
lateinit var workerFactory: HiltWorkerFactory
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal.domain
|
||||
package de.jacek.pamietnik.domain
|
||||
|
||||
data class Trackpoint(
|
||||
val eventId: String, // UUID, client-generated
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal.ui.home
|
||||
package de.jacek.pamietnik.ui.home
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -16,7 +16,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import de.jacek.reisejournal.R
|
||||
import de.jacek.pamietnik.R
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal.ui.home
|
||||
package de.jacek.pamietnik.ui.home
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package de.jacek.reisejournal.ui.navigation
|
||||
package de.jacek.pamietnik.ui.navigation
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import de.jacek.reisejournal.ui.home.HomeScreen
|
||||
import de.jacek.pamietnik.ui.home.HomeScreen
|
||||
|
||||
const val HOME_ROUTE = "home"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal.ui.theme
|
||||
package de.jacek.pamietnik.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal.ui.theme
|
||||
package de.jacek.pamietnik.ui.theme
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal.ui.theme
|
||||
package de.jacek.pamietnik.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.jacek.reisejournal
|
||||
package de.jacek.pamietnik
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.Assert.*
|
||||
|
||||
@@ -25,5 +25,5 @@ dependencyResolutionManagement {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "reisejournal"
|
||||
rootProject.name = "pamietnik"
|
||||
include(":app")
|
||||
|
||||
2
backend
2
backend
Submodule backend updated: 55d2ffc203...d97196790d
@@ -2,7 +2,7 @@
|
||||
|
||||
## 1. Einführung und Ziele
|
||||
|
||||
**Pamietnik** (Codename RALPH) ist ein persönliches Lebens- und Reisejournal bestehend aus drei Komponenten: einer Android-App, einer Web-App und einem Go-Backend-Server.
|
||||
**Pamietnik** ist ein persönliches Journal bestehend aus drei Komponenten: einer Android-App, einer Web-App und einem Go-Backend-Server.
|
||||
|
||||
### Fachliches Zielbild
|
||||
|
||||
@@ -194,7 +194,7 @@ backend/
|
||||
### Ebene 2 — Android-Pakete
|
||||
|
||||
```
|
||||
app/app/src/main/kotlin/de/jacek/reisejournal/
|
||||
app/app/src/main/kotlin/de/jacek/pamietnik/
|
||||
├── domain/ Trackpoint Domain Model
|
||||
├── data/ Room Entities, DAOs, lokale DB
|
||||
├── service/ Background Location Foreground Service
|
||||
|
||||
@@ -2,34 +2,30 @@ services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: ralph
|
||||
POSTGRES_PASSWORD: ralph
|
||||
POSTGRES_DB: ralph
|
||||
POSTGRES_USER: pamietnik
|
||||
POSTGRES_PASSWORD: pamietnik
|
||||
POSTGRES_DB: pamietnik
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ralph"]
|
||||
test: ["CMD-SHELL", "pg_isready -U pamietnik"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
api:
|
||||
build: ./backend
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "9050:8080"
|
||||
environment:
|
||||
DATABASE_URL: postgres://ralph:ralph@postgres:5432/ralph?sslmode=disable
|
||||
DATABASE_URL: postgres://pamietnik:pamietnik@postgres:5432/pamietnik?sslmode=disable
|
||||
LISTEN_ADDR: :8080
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
webapp:
|
||||
build: ./webapp
|
||||
ports:
|
||||
- "9050:80"
|
||||
depends_on:
|
||||
- api
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Pamietnik Webapp
|
||||
|
||||
Eigenständige Single-Page-Application für das Pamietnik-Reisejournal. Kommuniziert über REST mit dem Go-Backend.
|
||||
Eigenständige Single-Page-Application für das Pamietnik. Kommuniziert über REST mit dem Go-Backend.
|
||||
|
||||
## Technologie
|
||||
|
||||
|
||||
@@ -2,6 +2,16 @@ server {
|
||||
listen 80;
|
||||
|
||||
# API und Auth-Endpunkte zum Backend proxieren
|
||||
location /healthz {
|
||||
proxy_pass http://api:8080;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /readyz {
|
||||
proxy_pass http://api:8080;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location /v1/ {
|
||||
proxy_pass http://api:8080;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
@@ -50,9 +50,15 @@ async function get<T>(path: string): Promise<T> {
|
||||
|
||||
export const api = {
|
||||
getDays(from?: string, to?: string): Promise<DaySummary[]> {
|
||||
const params = new URLSearchParams()
|
||||
if (from) params.set('from', from)
|
||||
if (to) params.set('to', to)
|
||||
const now = new Date()
|
||||
const defaultTo = now.toISOString().slice(0, 10)
|
||||
const past = new Date(now)
|
||||
past.setDate(past.getDate() - 90)
|
||||
const defaultFrom = past.toISOString().slice(0, 10)
|
||||
const params = new URLSearchParams({
|
||||
from: from ?? defaultFrom,
|
||||
to: to ?? defaultTo,
|
||||
})
|
||||
return get<DaySummary[]>(`/v1/days?${params}`)
|
||||
},
|
||||
getTrackpoints(date: string): Promise<Trackpoint[]> {
|
||||
|
||||
Reference in New Issue
Block a user