ai-assisted-todolist
A browser-based todo list: tasks with due dates, importance and workflow state, private to whoever signed in. Quarkus backend, React + TypeScript frontend, PostgreSQL persistence, OpenID Connect sign-in.
The todo list is not really the point — this repository exists to build up experience with AI-assisted software development. See doc/purpose.md.
How the application fits together#
The backend is a backend-for-frontend: it is the OIDC client, it performs the code exchange itself, and what reaches the browser is an encrypted session cookie rather than a token. One origin, so the SPA needs no CORS handling and no API base URL. architecture.md has the deployment shape and authentication.md the sign-in flow in full.
How a change reaches main#
Anything that can be checked by a machine is, so that a convention does not depend on somebody remembering it. The one deliberate exception is mutation testing, which reports rather than blocks — testing.md says why, and decisions.md records that and every other choice with its reasoning.
Both diagrams are generated: edit doc/images/generate.py and re-run it rather than
touching the SVGs, which exist in a light and a dark variant that must stay in step.
Getting it running#
cd backend && ./mvnw quarkus:dev # starts PostgreSQL and Keycloak for you
cd frontend && npm install && npm run dev
Open http://localhost:5173 and sign in as gunnar / gunnar. Nothing else to install
and no credentials to obtain — doc/local-development.md has the
details, the second local account, the container stacks and the troubleshooting.
Documentation#
doc/ is the source of truth; this page is the entry point. Each page answers one
question, so start from the question rather than the filename.
Understanding it
| purpose.md | Why does this repository exist, and why is it built the way it is? |
| architecture.md | What are the pieces, how does a request travel, how is it deployed? |
| domain-model.md | What is a Task, and where is each invariant enforced? |
| authentication.md | How does sign-in work, and why is the backend the OIDC client? |
Working on it
| local-development.md | How do I run it, and what do I do when it misbehaves? |
| testing.md | What is tested where, and which checks can fail my build? |
| releasing.md | How do I cut a release, and what does it publish? |
| deployment.md | Where will this run on AWS, who may change it, and what does it cost? |
| decisions.md | Why is it like this — and what was tried and rejected? |
decisions.md is the one worth reading before changing anything structural: several
settings in this repository look removable and are not, and it says which and why.
Code-level documentation lives in the code, as Javadoc and TSDoc. The conventions are in backend/CLAUDE.md and frontend/CLAUDE.md, and the backend build enforces them.
Repository layout#
backend/— Quarkus REST API, published asquay.io/ghilling/todo-backendfrontend/— React + TypeScript SPA, published asquay.io/ghilling/todo-frontende2e/— Playwright browser tests driving the whole stack through a real sign-inkeycloak/— realm export with the local test accounts, shared by Dev Services and CIdeployment/— everything that deploys the app:docker/for the Compose stacks,aws-tofu/for the AWS infrastructure as OpenTofudoc/— project documentation, includingdoc/api/: the generated wire contract.github/workflows/— CI for backend, frontend, end-to-end, SonarCloud and publication
API#
All endpoints require a session except /api/auth/providers.
| Method | Path | |
|---|---|---|
GET |
/api/tasks |
the caller's tasks, by due date |
POST |
/api/tasks |
create |
PUT |
/api/tasks/{id} |
replace |
DELETE |
/api/tasks/{id} |
delete |
GET |
/api/auth/providers |
sign-in options |
GET |
/api/auth/login /logout /me |
session |
A task has a description, a due date, an importance (LOW, MEDIUM, HIGH) and a state
(TODO, WORKING, DONE). OpenAPI is at /q/openapi, Swagger UI at /q/swagger-ui,
Prometheus metrics at /q/metrics.
CI/CD#
backend-ci.yml— backend tests, JVM packaging, container image buildfrontend-ci.yml— install, lint, build, frontend image builde2e.yml— builds both images, starts the full stack, runs the Playwright suitesonarcloud.yml— onmainonly: both test suites with coverage, the Sonar scan, and the quality gate, a failure of which opens a GitHub issuepublish-images.yml— publishes both images to Quay aslatestfrommaincodeql.yml— CodeQL security scanning for Java and TypeScript, plus a weekly runrelease.yml— on av*tag: release checks, versioned images, a GitHub Release
Image publication needs these repository secrets:
QUAY_ROBOT_USER(preferred) orQUAY_USERNAMEQUAY_ROBOT_PASSWORD/QUAY_ROBOT_TOKEN(preferred) orQUAY_PASSWORD
Production Google credentials are supplied through environment variables and never checked
in; .env.example lists them.
Releases#
git tag v1.0.0 && git push origin v1.0.0
That is the whole procedure. No version is written down anywhere else: the backend's
pom.xml carries ${revision}, which the release build overrides from the tag, and the
frontend package is private and never published. release.yml then refuses SNAPSHOT and
pre-release dependencies, runs both suites, publishes quay.io/ghilling/todo-backend:1.0.0
and todo-frontend:1.0.0, and opens a GitHub Release. Details, including why latest is
not moved, are in doc/releasing.md.
Dependencies#
Renovate opens the update pull requests, configured in .github/renovate.json. Patch and
minor updates merge themselves once every check on the pull request is green; major updates
wait for a human. The dependency dashboard issue lists everything outstanding.
License#
Apache License 2.0 — see LICENSE.
Copyright 2026 Gunnar Hilling.