Feature: PostgreSQL Backend #25
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom#25
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrated from GitHub issue icub3d/decentcom#25
Original Author: @icub3d
Original Date: 2026-04-15T14:15:53Z
Feature: PostgreSQL Backend
Overview
The PostgreSQL storage backend is the scale-out alternative to the default SQLite backend. It enables multi-process server deployments behind a load balancer and pairs with S3-compatible object storage for media. This feature also provides migration tooling to move an existing SQLite-based server to PostgreSQL (and back) without data loss.
Background
The storage design doc (
docs/design/storage.md) defines a pluggable storage trait hierarchy (StorageBackendwithUserStore,MessageStore,ChannelStore,MediaStore,SessionStore). The SQLite backend is the default implementation built in Phase 1 (docs/features/scaffolding.md). The PostgreSQL backend implements the same trait using sqlx with the PostgreSQL driver. Media shifts from local disk (content-addressable files) to an S3-compatible object store. The configuration is described in the storage doc with a[storage]TOML section specifyingbackend = "postgres"and[storage.media]for S3 settings.Depends on:
storage(feature #3), all Phase 1 and Phase 2 features.Requirements
[storage].backendconfig fieldDesign
API / Interface Changes
No REST API changes. The storage backend is transparent to clients. One new admin CLI command:
decentcom migrate --from sqlite --to postgres --config <path>decentcom migrate --from postgres --to sqlite --config <path>Media serving endpoint behavior changes: when using S3,
GET /api/v1/media/{media_id}returns a 302 redirect to a pre-signed S3 URL instead of streaming the file body.Data Model Changes
PostgreSQL schema (mirrors SQLite schema with PostgreSQL-appropriate types):
All existing tables (
users,messages,channels,categories,roles,role_permissions,channel_permission_overrides,invites,sessions,media,reactions,threads,dms,device_keys) are recreated with:BIGSERIALprimary keys instead ofINTEGER PRIMARY KEY AUTOINCREMENTTIMESTAMPTZinstead ofTEXTfor timestampsBYTEAfor binary fields (pubkeys, signatures)TEXTwithtsvectorgenerated column onmessages.contentfor full-text searchON DELETE CASCADEwhere appropriateNew table for S3 media tracking:
media_idcontent_hashs3_keybucketsize_bytesmime_typeuploaded_byuploaded_atComponent Changes
Server (
server/):server/src/storage/postgres/— new module directory for the PostgreSQL backendserver/src/storage/postgres/mod.rs—PostgresBackendstruct implementingStorageBackendserver/src/storage/postgres/users.rs—UserStoreimplementationserver/src/storage/postgres/messages.rs—MessageStoreimplementation with tsvector searchserver/src/storage/postgres/channels.rs—ChannelStoreimplementationserver/src/storage/postgres/sessions.rs—SessionStoreimplementationserver/src/storage/postgres/media.rs—MediaStoreimplementation using S3server/src/storage/s3.rs— S3 client wrapper (upload, download, pre-signed URL generation)server/migrations/postgres/— PostgreSQL migration files (separate fromserver/migrations/sqlite/)server/src/storage/migrate.rs— migration tool: reads from one backend, writes to anotherserver/src/config.rs— parse[storage.media]S3 configurationserver/src/routes/media.rs— modify media serving to return 302 redirect for S3 backendserver/src/bin/migrate.rs— CLI entry point for the migration tool (or subcommand of the main binary)Dependencies:
aws-sdk-s3orrust-s3crate for S3 operationspostgresfeature enabledTask List
Phase A: PostgreSQL Schema and Connection
postgresfeature toserver/Cargo.tomlserver/migrations/postgres/directory with initial migration matching the SQLite schema (using PostgreSQL types)server/src/storage/postgres/mod.rs—PostgresBackendstruct withPgPool, implementsStorageBackendtraitUserStorefor PostgreSQL inserver/src/storage/postgres/users.rsChannelStorefor PostgreSQL inserver/src/storage/postgres/channels.rsSessionStorefor PostgreSQL inserver/src/storage/postgres/sessions.rsMessageStorefor PostgreSQL inserver/src/storage/postgres/messages.rsPhase B: S3 Media Storage
aws-sdk-s3orrust-s3) toserver/Cargo.tomlserver/src/storage/s3.rs— S3 client wrapper withupload,download,presigned_url, anddeletemethodsMediaStorefor PostgreSQL+S3 inserver/src/storage/postgres/media.rsserver/src/routes/media.rsto return 302 redirect to pre-signed URL when using S3 backend[storage.media]config section for S3 bucket, region, and credentialsPhase C: Backend Selection and Config
server/src/storage/mod.rsto select backend based on[storage].backendconfig valueserver/src/config.rswith full PostgreSQL and S3 configuration parsingPhase D: Migration Tooling
server/src/storage/migrate.rs— generic migration: iterate all records from source backend, write to destination backenddecentcom migratesubcommand) inserver/src/bin/migrate.rsor as a subcommand of the main server binaryTest List
UserStoremethods against PostgreSQL (same assertions as SQLite tests)MessageStoremethods against PostgreSQL including full-text searchChannelStoremethods against PostgreSQLSessionStoremethods against PostgreSQLMediaStorestores metadata in PostgreSQL and blob in S3backend = "postgres"config and serves requests correctlyOpen Questions
aws-sdk-s3is the official AWS SDK but heavy.rust-s3is lighter but less maintained. Which to use?