Product5 MIN READ123 / 129

Product backend

Status: implemented Kotlin/JVM Spring Boot service for customer accounts and API access. Google sign-in, backend token pairs, and persisted login sessions are implemented. Profile management, API keys, usage reporting, payments, and redeem codes remain planned. Updated: 29 October 2026.

The product backend is the account and access boundary for the customer astrology API. It owns the PostgreSQL schema, verifies Google credentials, creates or reuses customer accounts, and issues short-lived access tokens with longer-lived refresh tokens. Every ordinary application route requires a valid access token and an active database session.

Current capabilities

Capability State Notes
Google sign-in Implemented POST /login/v1/google verifies a Google ID token and creates or reuses an account.
Backend token pair Implemented HS256 access and refresh tokens bound to one persisted session.
Session validation Implemented Every authenticated request checks token signature, role, issuer, expiry, and active session state.
Public smoke endpoint Implemented GET /hello returns plain text without authentication or persistence.
OpenAPI documentation Implemented Springdoc exposes /v3/api-docs and Swagger UI.
Account profile Planned profile table and entity exist; no profile endpoint is exposed.
API keys and usage Planned Schema and projections exist; no key or usage service is exposed.
Payments and redeem codes Planned Schema and projections exist; no payment or redemption flow is exposed.
Refresh exchange and sign-out Planned Refresh tokens are issued, but no refresh or revocation endpoint exists yet.

Quick start

The service needs JDK 25, Docker for the local PostgreSQL stack, a Google client ID, and a Base64 HMAC key containing at least 32 random bytes.

cd apps/product-backend
docker compose --env-file local.env up -d --wait postgres
docker compose --env-file local.env exec -T postgres \
  psql -U postgres -d product_backend -v ON_ERROR_STOP=1 \
  < src/main/resources/database/migrations/V1__product_schema.sql
docker compose --env-file local.env up -d --build backend
curl http://127.0.0.1:8080/hello

The schema is applied manually. Flyway is a test-only dependency; it does not run during application startup or in the Compose image. See local development for environment keys, host-JVM startup, and verification commands.

Configuration

Setting Required Default Purpose
SPRING_DATASOURCE_URL Yes — PostgreSQL JDBC URL, including TLS options for hosted Supabase.
SPRING_DATASOURCE_USERNAME Yes — Database role.
SPRING_DATASOURCE_PASSWORD Yes — Database password.
GOOGLE_CLIENT_ID Yes — Expected Google ID-token audience.
JWT_SECRET Yes — Base64 HMAC secret, at least 32 decoded bytes.
JWT_ACTIVE_KID No primary Key ID used to sign new tokens.
PRODUCT_DB_POOL_SIZE No 5 Maximum HikariCP pool size.
PRODUCT_DB_MIN_IDLE No 1 Minimum idle database connections.
PORT No 8080 HTTP port.
PRODUCT_AUTH_TOKEN_ISSUER No product-backend Backend token issuer.
JWT_ACCESS_DURATION No 1 Access-token duration value.
JWT_ACCESS_DURATION_UNIT No HOURS Access-token duration unit.
JWT_REFRESH_DURATION No 30 Refresh-token/session duration value.
JWT_REFRESH_DURATION_UNIT No DAYS Refresh duration unit; total lifetime must exceed access lifetime.

The local profile imports apps/product-backend/local.env. Real environment variables override that file. Keep credentials out of Git and logs.

Routes

Method Path Access Behavior
POST /login/v1/google Public Exchange a Google ID token for an access/refresh pair.
GET /hello Public Plain-text smoke response.
GET /v3/api-docs/** Public OpenAPI document.
GET /swagger-ui/**, /swagger-ui.html Public Swagger UI.
Any other route — Bearer access token Requires ROLE_USER and an active session.

See the HTTP API guide for request and response examples, the error contract, and planned routes.

Security model

  • Spring Security is stateless; CSRF is disabled and no server-side HTTP session is created.
  • Google credentials are verified against Google’s JWK set before any database write. The configured client ID is the required audience.
  • Backend tokens use HS256 with the active key ID. Retained key IDs remain accepted until removed from configuration.
  • Access tokens carry a single-element role list containing user; refresh tokens carry refresh. Ordinary routes require ROLE_USER, so a refresh token cannot call them.
  • Both tokens carry the same sid header. The matching login_session row must be active and unexpired.
  • Database session checks happen on every authenticated request, so revocation is immediate once the row is marked inactive. No revocation endpoint exists yet.
  • Failed authentication and authorization return the common JSON error shape with a trace ID. Internal messages and stack traces stay in server logs.

Documentation map

  • Authentication: Google verification, account resolution, token claims, sessions, and failure paths.
  • HTTP API: routes, payloads, status codes, and the error contract.
  • Database schema: tables, relationships, ownership rules, and manual application.
  • Production architecture: the proposed Cloudflare container and Supabase PostgreSQL request path.
  • Local development: Compose, host JVM, configuration, IDE, and commands.
  • Native builds: GraalVM native compilation, AOT reflection, and native tests.
Path Owns
src/main/kotlin/com/astrology/product/account/login Google verification, account resolution, login endpoint, and login DTOs.
src/main/kotlin/com/astrology/product/account/token Backend token signing, key selection, roles, and session-bound validation.
src/main/kotlin/com/astrology/product/account/session Session persistence and active-session lookup.
src/main/kotlin/com/astrology/product/platform/config Typed configuration, security filter chain, and native reflection registration.
src/main/kotlin/com/astrology/product/platform/exception Application exceptions, assertion helpers, MVC advice, and servlet error writing.
src/main/kotlin/com/astrology/product/platform/db Explicit SQL statements and row mappers for all product tables.
src/main/resources/database/migrations Executable PostgreSQL schema.