SimpleBank is a small banking backend built with Go, PostgreSQL, Redis, gRPC, and a gin-based HTTP gateway. It supports user creation and login, account management, money transfers, token renewal, and an outbox-driven async worker for post-create user tasks.
- HTTP + gRPC API surface from one proto contract
- PostgreSQL-backed transactions for accounts, transfers, sessions, and users
- Transactional outbox for reliable async work
- SMTP email delivery for verify-email notifications
- Access + refresh token auth with purpose-aware validation
- Swagger/OpenAPI docs under
/swagger/ - GitHub Actions CI for vet, lint, tests, race, vuln scan, secret scan, and Docker build
flowchart LR
Client[Client] --> HTTP[HTTP Gateway]
Client --> GRPC[gRPC API]
HTTP --> API[SimpleBank server]
GRPC --> API
API --> Postgres[(PostgreSQL)]
API --> Redis[(Redis / Asynq)]
API --> Outbox[(Transactional outbox)]
Outbox --> Worker[Worker]
Worker --> Postgres
Worker --> SMTP[(SMTP / Mailpit)]
-
Copy the example env file:
cp app.env.example app.env
-
Start the stack:
make up
-
Open the services:
- HTTP gateway:
http://localhost:8080 - gRPC:
localhost:9090 - Swagger UI:
http://localhost:8080/swagger/ - Mailpit inbox:
http://localhost:8025
- HTTP gateway:
The app container runs migrations on startup. If you run the app natively with go run ., keep app.env in the repo root and make sure PostgreSQL and Redis are available.
| Command | What it does |
|---|---|
make migrateup |
Apply database migrations |
make test |
Run the full test suite |
make test-race |
Run tests with the race detector |
make check |
Run vet, lint, tests, and vuln checks |
make gitleaks |
Scan the repository history for secrets |
make docker-build |
Build the release container image locally |
make ci |
Run the local CI bundle |
make proto |
Regenerate protobuf, gRPC gateway, and Swagger artifacts |
make sqlc |
Regenerate SQLC queries and models |
make mock |
Regenerate GoMock store stubs |
The app reads configuration from app.env or environment variables.
Important values:
DB_SOURCEMIGRATION_URLREDIS_ADDRESSSMTP_SERVER_ADDRESSEMAIL_SENDER_NAMEEMAIL_SENDER_ADDRESSSMTP_USERNAME/SMTP_PASSWORD(optional, for authenticated SMTP)HTTP_SERVER_ADDRESSGRPC_SERVER_ADDRESSTOKEN_SYMMETRIC_KEY(must be exactly 32 characters)ACCESS_TOKEN_DURATIONREFRESH_TOKEN_DURATION
See app.env.example for a complete local-dev template.
Main RPCs and gateway routes:
CreateUser→POST /v1/create_userUpdateUser→PATCH /v1/update_userLoginUser→POST /v1/login_userRenewAccessToken→POST /v1/users/renew_accessCreateAccount→POST /v1/accountsGetAccount→GET /v1/accounts/{id}ListAccounts→GET /v1/accountsCreateTransfer→POST /v1/transfers
- Access and refresh tokens are purpose-separated and validated accordingly.
- Legacy tokens are rejected during the auth cutover; see docs/security/token-cutover.md.
- Git history is scanned for secrets in CI.
If you change protobuf or SQLC inputs, regenerate the derived files and run:
make check
make ci