PostgreSQL Schema

The PostgresStore creates two tables and one index. These are created by calling store.createTables() on application startup.

stripe402_clients

Stores client records and credit balances.

CREATE TABLE IF NOT EXISTS stripe402_clients (
  client_id TEXT PRIMARY KEY,
  stripe_customer_id TEXT NOT NULL,
  balance INTEGER NOT NULL DEFAULT 0,
  currency TEXT NOT NULL DEFAULT 'usd',
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Column
Type
Constraints
Default
Description

client_id

TEXT

PRIMARY KEY

HMAC-derived client identifier. 64-character hex string.

stripe_customer_id

TEXT

NOT NULL

Stripe Customer ID (cus_...).

balance

INTEGER

NOT NULL

0

Current credit balance in units (1 unit = 1/10,000 dollar).

currency

TEXT

NOT NULL

'usd'

ISO 4217 currency code.

created_at

TIMESTAMPTZ

NOT NULL

NOW()

Record creation timestamp.

updated_at

TIMESTAMPTZ

NOT NULL

NOW()

Last modification timestamp. Updated on balance changes.

Key Operations

Atomic balance deduction:

The WHERE balance >= $1 clause ensures the deduction only succeeds if the balance is sufficient. This is atomic — PostgreSQL acquires a row-level lock for the UPDATE.

Idempotent client creation:

stripe402_transactions

Stores transaction audit log entries.

Column
Type
Constraints
Default
Description

id

TEXT

PRIMARY KEY

UUID transaction identifier.

client_id

TEXT

NOT NULL, REFERENCES stripe402_clients(client_id)

Foreign key to the client.

type

TEXT

NOT NULL, CHECK (type IN ('topup', 'deduction'))

Transaction type.

amount

INTEGER

NOT NULL

Amount in units.

stripe_payment_intent_id

TEXT

(nullable)

NULL

Stripe PaymentIntent ID. Present for topup transactions.

resource

TEXT

(nullable)

NULL

Route key (e.g., 'GET /api/joke'). Present for deduction transactions.

created_at

TIMESTAMPTZ

NOT NULL

NOW()

Transaction timestamp.

Constraints

  • Foreign key: client_id references stripe402_clients(client_id) — transactions can only be recorded for existing clients.

  • Check constraint: type must be either 'topup' or 'deduction'.

Index

Enables efficient lookups of all transactions for a given client.

Useful Queries

Check a client's balance

Get transaction history for a client

Total revenue by route

Total top-ups by client

Last updated