REST API backend for the Itala personal finance platform. Built with Go and deployed as an AWS Lambda function behind API Gateway. Part of the Itala ecosystem alongside the PWA frontend, workers, and infrastructure.
Manages accounts, categories, and transactions with single-table DynamoDB design, JWT authentication via Amazon Cognito, and idempotent writes for transaction operations.
The codebase follows clean architecture (hexagonal) with domain, application, and infrastructure layers. Each feature (account, category, transaction, identity) is isolated under internal/features/ with its own domain entities, use cases, repository ports, and DynamoDB adapters. Decorator patterns provide cross-cutting concerns like logging, idempotency, and retry with exponential backoff.
A single DynamoDB table stores all entities using a composite key design (PK/SK) with GSIs for transaction queries by type, account, and category.
Development follows trunk-based development with master as the single long-lived branch. All work is committed directly to master or merged via short-lived PRs. Semantic-release automates versioning based on conventional commits. Pushing to master deploys to staging; publishing a GitHub release promotes to production.
itala-api/
├── cmd/
│ ├── api/main.go # Local HTTP server (:8080)
│ └── lambda/main.go # AWS Lambda entrypoint
├── docs/
│ ├── api/ # Bruno API collection
│ └── assets/ # Architecture diagrams
├── version/version.go # Build version (injected via ldflags)
├── internal/
│ ├── app/api/
│ │ ├── app.go # Bootstrap, dependency wiring
│ │ ├── router.go # Chi router, all route registration
│ │ ├── middleware/ # Authentication middleware
│ │ ├── handler/ # HTTP handlers (account, category, transaction)
│ │ ├── request/ # JSON body + query string decoders
│ │ └── response/ # JSON response writers
│ ├── features/
│ │ ├── account/ # Account domain, use cases, DynamoDB adapter
│ │ ├── category/ # Category domain, use cases, DynamoDB adapter
│ │ ├── transaction/ # Transaction domain, use cases, DynamoDB adapter
│ │ └── identity/ # Cognito JWT validation, identity provider
│ └── shared/
│ ├── domain/valueobject/ # Decimal, TransactionType value objects
│ └── infrastructure/ # DynamoDB client, idempotency, logger
├── .env.example # Required environment variables template
├── Makefile # build, package targets
├── lefthook.yml # Git hooks (gofmt, go vet, cog verify)
└── .air.toml # Hot-reload config
| Variable | Description |
|---|---|
AWS_REGION |
AWS region for Cognito issuer URL |
COGNITO_USER_POOL_ID |
Cognito User Pool ID for JWT validation |
DYNAMODB_TABLE_NAME |
DynamoDB table name (single-table design) |
- Go 1.26 — core language
- Chi v5 — HTTP router
- AWS SDK v2 — DynamoDB client
- Cognito JWT — authentication via JWKS (keyfunc + golang-jwt)
- algnhsa — Lambda-to-HTTP adapter
- shopspring/decimal — arbitrary-precision decimal arithmetic
- Air — hot-reload for local development
- Go 1.26+
- AWS credentials configured (default credential chain)
- A
.envfile (see Environment Variables)
Git hooks are managed with Lefthook and Cocogitto. Install both:
paru -S lefthook cocogittoInstall the hooks:
lefthook install| Hook | Action |
|---|---|
pre-commit |
Runs gofmt -w on staged Go files and go vet on their packages, re-staging fixes |
commit-msg |
Runs cog verify to enforce Conventional Commits |
Commits must follow the conventional format, e.g. feat: add transaction recurrence or fix: derive gsi key on update.
Deployments are fully automated via GitHub Actions. All pipelines use OIDC-based AWS authentication (no static credentials), fetch configuration from SSM Parameter Store, and notify Discord on completion.
Triggered on pushes to non-master branches. Checks formatting and vet, runs the test suite, builds the Lambda binary, and scans dependencies with Trivy before merging.
flowchart TD
T["push to branch"] --> LINT["lint\ngofmt check + go vet ./..."]
T --> TEST["test\ngo test ./..."]
T --> BUILD["build\ncross-compile Go → arm64"]
T --> SEC["security\nTrivy fs scan → CRITICAL,HIGH"]
Triggered on push to master. Runs semantic-release to determine the next version, builds the Lambda binary, and deploys to the staging environment.
flowchart TD
T["push to master"] --> SETUP["setup\nstaging"]
T --> VERSION["version\nsemantic-release → tag"]
SETUP --> BUILD["build\ncross-compile Go → arm64\nupload function.zip"]
VERSION --> BUILD
BUILD --> DEPLOY["deploy\nAWS OIDC auth\nSSM config lookup\nS3 upload → Lambda update"]
DEPLOY --> NOTIFY["notify\nDiscord (always)"]
BUILD -.-> NOTIFY
Triggered when a GitHub release is published. Builds from the release tag and deploys to the production environment.
flowchart TD
T["release published"] --> SETUP["setup\nproduction"]
SETUP --> BUILD["build\ncross-compile Go → arm64\nupload function.zip"]
BUILD --> DEPLOY["deploy\nAWS OIDC auth\nSSM config lookup\nS3 upload → Lambda update"]
DEPLOY --> NOTIFY["notify\nDiscord (always)"]
BUILD -.-> NOTIFY
