DevBlog is a guided project from AiCanCode. Over 9 phases (about 33 hours) you build the backend of a multi-author blog like a professional team would: requirements and threats, design, a test-first implementation, CI/CD, containers, observability and a retrospective. AI assistants help you at every step, and you verify everything they produce.
What you build: a REST API where readers register and comment, authors write Markdown posts (drafts, publishing, edits with optimistic locking, soft delete) and admins manage roles and moderate comments. The security is real, not a demo:
- passwords hashed with bcrypt; short-lived JWT access tokens (15 min, HS256 pinned);
- opaque refresh tokens that rotate on every use, stored only as SHA-256 hashes, with reuse detection (a stolen, already-used token revokes the whole session family);
- roles (READER, AUTHOR, ADMIN) and ownership checks; drafts are
404, never403; - errors as RFC 9457
application/problem+json; mass assignment ofroleis impossible.
Readers get a keyset-paginated feed with tag filters and PostgreSQL full-text search. Comments go through AI moderation: a model may only hold a comment for a human, never delete it, and a deterministic rule-based moderator takes over offline. Posts get an AI TL;DR with a template fallback. Both AI features work fully offline; a local Ollama model or a free Gemini/Groq key are optional.
Pick one track: the spec, database, API contract, tests and smoke test are shared. Only the code differs.
| Track | Stack | Folder |
|---|---|---|
| Java | Java 21 · Spring Boot 4 (Web MVC + JDBC) · Spring Security Crypto (BCrypt) · Nimbus JOSE+JWT · JUnit 5 · JaCoCo | tracks/java |
| Python | Python 3.11+ · FastAPI · psycopg 3 · PyJWT · bcrypt · pytest · coverage | tracks/python |
| TypeScript | Node 20+ · Fastify 5 · pg · jose · bcryptjs · Vitest · ESLint |
tracks/typescript |
Why these three tracks? They are the three stacks most often asked for in backend job posts for
juniors, and each teaches the same security ideas with a different amount of "magic": Spring Boot is
the enterprise standard (we deliberately use only spring-security-crypto, not the filter chain, so you
see every check, see ADR-0005), FastAPI is the fastest way to a typed, documented Python API, and
Fastify is a lean, fast Node framework where nothing is hidden. Because the contract and tests are
shared, you can switch tracks later or compare all three.
Course repository: https://github.com/AICanCode-org/blog-rest-api (main = starter, solution = reference).
Everything runs on your laptop with Docker Compose (app + PostgreSQL). Deploying to the cloud is an optional extra in Phase 6 and needs no credit card.
.
├── README.md ← you are here
├── AI_LOG.md ← your log of AI prompts, outputs and how you verified them
├── docs/ ← the course: phase-0 … phase-8 + GitHub Actions explained
├── spec/ ← shared spec: requirements, architecture, ADRs, openapi.yaml, db/
├── tracks/{java,python,typescript}/ ← code + tests (same Makefile targets in each)
├── scripts/ ← doctor.sh, check-all.sh, verify-tags.sh, build-cms.py (+ smoke-test.sh from Phase 6)
├── cms/ ← machine-readable export of the course for the AiCanCode site
├── docker-compose.yml ← PostgreSQL (+ the app per track from Phase 6, optional Ollama)
└── .github/ ← CI/CD workflows, issue/PR templates (+ Dependabot from Phase 5)
You need Git, Docker with Compose v2, make, curl plus the toolchain of one track.
Run scripts/doctor.sh at any time to see what is missing.
| Windows 10/11 | macOS | Linux (Ubuntu/Debian) | |
|---|---|---|---|
| Shell | WSL2 with Ubuntu: wsl --install in an admin PowerShell, reboot |
Terminal (zsh) | any |
| Docker | Docker Desktop, Use the WSL 2 based engine + WSL integration for Ubuntu enabled | Docker Desktop (or Colima) | Docker Engine + docker-compose-plugin; sudo usermod -aG docker $USER, log out/in |
| Git, make, curl | inside WSL: sudo apt install git make curl |
xcode-select --install |
sudo apt install git make curl |
| Java track | inside WSL: SDKMAN → sdk install java 21-tem && sdk install maven |
SDKMAN or brew install openjdk@21 maven |
SDKMAN |
| Python track | inside WSL: sudo apt install python3 python3-venv |
brew install python@3.12 |
sudo apt install python3 python3-venv |
| TypeScript track | inside WSL: nvm → nvm install 22 |
nvm or brew install node@22 |
nvm |
Windows, important: clone and work inside the WSL file system (~/code/blog-rest-api), not under
/mnt/c/.... It is many times faster and avoids line-ending and file-watching problems. VS Code: install
the WSL extension and run code . from the WSL terminal.
Hardware: 8 GB RAM is enough. The optional Ollama model (llama3.2:1b) needs about 2 GB more disk/RAM.
git clone https://github.com/<you>/blog-rest-api.git && cd blog-rest-api # your fork (docs/phase-0-setup.md)
scripts/doctor.sh # check your tools
cp .env.example .env # optional: change ports / AI provider
docker compose up -d postgres # database (also creates devblog_test for the tests)
cd tracks/python # or tracks/java, tracks/typescript
make install # dependencies
make lint test # 1 passing test, the rest are "pending" until Phase 3
make run # http://localhost:8080
curl -s localhost:8080/health # {"status":"UP","checks":{"database":"UP"}}Every track offers the same commands:
| Command | What it does |
|---|---|
make install |
install dependencies (Python: creates .venv) |
make lint |
linter + formatter check (Checkstyle / ruff / ESLint + Prettier + tsc) |
make test |
unit tests (no database needed) |
make test-integration |
integration tests against the devblog_test database |
make coverage |
unit + integration with an 85 % line-coverage gate |
make run |
start the API on port 8080 (with local-only dev defaults for the JWT secret and admin) |
make build |
build the Docker image (from Phase 6) |
From Phase 6 on, the app runs in Docker too: docker compose --profile python up --build
(or --profile java / --profile typescript), then scripts/smoke-test.sh http://localhost:8080.
| Phase | Topic | You end at tag |
|---|---|---|
| 0 | Setup and orientation | phase-0-end |
| 1 | Requirements, threats and user stories | phase-1-end |
| 2 | Design: architecture, auth, DB schema, API contract | phase-2-end |
| 3 | Implementation in five milestones | phase-3-end |
| 4 | Testing: integration, security and concurrency tests, coverage gate | phase-4-end |
| 5 | CI with GitHub Actions | phase-5-end |
| 6 | Containerise, deliver, optional deploy | phase-6-end = v1.0.0 |
| 7 | Observability and maintenance | phase-7-end = v1.1.0 |
| 8 | Retrospective and portfolio | phase-8-end |
Each phase page has the same 8 blocks: Why it matters · Objectives · Step-by-step instructions · AI-assist prompts · Deliverables · Self-check quiz · What you learned · Catch-up git commands.
main: the starter. Tracks have the structure, the full (pending) test suite and/health; the business logic isTODO.solution: the reference implementation, one or more commits per phase, with an annotated tag at the end of every phase:phase-0-end…phase-8-end, plus releasesv1.0.0andv1.1.0. Every tag builds and passes the tests of all three tracks.
Stuck or behind? Jump to the end state of the previous phase and continue from there:
git fetch upstream --tags
git switch -c my-phase-4 phase-3-end # start Phase 4 from the reference end of Phase 3Compare your work with the reference: git diff phase-3-end -- tracks/python.
Peek at a single file: git show phase-3-end:tracks/python/app/auth.py.
Try first, then compare. You learn far more that way.
The complete test suite already exists on main but is switched off in one list per track
(Pending.java, tests/conftest.py, test/pending.ts). In Phase 3 you remove one entry at a time,
watch the tests fail, and make them pass. Skipped tests are reported as skipped, never as passed.
Use any assistant you like. Each phase contains copy-paste prompts and a "Verify the output by"
checklist. Record what you asked and how you checked it in AI_LOG.md. Never paste
secrets, tokens, .env files or personal data into a prompt. Security code gets the strictest review:
an assistant that "simplifies" token verification is the classic way real APIs get broken.
- docs/README.md: index of all docs
- docs/github-actions-explained.md: every CI/CD concept, step by step
- spec/README.md: the shared specification
- CONTRIBUTING.md · CHANGELOG.md · LICENSE (MIT)
Questions or problems: open an issue using the templates, or contact us via https://www.aicancode.org/contact.