internal/client (new): a typed Go HTTP client for the API - login, register, logout, me, and full CRUD for games/platforms - shared by the TUI and the Fyne GUI so request-building, auth and error handling (an APIError with the HTTP status) live in one tested place instead of being duplicated. 8 tests against an httptest server covering success, 401, 403 and that the token is stored/cleared at the right times. cmd/tui (rewrite): drops the old unauthenticated read-only viewer. Now a login screen (bubbles/textinput) -> a scrollable games table (bubbles/table) with 'r' to refresh, built as an explicit state machine (screenLogin/screenLoading/screenGames) so Update's transitions are testable without a real terminal. 9 tests driving Update() directly. cmd/gui (rewrite): drops raylib for Fyne. Same shape as the TUI - a login form, then a games table, with networking on a goroutine and fyne.Do for the UI updates. The table-cell and login-validation logic are plain functions with no Fyne/display dependency, so they're tested directly (7 tests) rather than needing Fyne's headless test driver. internal/api: tagged every operation (Auth/Platforms/Games/Misc) so the generated OpenAPI spec groups into named services instead of one bucket; api/openapi.json regenerated. Added CORS middleware (wildcard origin, no credentials needed since clients use a bearer token, not the cookie) - needed for the new web client's browser requests to the API's a different origin. web/ (new): an Angular 22 + Material app, API client generated from api/openapi.json via ng-openapi-gen (services: true for per-resource classes - AuthService/GamesService/PlatformsService - instead of one generic Api facade). A Session service holds the token/user as signals, persists the token to localStorage, and is the only thing that calls the generated AuthService; an HttpInterceptorFn attaches the bearer token to every request; a CanActivateFn guard protects /games. Login and Games are standalone, lazy-loaded route components. 21 tests (Vitest, Angular's new default - no browser/Karma needed) covering the service, interceptor, guard and both components, run via `npm test` exactly as CI will call it. Justfile: fixed run-tui/run-gui, which used `go run .../main.go` - broken now that both packages span multiple files, since that only compiles the one named file. Added web-install/web-dev/web-build/web-test. .gitea/workflows/ci.yml (moved from .github, which Gitea doesn't read): on push to main/develop - gofmt, go vet, go build, go test, go mod tidy diff (with the Fyne build's system deps installed), sqlc diff, and the web app's build+test. .gitea/workflows/release.yml (new): on a vX.Y.Z tag, cross-compiles api+tui for linux/darwin/windows (amd64+arm64, pure Go, no cgo), builds the Fyne GUI for linux/amd64 only (cgo + its OpenGL/X11 link means it can't cross-compile from one Linux runner the way api/tui do, and this repo has no registered macOS/Windows runner to build it on natively - documented in the workflow's comments), builds the web app, and creates a Gitea release with all of it attached via the Gitea API. Written to Gitea's documented GitHub-Actions-compatible syntax but not executable from here - there's no Gitea server in this environment to run it against, unlike everything else in this commit, which was. Verified: every Go package builds/vets/tests clean; sqlc diff and go mod tidy -diff are clean; the Angular app builds for production and its test suite passes via `npm test`/`npm run build` (the exact commands CI runs), including after a clean `npm ci` from the committed lockfile; the new CORS config was checked with real preflight and GET requests against a running server, not just read. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
96 lines
3.5 KiB
Markdown
96 lines
3.5 KiB
Markdown
# Completed
|
|
|
|
A tracker for a video game collection: what you own, which platform it's on,
|
|
your score for it, and whether (and when) you finished it.
|
|
|
|
## Status
|
|
|
|
Each account has its own private game list, but all accounts share one
|
|
platform list (only an admin can add/rename/delete a platform - the first
|
|
account ever registered becomes an admin automatically). The API is usable.
|
|
There are three small-base clients: a terminal UI, a desktop GUI (Fyne),
|
|
and a web app (Angular) — each can log in and show your games, with more
|
|
to come.
|
|
|
|
## Running it
|
|
|
|
```sh
|
|
just docker-up # starts Postgres and the API on :8080
|
|
just docker-down # stops them
|
|
```
|
|
|
|
Or against a Postgres you already have running locally:
|
|
|
|
```sh
|
|
export DATABASE_URL="postgres://postgres:password@localhost:5432/gamedb?sslmode=disable"
|
|
just run-api
|
|
```
|
|
|
|
The API creates its database and runs migrations on startup if needed.
|
|
Browse `http://localhost:8080/docs` for the generated API docs.
|
|
|
|
## Using the API
|
|
|
|
```sh
|
|
# Register (also logs you in; the first account ever registered becomes
|
|
# an admin, which is required to create platforms - see Status above)
|
|
curl -X POST localhost:8080/api/auth/register -H 'Content-Type: application/json' \
|
|
-d '{"email":"you@example.com","password":"a long password","name":"You"}'
|
|
# -> {"token": "...", "user": {...}}
|
|
|
|
TOKEN=... # the token from above
|
|
|
|
curl -X POST localhost:8080/api/platforms -H "Authorization: Bearer $TOKEN" \
|
|
-H 'Content-Type: application/json' -d '{"name":"PC"}'
|
|
|
|
curl localhost:8080/api/games -H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
A browser-based client can skip the `Authorization` header: register/login
|
|
also set an httpOnly `session` cookie.
|
|
|
|
## Clients
|
|
|
|
- `just run-tui` — a terminal UI (Bubble Tea). Log in, see your games in a
|
|
scrollable table, `r` to refresh.
|
|
- `just run-gui` — a desktop GUI (Fyne). Log in, see your games in a table,
|
|
refresh.
|
|
- `just web-dev` — a web app (Angular + Material) at `http://localhost:4200`,
|
|
proxying nothing itself; it talks directly to the API at `localhost:8080`
|
|
(CORS is permissive enough for local dev as-is). Log in, see your games.
|
|
|
|
All three point at `http://localhost:8080` by default. The TUI and GUI read
|
|
`COMPLETED_API_URL` to use a different API; the web app's URL is a build-time
|
|
constant in `web/src/app/app.config.ts`.
|
|
|
|
Each client is a small base - listing is there, but adding/editing a game
|
|
or managing platforms isn't yet.
|
|
|
|
## Development
|
|
|
|
```sh
|
|
just test # go test ./...
|
|
just sqlc # regenerate internal/db after changing db/query.sql or a migration
|
|
just openapi # regenerate api/openapi.json after changing a route
|
|
just web-test # web app unit tests (Vitest)
|
|
just web-build # production build of the web app
|
|
```
|
|
|
|
Schema changes go in `db/migrations` as a new `<timestamp>_<name>.up.sql` /
|
|
`.down.sql` pair; `sqlc.yaml` reads the schema from that directory directly,
|
|
so there's no separate schema file to keep in sync.
|
|
|
|
The TUI and GUI share `internal/client`, a typed Go HTTP client for the API.
|
|
The web app's API client (`web/src/app/api/`) is generated from
|
|
`api/openapi.json` by `ng-openapi-gen` (`cd web && npx ng-openapi-gen`) and
|
|
shouldn't be hand-edited.
|
|
|
|
## CI/CD
|
|
|
|
`.gitea/workflows/ci.yml` builds and tests everything (Go + web) on every
|
|
push to `main` or `develop`. `.gitea/workflows/release.yml` builds all three
|
|
clients and attaches them to a Gitea release when a `vX.Y.Z` tag is pushed;
|
|
see that file's comments for its one real limitation (the desktop GUI is
|
|
only built for linux/amd64, since it needs cgo and this repo has no
|
|
registered macOS/Windows runner to cross-build it on).
|