A community based topic aggregation platform built on atproto

feat(db): add password encryption migration for V2.0

CRITICAL FIX: Replace password hashing with encryption to enable session recovery.

Changes:
- Add pds_password_encrypted column (BYTEA) for encrypted password storage
- Drop legacy pds_password_hash column (bcrypt prevents session recovery)
- Drop plaintext pds_access_token and pds_refresh_token columns
- Migration 006 already added encrypted token columns

Why encryption over hashing:
When access/refresh tokens expire (90-day window), we need plaintext password
to call com.atproto.server.createSession. Bcrypt hashing prevents this recovery.

Security: Uses PostgreSQL pgp_sym_encrypt with encryption_keys table.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Changed files
+35
internal
+35
internal/db/migrations/007_add_password_encryption.sql
···
+
-- +goose Up
+
-- +goose StatementBegin
+
-- V2.0: Add encrypted password column for PDS account recovery
+
-- CRITICAL FIX: Password must be encrypted (not hashed) for session recovery
+
-- When access/refresh tokens expire (90-day window), we need the plaintext password
+
-- to call com.atproto.server.createSession - bcrypt hashing prevents this
+
+
-- Add encrypted password column
+
ALTER TABLE communities ADD COLUMN pds_password_encrypted BYTEA;
+
+
-- Drop legacy plaintext token columns (we now use *_encrypted versions from migration 006)
+
ALTER TABLE communities DROP COLUMN IF EXISTS pds_access_token;
+
ALTER TABLE communities DROP COLUMN IF EXISTS pds_refresh_token;
+
+
-- Drop legacy password_hash column from migration 005 (never used in production)
+
ALTER TABLE communities DROP COLUMN IF EXISTS pds_password_hash;
+
+
-- Add comment
+
COMMENT ON COLUMN communities.pds_password_encrypted IS 'Encrypted community PDS password (pgp_sym_encrypt) - required for session recovery when tokens expire';
+
+
-- +goose StatementEnd
+
+
-- +goose Down
+
-- +goose StatementBegin
+
-- Restore legacy columns (for rollback compatibility)
+
ALTER TABLE communities ADD COLUMN pds_access_token TEXT;
+
ALTER TABLE communities ADD COLUMN pds_refresh_token TEXT;
+
ALTER TABLE communities ADD COLUMN pds_password_hash TEXT;
+
+
-- Drop encrypted password
+
ALTER TABLE communities DROP COLUMN IF EXISTS pds_password_encrypted;
+
+
-- Restore old comment
+
COMMENT ON COLUMN communities.pds_password_hash IS 'bcrypt hash of community PDS password (DEPRECATED - cannot recover plaintext)';
+
-- +goose StatementEnd