From b97cd5992033ec940f055d63006b770f735f47d9 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Mon, 13 Apr 2026 08:13:39 -0700 Subject: [PATCH] =?UTF-8?q?feat(community):=20migration=20028=20=E2=80=94?= =?UTF-8?q?=20community=5Fpseudonyms=20table=20in=20per-user=20kiwi.db?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/028_community_pseudonyms.sql | 21 +++++++++++++++++++ tests/db/test_migrations.py | 18 ++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 app/db/migrations/028_community_pseudonyms.sql create mode 100644 tests/db/test_migrations.py diff --git a/app/db/migrations/028_community_pseudonyms.sql b/app/db/migrations/028_community_pseudonyms.sql new file mode 100644 index 0000000..d5fede0 --- /dev/null +++ b/app/db/migrations/028_community_pseudonyms.sql @@ -0,0 +1,21 @@ +-- 028_community_pseudonyms.sql +-- Per-user pseudonym store: maps the user's chosen community display name +-- to their Directus user ID. This table lives in per-user kiwi.db only. +-- It is NEVER replicated to the community PostgreSQL — pseudonym isolation is by design. +-- +-- A user may have one active pseudonym. Old pseudonyms are retained for reference +-- (posts published under them keep their pseudonym attribution) but only one is +-- flagged as current (is_current = 1). + +CREATE TABLE IF NOT EXISTS community_pseudonyms ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + pseudonym TEXT NOT NULL, + directus_user_id TEXT NOT NULL, + is_current INTEGER NOT NULL DEFAULT 1 CHECK (is_current IN (0, 1)), + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +-- Only one pseudonym can be current at a time per user +CREATE UNIQUE INDEX IF NOT EXISTS idx_community_pseudonyms_current + ON community_pseudonyms (directus_user_id) + WHERE is_current = 1; diff --git a/tests/db/test_migrations.py b/tests/db/test_migrations.py new file mode 100644 index 0000000..2ae6895 --- /dev/null +++ b/tests/db/test_migrations.py @@ -0,0 +1,18 @@ +import pytest +from pathlib import Path +from app.db.store import Store + + +@pytest.fixture +def tmp_db(tmp_path: Path) -> Path: + return tmp_path / "test.db" + + +def test_migration_028_adds_community_pseudonyms(tmp_db): + """Migration 028 adds community_pseudonyms table to per-user kiwi.db.""" + store = Store(tmp_db) + cur = store.conn.execute( + "SELECT name FROM sqlite_master WHERE type='table' AND name='community_pseudonyms'" + ) + assert cur.fetchone() is not None + store.close()