A purely functional, backend-only e-commerce API written in Scala, built by following Practical FP in Scala by Gabriel Volpe. It implements a small shop domain — brands, categories, items, a Redis-backed cart, checkout, orders, and JWT-based authentication — using the Typelevel/tf2 stack (Cats Effect, http4s, skunk, redis4cats, circe, refined).
- Language: Scala 2.13
- Effects: Cats Effect 3
- HTTP server: http4s (Ember)
- Database: PostgreSQL, accessed via skunk
- Cache / cart storage: Redis, via redis4cats
- JSON: circe
- Config: ciris
- Validation: refined
- Auth: JWT via http4s-jwt-auth
- Testing: weaver-test
- Build tool: sbt, packaged as a Docker image via sbt-native-packager
.
├── build.sbt
├── project/
│ ├── Dependencies.scala # library versions & dependency definitions
│ ├── plugins.sbt # sbt plugins (native-packager, scalafmt, scalafix, revolver…)
│ └── build.properties
└── modules/
├── core/ # the application itself
│ └── src/main/
│ ├── resources/tables.sql
│ └── scala/shop/
│ ├── Main.scala
│ ├── auth/ # crypto, JWT tokens
│ ├── config/ # ciris-based config loading
│ ├── domain/ # domain models (brand, cart, item, order, …)
│ ├── effects/
│ ├── ext/ # ciris/derevo/http4s extensions
│ ├── http/ # routes, clients, auth middleware
│ ├── modules/ # wiring: HttpApi, Services, Security, Programs…
│ ├── optics/
│ ├── programs/ # Checkout program
│ ├── resources/ # Postgres/Redis/HTTP client resource management
│ ├── retries/
│ ├── services/ # business logic (Brands, Items, Orders, ShoppingCart, …)
│ └── sql/ # skunk codecs
└── tests/ # unit + integration test suite (weaver)
- JDK 11
- sbt 1.6+
- PostgreSQL (default config expects
localhost:5432, databasestore) - Redis (see environment-specific URI below)
Configuration is loaded at startup via ciris from environment variables. Set an .env file (already git-ignored) or export these in your shell:
| Variable | Description |
|---|---|
SC_APP_ENV |
test or prod — selects Redis/payment URIs |
SC_JWT_SECRET_KEY |
Secret key for admin JWT signing |
SC_JWT_CLAIM |
JWT claim string |
SC_ACCESS_TOKEN_SECRET_KEY |
Secret key for user access tokens |
SC_ADMIN_USER_TOKEN |
Admin bearer token |
SC_PASSWORD_SALT |
Salt used for password hashing |
SC_POSTGRES_PASSWORD |
Postgres password |
Other settings (Postgres host/user/db, HTTP server host/port, token expirations, checkout retry policy, etc.) are hardcoded defaults in shop.config.Config and can be adjusted there.
The database schema is defined in modules/core/src/main/resources/tables.sql — apply it to your Postgres instance before running the app.
# apply the database schema
psql -h localhost -U postgres -d store -f modules/core/src/main/resources/tables.sql
# set required environment variables (see above), then:
sbt core/runThe API is served on http://0.0.0.0:8080 under the /v1 prefix (open routes) and /v1/admin (admin-only routes).
The core module uses sbt-native-packager's Docker plugin:
sbt core/docker:publishLocalsbt test # unit tests
sbt it:test # integration tests (require running Postgres & Redis)sbt scalafmtAll # format code (also runs automatically on compile)
sbt runLinter # run scalafix OrganizeImports ruleGET /v1/healthcheck— health checkGET /v1/brands,/v1/categories,/v1/items— public catalog browsingPOST /v1/users,/v1/login,POST /v1/logout— auth/v1/cart,/v1/checkout,/v1/orders— secured, JWT-protected routes/v1/admin/brands,/v1/admin/categories,/v1/admin/items— admin-only, JWT-protected CRUD
This project is an implementation exercise following Practical FP in Scala by Gabriel Volpe, and mirrors the architecture and patterns taught there (tagless-final services, Redis-backed shopping cart, JWT auth, ciris config, skunk for Postgres).