diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..957ef8c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.git +.gitea +docs +node_modules +**/node_modules +**/*.log +tmp +dist diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index cd385c5..f402da9 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: "1.22.x" + go-version: "1.25.x" - name: Go tests run: go test ./... diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a0ff140 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# syntax=docker/dockerfile:1.7 + +FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /src + +RUN apt-get update && apt-get install -y --no-install-recommends \ + git ca-certificates && rm -rf /var/lib/apt/lists/* + +COPY go.mod ./ +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY . . +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \ + go build -p "$(nproc)" -trimpath -ldflags="-s -w" -o /out/api ./cmd/api + +FROM gcr.io/distroless/static-debian12:nonroot + +WORKDIR /app +COPY --from=builder /out/api /app/api + +ENV ADDR=:8080 +EXPOSE 8080 + +ENTRYPOINT ["/app/api"] diff --git a/README.md b/README.md index 94f329b..3f804fa 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,26 @@ Optional environment variables: - `ADDR` (default `:8080`) - `ADMIN_PUBLIC_KEY` (bootstrap initial inviter/admin user) +## Docker Compose + +Build and run the backend service: + +```bash +docker compose up --build -d +``` + +Stop the service: + +```bash +docker compose down +``` + +For local development with auto-rebuild on file changes: + +```bash +docker compose up --watch +``` + ## Frontend Open `web/index.html` through a static server (recommended) or browser file URL. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d3658f2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +services: + api: + build: + context: . + dockerfile: Dockerfile + image: momswap-backend:latest + container_name: momswap-backend-api + environment: + ADDR: ":8080" + ADMIN_PUBLIC_KEY: "${ADMIN_PUBLIC_KEY:-}" + ports: + - "8080:8080" + restart: unless-stopped + develop: + watch: + - action: rebuild + path: . diff --git a/docs/geo-auth-backend-plan.md b/docs/geo-auth-backend-plan.md index 8c512a3..02eaa67 100644 --- a/docs/geo-auth-backend-plan.md +++ b/docs/geo-auth-backend-plan.md @@ -36,7 +36,7 @@ isProject: false ## Current Project Context -- No existing backend source files were found in `/home/ano/projects/produktor.io/tenerife.baby/backend`, so this plan assumes a greenfield implementation in that directory. +- No existing backend source files were found in this repository root, so this plan assumes a greenfield implementation. - Stack confirmed: **Go + PostgreSQL (+ PostGIS)**. - Invitation model confirmed: **Hybrid** (signed token + inviter lineage tracking). - Client scope confirmed: **both** a reusable TS library and a plain JS frontend integration. @@ -72,31 +72,31 @@ flowchart TD ## Planned Files and Components - Backend bootstrap: - - `/home/ano/projects/produktor.io/tenerife.baby/backend/cmd/api/main.go` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/http/routes.go` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/config/config.go` + - `cmd/api/main.go` + - `internal/http/routes.go` + - `internal/config/config.go` - Auth/invitation domain: - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/auth/challenge.go` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/auth/ed25519_verify.go` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/invite/token.go` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/invite/service.go` + - `internal/auth/challenge.go` + - `internal/auth/ed25519_verify.go` + - `internal/invite/token.go` + - `internal/invite/service.go` - Geo domain: - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/geo/collections_service.go` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/internal/geo/features_service.go` + - `internal/geo/collections_service.go` + - `internal/geo/features_service.go` - Database: - - `/home/ano/projects/produktor.io/tenerife.baby/backend/migrations/0001_init_users_invites.sql` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/migrations/0002_geo_collections_features.sql` + - `migrations/0001_init_users_invites.sql` + - `migrations/0002_geo_collections_features.sql` - Frontend (no npm/bundling): - - `/home/ano/projects/produktor.io/tenerife.baby/backend/web/index.html` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/web/app.js` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/web/api.js` + - `web/index.html` + - `web/app.js` + - `web/api.js` - Reusable TypeScript client library (separate package): - - `/home/ano/projects/produktor.io/tenerife.baby/backend/libs/geo-api-client/package.json` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/libs/geo-api-client/tsconfig.json` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/libs/geo-api-client/src/GeoApiClient.ts` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/libs/geo-api-client/src/keys.ts` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/libs/geo-api-client/src/storage.ts` - - `/home/ano/projects/produktor.io/tenerife.baby/backend/libs/geo-api-client/dist/` (build output consumed by frontend) + - `libs/geo-api-client/package.json` + - `libs/geo-api-client/tsconfig.json` + - `libs/geo-api-client/src/GeoApiClient.ts` + - `libs/geo-api-client/src/keys.ts` + - `libs/geo-api-client/src/storage.ts` + - `libs/geo-api-client/dist/` (build output consumed by frontend) ## API Surface (v1) diff --git a/go.mod b/go.mod index d8f9b89..1727ac3 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module momswap/backend -go 1.22.2 +go 1.25