A Go REST API for personal task management with JWT authentication, PostgreSQL support, and an in-memory mode for fast local development.
This project is designed as a compact but production-minded backend service: layered architecture, migrations, middleware, rate limiting, metrics, structured logging, and automated tests.
- A complete backend service, not a single-file demo CRUD app.
- Supports both
memoryandpostgresstorage modes. - Authentication uses JWT access and refresh tokens.
- Passwords are hashed with
bcrypt. - The login flow is protected with rate limiting by
login + IP. - Application metrics are exposed via a dedicated endpoint restricted to localhost.
- The codebase is split into clear layers:
app,config,service,storage,transport,security, andmetrics. - The repository includes SQL migrations and tests for HTTP handlers, middleware, and storage logic.
- User registration
- User login with
access_tokenandrefresh_token - Access token validation
- Access token refresh
- Authenticated task CRUD
- Task statuses:
todo,in_progress,done - Built-in application metrics
- Structured JSON logging via
log/slog - Graceful HTTP server shutdown
- Go
1.25.1 net/http- PostgreSQL
database/sql+pgx- JWT:
github.com/golang-jwt/jwt/v5 - Password hashing:
golang.org/x/crypto/bcrypt - UUIDs:
github.com/google/uuid
cmd/auth entrypoint
internal/app application bootstrap and server startup
internal/config environment-based configuration
internal/service business logic
internal/storage interfaces and in-memory storage
internal/storage/postgres PostgreSQL storage implementations
internal/transport/http handlers, middleware, response helpers
internal/security rate limiter
internal/metrics application counters
migrations SQL schema and data migrations
The service reads environment variables and automatically loads .env if present.
| Variable | Required | Default | Description |
|---|---|---|---|
PORT |
No | :8081 |
HTTP listen address |
JWT_SECRET |
Yes | - | JWT signing secret |
LOG_LEVEL |
No | info |
debug, info, warn, error |
STORAGE |
No | memory |
memory or postgres |
DATABASE_URL |
For postgres |
- | PostgreSQL connection string |
ACCESS_TOKEN_TTL |
No | 15m |
Access token TTL |
REFRESH_TOKEN_TTL |
No | 168h |
Refresh token TTL |
Example .env:
PORT=8081
JWT_SECRET=super-secret-key
LOG_LEVEL=info
STORAGE=postgres
DATABASE_URL=postgres://postgres:postgres@localhost:5432/task_tracker?sslmode=disable
ACCESS_TOKEN_TTL=15m
REFRESH_TOKEN_TTL=168hexport JWT_SECRET=super-secret-key
go run ./cmd/authThe API will start on http://localhost:8081.
- Create a PostgreSQL database.
- Apply the migrations from
migrations/001_init.sqlandmigrations/002_migrate_tasks_user_login_to_user_id.sql. - Start the service:
export JWT_SECRET=super-secret-key
export STORAGE=postgres
export DATABASE_URL=postgres://postgres:postgres@localhost:5432/task_tracker?sslmode=disable
go run ./cmd/authPOST /register
{
"login": "alice",
"password": "strongpass123"
}POST /login
{
"login": "alice",
"password": "strongpass123"
}Response:
{
"access_token": "jwt...",
"refresh_token": "jwt..."
}POST /validate
{
"token": "jwt..."
}POST /refresh
{
"refresh_token": "jwt..."
}All task endpoints require:
Authorization: Bearer <access_token>GET /tasks
POST /tasks
{
"title": "Finish README",
"description": "Rewrite project README for GitHub"
}PUT /tasks/{id}
{
"title": "Finish README v2",
"description": "Make it portfolio-ready",
"status": "in_progress"
}DELETE /tasks/{id}
GET /metrics
This endpoint is restricted to localhost and returns:
{
"successful_logins": 1,
"failed_logins": 0,
"task_requests": 3,
"errors_4xx": 0,
"errors_5xx": 0
}Register a user:
curl -X POST http://localhost:8081/register \
-H "Content-Type: application/json" \
-d '{"login":"alice","password":"strongpass123"}'Login:
curl -X POST http://localhost:8081/login \
-H "Content-Type: application/json" \
-d '{"login":"alice","password":"strongpass123"}'Create a task:
curl -X POST http://localhost:8081/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access_token>" \
-d '{"title":"Ship portfolio project","description":"Push project to GitHub"}'- Request bodies are size-limited
- JSON decoding uses
DisallowUnknownFields()for stricter validation - Passwords are never stored in plain text
- HTTP status codes are mapped explicitly for common error cases
- The service supports graceful shutdown
- Metrics and structured logging are built in
- PostgreSQL schema uses foreign keys, indexes, and status constraints
- Docker and
docker-composefor one-command local setup - OpenAPI / Swagger documentation
- CI with
go test, linting, and migration checks - Prometheus-compatible metrics
- Refresh token rotation and revocation
- Pagination, filtering, and sorting for tasks
go test ./...This repository is in a good state to showcase backend engineering fundamentals on GitHub and in a resume. It can also serve as a base for a more production-like version with Docker, CI/CD, and API documentation.