RepoPilotOpen in app →

techschool/simplebank

Backend master class: build a simple bank service in Go

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 7 active contributors
  • MIT licensed
  • CI configured
Show all 6 evidence items →
  • Tests present
  • Stale — last commit 1y ago
  • Concentrated ownership — top contributor handles 67% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/techschool/simplebank)](https://repopilot.app/r/techschool/simplebank)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/techschool/simplebank on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: techschool/simplebank

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/techschool/simplebank shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • 7 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 1y ago
  • ⚠ Concentrated ownership — top contributor handles 67% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live techschool/simplebank repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/techschool/simplebank.

What it runs against: a local clone of techschool/simplebank — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in techschool/simplebank | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | Last commit ≤ 412 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>techschool/simplebank</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of techschool/simplebank. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/techschool/simplebank.git
#   cd simplebank
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of techschool/simplebank and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "techschool/simplebank(\\.git)?\\b" \\
  && ok "origin remote is techschool/simplebank" \\
  || miss "origin remote is not techschool/simplebank (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 412 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~382d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/techschool/simplebank"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

A production-grade backend banking service built in Go that demonstrates full-stack development from database design to Kubernetes deployment. It provides REST and gRPC APIs for account management, balance tracking via ledger entries, and inter-account money transfers, with secure token-based authentication (JWT/PASETO) and role-based access control. Monolithic service structure: db/ contains schema migrations (5 versioned SQL files) and sqlc-generated data access code; api/ holds all HTTP handlers and middleware (account, user, transfer, token endpoints); db/query/ defines raw SQL queries that sqlc compiles to type-safe Go code in db/sqlc/. The Makefile orchestrates database setup, migrations, and testing.

👥Who it's for

Go backend engineers and computer science students learning enterprise-level service architecture, particularly those building financial systems or microservices that require transaction guarantees, database isolation levels, and deployment automation.

🌱Maturity & risk

This is an actively maintained educational repository (part of a paid Backend Master Class course). It includes comprehensive unit tests (e.g., db/sqlc/account_test.go, api/account_test.go), automated CI/CD via GitHub Actions in .github/workflows/test.yml and deploy.yml, a Makefile for build automation, and Docker containerization. Verdict: production-ready demonstration codebase with learning intent.

Low technical risk for a learning project: it's self-contained with minimal external dependencies (Gin framework, sqlc for SQL generation, Docker). However, this is a reference implementation, not a library — copying it directly to production requires significant hardening (input validation expansion, audit logging, rate limiting policies). No apparent maintenance risks; the project serves an educational purpose with infrequent updates expected.

Active areas of work

This is a completed course codebase. The repo demonstrates a progression: initial account/entry/transfer tables → user authentication → session management → email verification → role-based access control. The final state includes advanced features like gRPC APIs, background workers, and Swagger documentation mentioned in the README but not fully visible in the file list provided.

🚀Get running

git clone https://github.com/techschool/simplebank.git
cd simplebank
make migrateup
make test
make server

Daily commands:

make migrateup        # Apply all migrations from db/migration/
make test             # Run unit tests across db/ and api/
make server           # Start HTTP server (port inferred from app.env)

🗺️Map of the codebase

  • db/sqlc/store.go: Core transaction handler that wraps database operations with isolation levels and ensures atomicity for money transfers.
  • api/server.go: Initializes the Gin router, registers all HTTP handlers, and wires middleware for the entire API surface.
  • api/middleware.go: Implements JWT/PASETO token extraction and validation for route protection; the security boundary for the service.
  • db/migration/000001_init_schema.up.sql: Defines foundational tables (accounts, entries, transfers) that model the core banking domain.
  • db/sqlc/models.go: Auto-generated Go structs representing database tables; essential for understanding data shapes throughout the codebase.
  • Makefile: Single source of truth for local development tasks (migrations, testing, server startup, Docker builds).
  • .github/workflows/test.yml: Defines the automated test pipeline that runs on every push; shows CI/CD entry point for continuous integration.

🛠️How to make changes

Adding API endpoints: Edit api/account.go, api/user.go, or api/transfer.go and add matching handler functions; create tests in api/*_test.go. Adding database queries: Write SQL in db/query/ files, run make sqlc to auto-generate Go code in db/sqlc/. Schema changes: Create new migration file in db/migration/ (e.g., 000006_add_feature.up.sql), apply with make migrateup. Authentication: Modify api/middleware.go and api/token.go for new token schemes.

🪤Traps & gotchas

app.env required: The service reads app.env for database URL, JWT secret, PASETO key, and server port — ensure this file exists with valid values before running. PostgreSQL must be running: Migrations and tests assume a live PostgreSQL instance (check Makefile for postgres service or Docker setup). sqlc compilation step: Modifying SQL queries in db/query/ requires running make sqlc to regenerate db/sqlc/*.sql.go files — changes won't appear in Go without this. Migration order matters: Migrations execute in numeric order; adding columns to existing tables requires careful sequencing to avoid foreign key constraint violations.

💡Concepts to learn

  • Database Transactions & Isolation Levels — The transfer operation in simplebank must be atomic — either both account balances change or neither does. Understanding Serializable vs. Read Committed isolation prevents race conditions and data corruption in concurrent environments.
  • PASETO (Platform-Agnostic Security Tokens) — The repo uses PASETO instead of JWT for authentication (evident from api/token.go and middleware.go); it addresses JWT vulnerabilities like algorithm confusion attacks.
  • SQL Code Generation (sqlc) — Rather than writing ORM code or hand-crafted SQL mappers, sqlc generates type-safe Go functions from raw SQL; this pattern eliminates a class of SQL injection bugs and keeps SQL readable.
  • Database Migrations (Versioned Schema Changes) — The db/migration/ directory uses numbered .up.sql and .down.sql files to make schema changes reproducible and reversible; essential for deploying to production without downtime.
  • Role-Based Access Control (RBAC) — The repo adds role_to_users in migration 000005, enabling permission checks in middleware; this is foundational for multi-tenant or multi-user services with varying privileges.
  • Middleware & HTTP Handler Chains — The api/middleware.go demonstrates how to wrap handlers with authentication logic; understanding middleware patterns is critical for building secure, maintainable HTTP services.
  • Docker & Container Orchestration (Kubernetes/EKS) — The Dockerfile and .github/workflows/deploy.yml show how to containerize and deploy the service to AWS EKS; essential knowledge for production Go services.
  • golang-standards/project-layout — Defines Go project structure conventions; simplebank roughly follows this but adds db/ and api/ subdirectories for domain clarity.
  • gin-gonic/gin — The HTTP framework powering all endpoints in api/; understanding Gin's router and middleware system is essential for extending this project.
  • kyleconroy/sqlc — The tool generating type-safe Go code from db/query/ SQL files; critical to understand for modifying data layer without manual struct writing.
  • google/uuid — Likely used for session and transaction IDs in the migrations (000003_add_sessions.up.sql); shows Go stdlib integration for unique identifiers.
  • techschool/backend-master-class — The official course repository paired with this codebase; contains lecture notes and additional resources for understanding design decisions.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for API transaction flows in api/

The repo has unit tests for individual API handlers (account_test.go, transfer_test.go, user_test.go) but lacks end-to-end integration tests that verify complete workflows like user registration → account creation → transfer → balance verification. This would catch issues in the interaction between api/server.go, db/sqlc/, and middleware.go that unit tests miss.

  • [ ] Create api/integration_test.go with test fixtures for setup/teardown
  • [ ] Add test cases for: user signup flow (api/user.go) → create account (api/account.go) → transfer money (api/transfer.go) → verify balances
  • [ ] Test middleware authentication chain (api/middleware.go) with valid/invalid tokens across multiple requests
  • [ ] Verify transaction isolation in db/sqlc/tx_transfer.go handles concurrent transfers correctly
  • [ ] Update .github/workflows/test.yml to run integration tests with test database (already has migrations in db/migration/)

Add comprehensive error handling tests for db/sqlc/ models

The db/sqlc/ directory has generated model files (account.sql.go, user.sql.go, transfer.sql.go) but the corresponding _test.go files (account_test.go, user_test.go, transfer_test.go) appear minimal. Missing test coverage for db/sqlc/error.go and edge cases like duplicate key violations, foreign key constraint failures, and transaction rollbacks that are critical for a banking service.

  • [ ] Expand db/sqlc/account_test.go with: invalid account IDs, negative balances, non-existent owner references
  • [ ] Expand db/sqlc/transfer_test.go with: insufficient balance scenarios, same source/destination account, null amount validation
  • [ ] Add tests in db/sqlc/user_test.go for duplicate email detection, invalid password formats, and role validation (000005_add_role_to_users.down.sql)
  • [ ] Test db/sqlc/tx_transfer.go transaction rollback on constraint violations
  • [ ] Test db/sqlc/error.go error type assertions and database-specific error mapping

Add security and validator test coverage in api/validator.go

The repo has api/validator.go but no corresponding validator_test.go file. Given this is a banking service handling sensitive operations (transfers, user creation), input validation is critical. The api/ tests reference validator usage but don't directly test validation rules, edge cases, or SQL injection prevention.

  • [ ] Create api/validator_test.go with test cases for: email format validation, password strength rules, account currency validation
  • [ ] Test boundary conditions: max/min transfer amounts, account name length limits, username character restrictions
  • [ ] Verify validation against db/query/*.sql constraints (e.g., account currency enum from 000001_init_schema.up.sql)
  • [ ] Test that validator prevents common injection patterns for strings passed to db/sqlc/ queries
  • [ ] Update api/account_test.go, api/transfer_test.go, api/user_test.go to reference new validator tests for maintainability

🌿Good first issues

  • Add comprehensive validation tests for api/validator.go — currently the validator module exists but has no dedicated test file; write table-driven tests for account number formats, transfer amounts, and email validation.
  • Implement integration tests for the full transfer flow in api/transfer_test.go that exercise both CreateTransfer and verify ledger entries were created atomically; current test coverage appears partial.
  • Document the database isolation levels used in db/sqlc/store.go and db/migration/000001_init_schema.up.sql with comments explaining why Serializable isolation is chosen for transfers vs. Read Committed for reads — future maintainers need this context.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 97f000f — feat: add token type to token payload (#136) (phamlequang)
  • 7c6f92f — chore: upgrade JWT to v5 (#131) (phamlequang)
  • cc1ef6d — Add frontend VueJS app and and set up CORS on the backend (#120) (phamlequang)
  • 931b0d9 — update go v1.22 (#118) (phamlequang)
  • 3a4535f — Graceful shutdown servers and workers (#113) (phamlequang)
  • 9544012 — update ingress yaml file names (phamlequang)
  • 3ec096a — use kubectl apply (phamlequang)
  • 7e8c483 — deploy grpc and http to eks (phamlequang)
  • 42c6148 — update lecture name (phamlequang)
  • 2e2094e — add role-based access control (RBAC) (#103) (phamlequang)

🔒Security observations

  • Critical · Hardcoded Database Credentials in docker-compose.yaml — docker-compose.yaml (postgres service environment variables). Database credentials (POSTGRES_USER=root, POSTGRES_PASSWORD=secret) are hardcoded in the docker-compose.yaml file. These are weak default credentials ('secret' as password) exposed in version control and configuration files. Fix: Use Docker secrets or environment variable files (.env) not committed to version control. Use strong, randomly generated passwords. Consider using AWS Secrets Manager or similar in production.
  • Critical · Exposed app.env File Containing Secrets — Dockerfile, app.env. The app.env file is explicitly copied into the Docker image (Dockerfile: COPY app.env .) and likely contains sensitive configuration. This file should never be committed to version control or baked into container images. Fix: Remove app.env from version control (.gitignore should exclude it). Use runtime environment variables or secret management systems. Never COPY secrets into Docker images.
  • High · Disabled SSL/TLS for Database Connection — docker-compose.yaml (api service DB_SOURCE variable). Database connection string uses 'sslmode=disable' in docker-compose.yaml (DB_SOURCE environment variable). This disables encryption for database traffic, allowing potential man-in-the-middle attacks. Fix: Use 'sslmode=require' or 'sslmode=verify-full' for production environments. Configure proper SSL certificates for PostgreSQL connections.
  • High · Default PostgreSQL User 'root' with Weak Privileges — docker-compose.yaml (postgres service). PostgreSQL is configured with superuser 'root' and password 'secret'. Using default superuser credentials violates the principle of least privilege and creates unnecessary risk. Fix: Create a dedicated non-superuser database account with limited privileges. Use strong, randomly generated passwords. Rotate credentials regularly.
  • High · Exposed Multiple Ports Without Network Segmentation — docker-compose.yaml (postgres ports: 5432, redis implicit exposure). Docker-compose exposes ports 5432 (PostgreSQL) and 6379 (Redis) directly without network segmentation. Both database and cache are accessible from outside the container network. Fix: Remove port mappings for databases and cache services in production. Use internal Docker networks only. Expose only the API service (8080, 9090) and use a reverse proxy for controlled access.
  • High · Missing Security Headers and CORS Configuration — api/middleware.go, api/server.go. Based on file structure (api/middleware.go, api/server.go), there's no evidence of security headers (HSTS, X-Frame-Options, X-Content-Type-Options, CSP) or proper CORS configuration documented. Fix: Implement comprehensive security middleware including HSTS, X-Frame-Options, X-Content-Type-Options, X-XSS-Protection headers. Configure CORS explicitly with allowed origins, methods, and credentials.
  • High · Potential SQL Injection via Generated SQL Code — db/query/*.sql, db/sqlc/. The codebase uses sqlc for SQL code generation (db/sqlc directory), but raw SQL queries in db/query directory could be vulnerable if queries are constructed dynamically or if input validation is insufficient. Fix: Verify all SQL queries use parameterized statements exclusively. Conduct thorough code review of api/account.go, api/transfer.go, api/user.go for any dynamic query construction. Use sqlc's type-safe approach consistently.
  • High · Missing Input Validation Framework — api/validator.go, api/account.go, api/transfer.go, api/user.go. File api/validator.go exists but validation rules are not apparent from file structure. Insufficient input validation could lead to injection attacks, buffer overflows, or unexpected behavior. Fix: Implement comprehensive input validation for all API endpoints. Use whitelisting approach. Validate data types, lengths, formats, and ranges. Sanitize all user inputs.
  • Medium · Missing Authentication/Authorization on All Endpoints — undefined. While api/token.go and api/middleware.go exist, there's no evidence of comprehensive authentication/authorization Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · techschool/simplebank — RepoPilot