⌂ Home
Gemini CLI: From Zero to Production
Capstone Project
4–6 hours All modules Production output
Gemini CLI Capstone

Build a Task Management API

Apply every technique from every track to build and ship a production-ready REST API from scratch — using Gemini CLI at every stage of the software development lifecycle. Requirements to deployment, in one continuous flow.

What You'll Build

A production-grade Task Management API with two implementations — FastAPI (Python) and Express (Node.js/TypeScript) — built entirely using Gemini CLI as your co-pilot at every SDLC phase.

7 SDLC phases
4–6h Estimated time
80% Test coverage target
17 Modules applied

What You're Building

  • Auth: User registration + login with JWT (HS256, 15-minute access tokens, 7-day refresh tokens)
  • Tasks CRUD: Create, read, update, delete tasks with title, description, status (todo/in-progress/done), priority, due date
  • Database: PostgreSQL 16 — SQLAlchemy + Alembic (Python) / Prisma (Node.js)
  • Infrastructure: Docker + docker-compose for local dev, GitHub Actions CI
  • API spec: OpenAPI 3.1 auto-generated and validated
  • Automation: Pre-commit hooks, nightly security audit script

Prerequisites

  • Completed all 17 course modules (M00–M16)
  • Docker Desktop installed and running
  • GitHub account with a new empty repository created
  • Python 3.12+ OR Node.js 22 LTS (choose your stack)
  • GEMINI_API_KEY set in your environment
Before You Start

Create a fresh directory: mkdir taskflow-api && cd taskflow-api. Create a project GEMINI.md with your chosen stack, your GitHub repo URL, and your name. This context will persist across all 7 phases.

Phase 1 · Requirements

1

Generate Requirements Document

Skills from M05

M05

Use Gemini CLI to generate a complete Product Requirements Document. Save the output as REQUIREMENTS.md in your project root.

prompt — Phase 1
Generate a complete Product Requirements Document for a Task Management REST API.

Product: TaskFlow API
Users: Individual developers and small engineering teams (2-10 people)

Include:
1. Executive Summary (3-4 sentences)
2. User Personas (2 personas with goals and pain points)
3. User Stories (minimum 15, in "As a... I want... So that..." format)
4. Acceptance Criteria (for each user story)
5. Non-Functional Requirements (performance, security, scalability)
6. Out of Scope (what this v1 will NOT include)
7. Success Metrics

Output as a well-structured Markdown document I can save as REQUIREMENTS.md.
Phase 1 Deliverable

Copy Gemini's output to REQUIREMENTS.md. Review it — add or remove user stories based on your own judgment. The goal is a document that accurately represents what you're building. Gemini will reference this in every subsequent phase.

  • REQUIREMENTS.md created and saved in project root
  • At least 15 user stories covering auth, tasks, and error cases
  • Acceptance criteria defined for each story
  • Non-functional requirements include response time (<200ms p99) and JWT expiry

Phase 2 · Design

2

Architecture, ERD, and API Contract

Skills from M06

M06

Generate three design artifacts and save them in a docs/ directory.

2a · Entity Relationship Diagram

prompt — ERD (Mermaid)
@REQUIREMENTS.md

Generate a Mermaid ERD for the TaskFlow API database schema.

Tables required: users, tasks, refresh_tokens
Include: all columns with types, primary keys, foreign keys, indexes
Output ONLY the Mermaid code block — save as docs/erd.md

2b · OpenAPI 3.1 Spec

prompt — API contract
@REQUIREMENTS.md

Generate a complete OpenAPI 3.1 specification for the TaskFlow API.

Endpoints:
- POST /auth/register — create user
- POST /auth/login — get JWT tokens
- POST /auth/refresh — refresh access token
- DELETE /auth/logout — invalidate refresh token
- GET /tasks — list tasks (pagination, status filter)
- POST /tasks — create task
- GET /tasks/{id} — get single task
- PATCH /tasks/{id} — update task
- DELETE /tasks/{id} — delete task

Include: request/response schemas with examples, error responses (400, 401, 404, 422, 500), security scheme (Bearer JWT).
Output YAML. Save as docs/openapi.yaml

2c · Architecture Decision Record — Auth Strategy

prompt — ADR
@REQUIREMENTS.md

Write an Architecture Decision Record (ADR) for the JWT authentication strategy.

Format:
# ADR-001: JWT Authentication Strategy
## Status: Accepted
## Context (problem being solved)
## Decision (what we chose and why)
## Considered Alternatives (with pros/cons)
## Consequences (positive and negative)
## Implementation Notes

The decision: HS256 JWT, 15-minute access tokens, 7-day refresh tokens stored in DB for revocation.

Save as docs/ADR-001-auth-strategy.md
  • docs/erd.md contains valid Mermaid ERD with users, tasks, refresh_tokens tables
  • docs/openapi.yaml passes OpenAPI 3.1 validation (use npx @stoplight/spectral-cli lint docs/openapi.yaml)
  • docs/ADR-001-auth-strategy.md written with at least 2 considered alternatives

Phase 3 · Scaffold

3

Generate Full Project Scaffold

Skills from M07

M07
prompt — scaffold (Python / FastAPI)
@REQUIREMENTS.md @docs/openapi.yaml @docs/erd.md

Scaffold a complete FastAPI project for the TaskFlow API.

Stack: Python 3.12, FastAPI, SQLAlchemy 2.0 (async), Alembic, PostgreSQL 16, python-jose for JWT, passlib for passwords, pydantic v2

Generate this directory structure and all files:
- pyproject.toml (dependencies, dev dependencies, pytest config)
- .env.example (all required env vars)
- src/main.py (FastAPI app factory)
- src/config.py (settings with pydantic-settings)
- src/database.py (async engine + session)
- src/models/ (User, Task, RefreshToken SQLAlchemy models)
- src/schemas/ (Pydantic request/response schemas matching openapi.yaml)
- src/routers/ (auth.py and tasks.py with route stubs)
- src/services/ (auth_service.py and task_service.py stubs)
- alembic/ (initial config + first migration)
- tests/ (conftest.py with test DB setup)
- docker-compose.yml (app + postgres services)
- Dockerfile

Use --yolo to create all files. Save a checkpoint when done: /checkpoint save "phase-3-scaffold"
WHAT: This is a Plan Mode prompt — Gemini CLI will create ~20 files. GOTCHA: Review each file Gemini creates before proceeding. Run python -m pytest tests/ --collect-only to verify the test structure is valid before moving to implementation.

Expected Directory Structure

  • docker-compose up -d starts without errors
  • alembic upgrade head applies migration successfully
  • uvicorn src.main:app --reload starts and /docs loads
  • Checkpoint saved: "phase-3-scaffold"

Phase 4 · Implementation

4

Iterative Implementation with Gemini

Skills from M07 — multi-file context loading

M07 M04

Implement each service in two passes: first the auth service, then the task service. Use multi-file context to give Gemini full visibility into your models and schemas.

Implement Auth Service

prompt — auth service implementation
@src/models/user.py @src/models/refresh_token.py @src/schemas/auth.py @docs/ADR-001-auth-strategy.md

Implement src/services/auth_service.py and src/routers/auth.py.

auth_service.py functions:
- register_user(db, schema) → User (hash password with bcrypt, check email uniqueness)
- authenticate_user(db, email, password) → User | None
- create_tokens(user_id) → {access_token, refresh_token, token_type}
- refresh_access_token(db, refresh_token) → {access_token}
- revoke_refresh_token(db, token) → None

auth.py routes:
- POST /auth/register → 201 UserResponse
- POST /auth/login → 200 TokenResponse
- POST /auth/refresh → 200 {access_token}
- DELETE /auth/logout → 204

Requirements:
- All DB operations are async
- Raise HTTPException with correct status codes
- JWT: HS256, SECRET_KEY from config, access_token 15min, refresh_token 7 days
- Store refresh tokens in DB for revocation support
- Every function has a docstring

Implement Task Service

prompt — task service implementation
@src/models/task.py @src/schemas/tasks.py @src/services/auth_service.py @docs/openapi.yaml

Implement src/services/task_service.py and src/routers/tasks.py.

task_service.py functions:
- list_tasks(db, user_id, status?, page, limit) → list[Task] + total count
- create_task(db, user_id, schema) → Task
- get_task(db, user_id, task_id) → Task (raise 404 if not found or wrong user)
- update_task(db, user_id, task_id, schema) → Task
- delete_task(db, user_id, task_id) → None

tasks.py routes:
- GET /tasks → 200 PaginatedTasksResponse
- POST /tasks → 201 TaskResponse
- GET /tasks/{id} → 200 TaskResponse
- PATCH /tasks/{id} → 200 TaskResponse
- DELETE /tasks/{id} → 204

Requirements:
- All routes require Bearer JWT auth (use FastAPI Depends)
- Tasks are scoped to the authenticated user (never return another user's tasks)
- Pagination: page + limit query params, default page=1, limit=20, max limit=100
- Status filter on GET /tasks
- Partial updates on PATCH (only update provided fields)

Phase 5 · Tests

5

Generate Test Suite (≥80% Coverage)

Skills from M08

M08
prompt — test generation
@src/routers/auth.py @src/services/auth_service.py @src/routers/tasks.py @src/services/task_service.py @tests/conftest.py

Generate a comprehensive pytest test suite.

Create:
- tests/test_auth.py — test every auth endpoint
- tests/test_tasks.py — test every task endpoint

For each endpoint test:
1. Happy path (valid input, expected 2xx response)
2. Validation error (invalid input, 422)
3. Auth error (missing/expired token, 401)
4. Not found (invalid ID, 404 where applicable)
5. Edge cases (pagination boundaries, empty results)

Requirements:
- Use pytest-asyncio for async tests
- Use httpx AsyncClient (not Requests)
- Each test function is independent (no shared state)
- Factory functions in conftest.py for user/task creation
- Coverage target: 80% (run with pytest --cov=src --cov-report=term-missing)
  • pytest tests/ -v — all tests pass
  • pytest --cov=src --cov-report=term-missing — coverage ≥ 80%
  • Auth tests cover: register, login, refresh, logout, token expiry
  • Task tests cover: CRUD, pagination, status filter, ownership enforcement

Phase 6 · Deploy

6

Docker + GitHub Actions CI

Skills from M09, M12

M09 M12

Production Dockerfile

prompt — Dockerfile
@pyproject.toml @src/main.py

Generate a production-ready multi-stage Dockerfile for the TaskFlow FastAPI app.

Requirements:
- Stage 1 (builder): install dependencies with pip into /install
- Stage 2 (production): slim Python 3.12-slim base, copy only /install and src/
- Run as non-root user (uid 1000)
- EXPOSE 8000
- CMD: uvicorn src.main:app --host 0.0.0.0 --port 8000 --workers 2
- Health check endpoint: GET /health → 200 {"status": "ok"}
- Final image size target: under 200MB

GitHub Actions CI Workflow

prompt — CI workflow
Generate a GitHub Actions CI workflow for the TaskFlow API.

File: .github/workflows/ci.yml

Triggers: push to main, pull_request to main

Jobs:
1. test:
   - ubuntu-latest
   - Start PostgreSQL service container (postgres:16)
   - Install Python 3.12, install dependencies
   - Run alembic upgrade head
   - Run pytest --cov=src --cov-fail-under=80
   - Upload coverage report to Codecov

2. lint:
   - Run ruff check src/ tests/
   - Run mypy src/ --strict

3. build:
   - Depends on test + lint passing
   - Docker build (verify image builds without errors)
   - Does NOT push to registry (local build only for PR validation)
  • docker build -t taskflow-api:local . succeeds under 200MB
  • docker-compose up — app starts, curl localhost:8000/health returns 200
  • .github/workflows/ci.yml created and pushed — first Actions run passes
  • PR review workflow added from M12 patterns (auto-reviews PRs)

Phase 7 · Automation

7

Hooks + Nightly Automation

Skills from M14, M16

M14 M16

Pre-Commit Hook

prompt — pre-commit hook
Generate a prepare-commit-msg Git hook for this project.

Requirements:
- Works on both Git Bash and PowerShell
- Gets the staged diff with git diff --cached
- Passes diff to Gemini CLI to generate a conventional commit message
- Writes the generated message to the commit message file
- Falls back gracefully if Gemini CLI is unavailable (exits 0 silently)
- Include a launcher script for Windows (.git/hooks/prepare-commit-msg)
  that calls pwsh if available, falls back to bash

Output: both the .ps1 script and the shell launcher file.

Nightly Security Audit Script

prompt — nightly audit
Generate a nightly security audit script for this Python project.

File: scripts/nightly-security-audit.ps1 (and bash equivalent)

Requirements:
- Audit all src/*.py files for OWASP Top 10 issues using Gemini CLI
- Write structured JSON report to logs/security-audit-YYYYMMDD.json
- Exit code 1 if HIGH or CRITICAL issues found
- Suitable for Windows Task Scheduler (reads GEMINI_API_KEY from System env vars)
- Log start time, end time, files scanned, and total findings summary
- Trim log files older than 30 days (keep storage manageable)
  • Pre-commit hook installed: git stage src/main.py && git commit generates a message
  • scripts/nightly-security-audit.ps1 runs without errors on the codebase
  • logs/ directory created, JSON report generated
  • Task Scheduler entry created (optional but recommended)

End-to-End Verification

Run through this verification checklist after completing all 7 phases. Every item should pass before you consider the Capstone complete.

  • docker-compose up -dAll services start healthy. docker-compose ps shows all "Up".
  • alembic upgrade headAll migrations applied. Database has users, tasks, refresh_tokens tables.
  • curl localhost:8000/healthReturns {"status": "ok"} with 200 status.
  • curl localhost:8000/docsOpenAPI UI loads. All 9 endpoints visible with correct schemas.
  • pytest tests/ -vAll tests pass. No skipped tests in the core suite.
  • pytest --cov=srcCoverage ≥ 80% on src/ directory.
  • ruff check src/Zero linting errors.
  • docker build -t taskflow:cap .Build succeeds. docker images taskflow:cap shows image under 200MB.
  • GitHub ActionsCI workflow shows green on main branch. All 3 jobs (test, lint, build) pass.
  • git commit -m "wip"prepare-commit-msg hook fires. Commit message is replaced with AI-generated conventional commit.
  • scripts/nightly-security-audit.ps1Script runs to completion. JSON report written to logs/.
Why This Matters

You've just used Gemini CLI for every single stage of a real software project: requirements, architecture, code, tests, CI, containerization, and automation. This is the AI SDLC in practice — not just using AI for a single task, but as an integrated tool that accelerates every phase of the development lifecycle.

Bonus Challenges

Completed the core Capstone? These three extensions push further into production patterns.

BONUS 1

Add Redis Caching

Add Redis to your docker-compose and implement response caching for GET /tasks. Cache key: tasks:{user_id}:{page}:{limit}:{status}. TTL: 60 seconds. Invalidate on any task mutation. Use Gemini CLI to generate the Redis middleware, add it to your service layer, and generate the corresponding tests. Measure the performance difference with pytest-benchmark.

BONUS 2

Add Rate Limiting

Implement per-user rate limiting: 100 requests/minute per authenticated user, 20 requests/minute for unauthenticated endpoints. Use slowapi (FastAPI) or express-rate-limit (Node.js). Ask Gemini CLI to generate the middleware, configure the limits from environment variables, and write a test that verifies the 429 response and Retry-After header.

BONUS 3

Deploy to Cloud Run

Use Gemini CLI to generate the full Cloud Run deployment: cloudbuild.yaml, Cloud Run service configuration YAML, and a PowerShell deployment script. Ask: "Generate Cloud Run deployment config for the taskflow-api container, using Cloud SQL PostgreSQL as the backend, with secrets managed via Secret Manager for DATABASE_URL and SECRET_KEY." Deploy from the command line using gcloud run deploy.