Files
SimpleFinanceDash/.planning/codebase/INTEGRATIONS.md

4.0 KiB

External Integrations

Database: PostgreSQL 16

Location: backend/internal/db/db.go, backend/internal/db/queries.go

Connection

  • Driver: github.com/jackc/pgx/v5 (pgx connection pool)
  • Default URL: postgres://simplefin:simplefin@localhost:5432/simplefindb?sslmode=disable
  • Environment Variable: DATABASE_URL
  • Connection Pool: pgxpool.Pool with automatic management

Schema

Tables (from backend/migrations/001_initial.sql):

  1. users — id (UUID), email, password_hash, oidc_subject, display_name, preferred_locale, timestamps
  2. categories — id (UUID), user_id (FK), name, type (enum), icon, sort_order, timestamps
  3. budgets — id (UUID), user_id (FK), name, start_date, end_date, currency, carryover_amount, timestamps
  4. budget_items — id (UUID), budget_id (FK), category_id (FK), budgeted_amount, actual_amount, notes, timestamps
  5. schema_migrations — version tracking

Enum: category_type — bill, variable_expense, debt, saving, investment, income

Numeric precision: NUMERIC(12, 2) in PostgreSQL, shopspring/decimal in Go

Migration Runner

  • Custom implementation in backend/internal/db/db.go
  • Reads .sql files from embedded filesystem (embed.FS)
  • Tracks applied versions in schema_migrations table
  • Sequential numbering: 001_initial.sql, 002_..., etc.

Authentication

Local Auth (Active)

Location: backend/internal/auth/auth.go

  • Password hashing: bcrypt with DefaultCost
  • Session: JWT (HS256) in HTTP-only cookie
  • Secret: SESSION_SECRET environment variable
  • Token TTL: 7 days
  • Cookie: HttpOnly, SameSite=Lax, MaxAge=7 days

Routes:

  • POST /api/auth/register — Create account
  • POST /api/auth/login — Login
  • POST /api/auth/logout — Clear cookie
  • GET /api/auth/me — Current user

OIDC (Planned, Not Implemented)

Location: backend/internal/api/handlers.go (stubs returning 501)

  • Routes: GET /api/auth/oidc, GET /api/auth/oidc/callback
  • Environment variables defined in compose.yml: OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET
  • DB support ready: oidc_subject column, GetUserByOIDCSubject(), UpsertOIDCUser() queries

CORS

Location: backend/internal/api/router.go

AllowedOrigins:   ["http://localhost:5173", "http://localhost:8080"]
AllowedMethods:   ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
AllowedHeaders:   ["Content-Type"]
AllowCredentials: true

Frontend API Client

Location: frontend/src/lib/api.ts

  • Base URL: /api (proxied to http://localhost:8080 via Vite in dev)
  • Uses native Fetch API with credentials: 'include'
  • Custom ApiError class for error handling
  • Typed endpoints: auth.*, categories.*, budgets.*, budgetItems.*, settings.*

Internationalization (i18n)

Location: frontend/src/i18n/

  • Library: i18next + react-i18next
  • Languages: English (en, default), German (de)
  • Keys: ~87 per language (auth, navigation, dashboard, budget, categories, settings)
  • User preference: Stored in DB (preferred_locale column)

Deployment

Docker (Multi-stage Build)

Location: Dockerfile

  1. Stage 1 (bun): Build frontend → frontend/dist
  2. Stage 2 (golang:1.24-alpine): Build Go binary with embedded frontend + migrations
  3. Stage 3 (alpine): Runtime with ca-certificates, port 8080

Docker Compose

Location: compose.yml

  • app: Go server (:8080), depends on db
  • db: PostgreSQL 16 (:5432), health check, pgdata volume

Environment Variables

Variable Purpose Required
DATABASE_URL PostgreSQL connection string Yes
SESSION_SECRET JWT signing secret Yes (production)
OIDC_ISSUER OIDC provider URL No (future)
OIDC_CLIENT_ID OIDC client ID No (future)
OIDC_CLIENT_SECRET OIDC client secret No (future)

External Services

None currently integrated. No third-party APIs, webhooks, payment processors, email providers, or message queues.