Skip to content

Milestone 1: Go API + React 19 SPA + compose scaffold - #2

Merged
Exonical merged 1 commit into
mainfrom
devin/1779173699-milestone-1-scaffold
May 19, 2026
Merged

Exonical merged 1 commit into
mainfrom
devin/1779173699-milestone-1-scaffold

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

Lands the next baseline behind Milestone 0's docs site: a Go API, a
React 19 + shadcn/ui SPA, a docker-compose stack, and CI for both.
Stubs only — real /api/v1 handlers (from the upstream OpenAPI spec)
and the Postgres schema arrive in Milestones 2–4.

api/ — Go 1.25 backend

  • Module github.com/Exonical/stig-manager-react/api.
  • chi router with RequestID / RealIP / Recoverer / Timeout
    middleware and go-chi/cors.
  • Scaffold endpoints behind /api/v1: op/appinfo, op/appdata/tables.
  • /health liveness probe.
  • log/slog JSON handler + graceful shutdown on SIGINT/SIGTERM.
  • pgx v5 pool helper in internal/store (no connection at startup
    during the scaffold; real schema + queries arrive in Milestone 2).
  • go test ./... covers the three scaffold handlers.
  • Multi-stage distroless Dockerfile.

web/ — React 19 SPA

  • Vite 6 + React 19 + TypeScript (strict) + path alias @/*.
  • Tailwind CSS v4 via @tailwindcss/vite with a shadcn-flavoured theme
    (oklch palette, dark/light tokens in src/styles/globals.css).
  • shadcn/ui Button + Card scaffolded as project-local components.
    buttonVariants is extracted to its own module so
    react-refresh/only-export-components stays clean.
  • Theme toggle and a landing page that exercises
    GET /api/v1/op/appinfo through the Vite dev proxy.
  • ESLint flat config + Prettier.
  • Multi-stage Dockerfile: builds the SPA, serves via nginx, proxies
    /api/* to the Go API in the compose network.

deploy/ — local stack

  • docker-compose.yaml: Postgres 18 + Keycloak 26 + api + web.
  • Keycloak realm import (deploy/keycloak/stigman-realm.json) with the
    stig-manager SPA client, OIDC scopes matching upstream
    (stig-manager:collection, :stig, :user, :op + :read
    variants), and demo users admin / evaluator.

CI

  • .github/workflows/web.yaml — lint → typecheck → build → artifact.
  • .github/workflows/api.yaml — vet → test (-race) → build → artifact.
  • .github/workflows/docs.yaml — updated to use the new root lockfile.

pnpm workspace

  • Re-introduces pnpm-workspace.yaml (docs, web).
  • Single pnpm-lock.yaml at the repo root, replacing
    docs/pnpm-lock.yaml.

Review & Testing Checklist for Human

  • Run the compose stack —
    docker compose -f deploy/compose/docker-compose.yaml up -d --build
    and confirm the SPA on http://localhost:54000 loads, the
    Keycloak admin console on http://localhost:8080 opens, and the
    API answers curl -s http://localhost:54001/health.
  • Confirm the SPA → API wire — click "Fetch app info" on the
    landing page and verify the version JSON renders. The Vite dev
    server proxies /api/* through to :54001.
  • Confirm theme + structure — toggle dark/light, scan the
    three demo cards, and check the layout looks clean at both
    desktop and mobile widths.
  • CI is the floor, not the ceiling — green workflows mean the
    app compiles and /api/v1/op/appinfo returns the right JSON,
    but they don't exercise the compose stack, the Keycloak realm
    import, or any real persistence. The compose smoke test above
    is the meaningful check.

Test plan

# 1. JS workspace
pnpm install
pnpm --filter @stig-manager-react/web lint
pnpm --filter @stig-manager-react/web typecheck
pnpm --filter @stig-manager-react/web build
pnpm --filter docs build

# 2. Go API
cd api
go vet ./...
go test ./... -race -count=1
go run ./cmd/stigman          # listens on :54001
curl -s http://localhost:54001/health
curl -s http://localhost:54001/api/v1/op/appinfo | jq

# 3. Integrated stack
docker compose -f deploy/compose/docker-compose.yaml up -d --build
# SPA       http://localhost:54000
# API       http://localhost:54001
# Keycloak  http://localhost:8080  (admin / admin)
docker compose -f deploy/compose/docker-compose.yaml down

Notes

  • Postgres is provisioned by compose but the API is not yet
    connecting on startup — that lands in Milestone 2 along with the
    goose-managed baseline schema. The pgx pool helper is already
    factored into internal/store so wiring it is a small, isolated
    diff.
  • Auth is similarly staged: the Keycloak realm + client + scopes
    are imported, but the SPA does not yet do an OIDC PKCE flow and the
    API does not yet verify tokens. That's Milestone 3, where it lands
    end-to-end (login → token → scope-checked handler).
  • Workspace structure — Milestone 0 had a CI hiccup around
    workspace mode. This PR re-introduces it correctly: workspace file
    at the root, single lockfile at the root, and the docs workflow has
    been updated alongside. Both pnpm --filter docs build and
    pnpm --filter @stig-manager-react/web build succeed from a clean
    install locally.
  • Versions — Node 22 + pnpm 9 are pinned in CI. Go is pinned to
    1.25.4 because pgx/v5@v5.9.2 requires Go ≥ 1.25.
  • OpenAPI — this PR does not regenerate handlers from the spec; the
    scaffold endpoints are hand-rolled so the diff stays small and
    understandable. Milestone 2 plugs in oapi-codegen and replaces
    them with generated stubs.

Link to Devin session: https://app.devin.ai/sessions/022810763c4643c0848ba894c1512b92
Requested by: @Exonical

Adds the next baseline behind Milestone 0's docs site:

api/
  - Go 1.25 module github.com/Exonical/stig-manager-react/api
  - chi router with RequestID / RealIP / Recoverer / Timeout + CORS
  - Scaffold endpoints behind /api/v1: op/appinfo, op/appdata/tables
  - /health liveness probe
  - log/slog JSON handler + graceful shutdown on SIGINT/SIGTERM
  - pgx v5 pool helper in internal/store (no connection at startup;
    real schema + queries arrive in Milestone 2)
  - go test ./... covers the three scaffold handlers
  - Multi-stage distroless Dockerfile

web/
  - Vite 6 + React 19 + TypeScript (strict) + path alias @/*
  - Tailwind CSS v4 (@tailwindcss/vite) with shadcn-flavoured theme
    tokens (oklch palette, dark/light)
  - shadcn/ui Button + Card scaffolded as project-local components
    (variants extracted to a separate module so react-refresh stays clean)
  - Theme toggle, landing page that exercises GET /api/v1/op/appinfo
    through the Vite dev proxy
  - ESLint flat config + Prettier
  - Multi-stage Dockerfile that serves the built SPA via nginx and
    proxies /api/* to the Go API in the compose network

deploy/
  - docker-compose stack: Postgres 18 + Keycloak 26 + api + web
  - Keycloak realm import with the stig-manager SPA client, OIDC
    scopes matching upstream (collection / stig / user / op + :read
    variants), and demo users (admin / evaluator)

ci/
  - .github/workflows/web.yaml: lint, typecheck, build, artifact
  - .github/workflows/api.yaml: vet, test (-race), build, artifact
  - .github/workflows/docs.yaml updated to use the new root lockfile

pnpm workspace:
  - pnpm-workspace.yaml (docs, web) and a single pnpm-lock.yaml at
    the repo root, replacing docs/pnpm-lock.yaml

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Bryce Anglin <brycemanglin@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@Exonical
Exonical merged commit e0dfa53 into main May 19, 2026
4 checks passed
@Exonical
Exonical deleted the devin/1779173699-milestone-1-scaffold branch May 19, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant