Skip to content

Build full PostgreSQL persistence layer with migrations, repositories, and connection pooling #9

Description

@vestor-dev

Overview

Replace all in-memory Maps with a production-grade PostgreSQL persistence layer. This is the single largest backend task and a hard prerequisite for every other feature.

Scope (~2500 lines)

Schema & Migrations (backend/src/db/)

  • connection.js — pg Pool setup, graceful shutdown, health probe
  • migrations/001_create_assets.sql — assets table with JSONB tags, GIN index for full-text
  • migrations/002_create_agents.sql — agents table, capabilities as text[]
  • migrations/003_create_licenses.sql — licenses table with FK to assets
  • migrations/004_create_streams.sql — streams table
  • migrations/005_create_reports.sql — moderation reports table
  • migrations/006_create_events_log.sql — raw on-chain event audit log
  • migrate.js — migration runner that reads SQL files in order and tracks applied migrations in a schema_migrations table

Repository Layer (backend/src/repositories/)

  • assetRepository.jsfindById, findAll(filters, pagination), create, update, softDelete, search(query) using to_tsvector / plainto_tsquery
  • agentRepository.jsfindById, findAll(filters), create, updateReputation, deactivate
  • licenseRepository.jscreate, findByBuyerAndAsset, findAllByBuyer, updateCallsRemaining, expire
  • streamRepository.jscreate, findById, findBySender, findByRecipient, updateStatus, recordWithdrawal
  • eventLogRepository.jsappend, findSince(ledger), findByContractAndTopic

Service Migration

  • Migrate assetService.js, agentService.js, streamService.js to call repositories instead of Maps
  • Keep the same public interface so routes require zero changes
  • Add transaction wrappers for multi-table writes (e.g. purchase_license updates asset.usage_count AND creates a license row atomically)

Connection Pooling

  • Configure pg.Pool with max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000
  • Add pool metrics endpoint at GET /api/v1/internal/db-stats (admin-only)

Tests

  • Spin up a real PostgreSQL instance in CI using @testcontainers/postgresql
  • Repository-level integration tests for every method with real SQL
  • Test transaction rollback on failure
  • Test migration idempotency (running twice does not fail)

Acceptance Criteria

  • All data survives process restart
  • npm test passes with a live PG container
  • Migration runner is idempotent
  • No raw SQL strings outside the repository layer
  • Pool never leaks connections under test load

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions