Redis: per-app DB index (0-5) with shared auth DB 15 for SSO keys; flushdb replaces flushall so deploys don't wipe cross-app auth state. Postgres: drop 13 cross-domain FK constraints (migration v2t0p8q9r0), remove dead ORM relationships, add explicit joins for 4 live ones. Multi-engine sessions (account + federation) ready for per-domain DBs via DATABASE_URL_ACCOUNT / DATABASE_URL_FEDERATION env vars. All URLs initially point to the same appdb — zero behaviour change until split-databases.sh is run to migrate data to per-domain DBs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
154 lines
3.9 KiB
Bash
Executable File
154 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# split-databases.sh — Migrate from single appdb to per-domain databases.
|
|
#
|
|
# Prerequisites:
|
|
# - All apps stopped (5-min maintenance window)
|
|
# - init-databases.sql already run (CREATE DATABASE db_*)
|
|
# - Run from a host that can reach the Postgres container
|
|
#
|
|
# Usage:
|
|
# PGHOST=db PGUSER=postgres PGPASSWORD=change-me bash split-databases.sh
|
|
#
|
|
set -euo pipefail
|
|
|
|
SOURCE_DB="${SOURCE_DB:-appdb}"
|
|
|
|
# ── Table → database mapping ───────────────────────────────────────────────
|
|
|
|
declare -A DB_TABLES
|
|
|
|
DB_TABLES[db_account]="
|
|
users
|
|
magic_links
|
|
oauth_codes
|
|
oauth_grants
|
|
ghost_labels
|
|
user_labels
|
|
ghost_newsletters
|
|
user_newsletters
|
|
ghost_tiers
|
|
ghost_subscriptions
|
|
kv
|
|
"
|
|
|
|
DB_TABLES[db_blog]="
|
|
authors
|
|
tags
|
|
posts
|
|
post_authors
|
|
post_tags
|
|
post_likes
|
|
menu_items
|
|
menu_nodes
|
|
container_relations
|
|
"
|
|
|
|
DB_TABLES[db_market]="
|
|
products
|
|
product_images
|
|
product_sections
|
|
product_labels
|
|
product_stickers
|
|
product_attributes
|
|
product_nutrition
|
|
product_allergens
|
|
product_likes
|
|
product_logs
|
|
market_places
|
|
nav_tops
|
|
nav_subs
|
|
listings
|
|
listing_items
|
|
link_errors
|
|
link_externals
|
|
subcategory_redirects
|
|
"
|
|
|
|
DB_TABLES[db_cart]="
|
|
cart_items
|
|
orders
|
|
order_items
|
|
"
|
|
|
|
DB_TABLES[db_events]="
|
|
calendars
|
|
calendar_slots
|
|
calendar_entries
|
|
calendar_entry_posts
|
|
ticket_types
|
|
tickets
|
|
page_configs
|
|
"
|
|
|
|
DB_TABLES[db_federation]="
|
|
ap_anchors
|
|
ap_actor_profiles
|
|
ap_activities
|
|
ap_followers
|
|
ap_inbox_items
|
|
ap_remote_actors
|
|
ap_following
|
|
ap_remote_posts
|
|
ap_local_posts
|
|
ap_interactions
|
|
ap_notifications
|
|
ap_delivery_log
|
|
ipfs_pins
|
|
"
|
|
|
|
# ── Migrate each domain ────────────────────────────────────────────────────
|
|
|
|
for target_db in db_account db_blog db_market db_cart db_events db_federation; do
|
|
tables="${DB_TABLES[$target_db]}"
|
|
table_list=""
|
|
for t in $tables; do
|
|
table_list="$table_list --table=$t"
|
|
done
|
|
|
|
echo "=== Migrating $target_db ==="
|
|
echo " Tables: $(echo $tables | tr '\n' ' ')"
|
|
|
|
# Dump schema + data for these tables from the source DB
|
|
pg_dump "$SOURCE_DB" $table_list --no-owner --no-privileges \
|
|
| psql -q "$target_db"
|
|
|
|
echo " Done."
|
|
done
|
|
|
|
# ── Stamp Alembic head in each domain DB ──────────────────────────────────
|
|
|
|
echo ""
|
|
echo "=== Stamping Alembic head in each DB ==="
|
|
for target_db in db_account db_blog db_market db_cart db_events db_federation; do
|
|
# Create alembic_version table and stamp current head
|
|
psql -q "$target_db" <<'SQL'
|
|
CREATE TABLE IF NOT EXISTS alembic_version (
|
|
version_num VARCHAR(32) NOT NULL,
|
|
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
|
);
|
|
DELETE FROM alembic_version;
|
|
INSERT INTO alembic_version (version_num) VALUES ('v2t0p8q9r0');
|
|
SQL
|
|
echo " $target_db stamped at v2t0p8q9r0"
|
|
done
|
|
|
|
echo ""
|
|
echo "=== Migration complete ==="
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. Update docker-compose.yml — set per-app DATABASE_URL to the new DBs"
|
|
echo " 2. Remove schema_sql config (no longer needed)"
|
|
echo " 3. Redeploy all services"
|
|
echo ""
|
|
echo "Per-app DATABASE_URL values:"
|
|
echo " blog: postgresql+asyncpg://postgres:change-me@db:5432/db_blog"
|
|
echo " market: postgresql+asyncpg://postgres:change-me@db:5432/db_market"
|
|
echo " cart: postgresql+asyncpg://postgres:change-me@db:5432/db_cart"
|
|
echo " events: postgresql+asyncpg://postgres:change-me@db:5432/db_events"
|
|
echo " federation: postgresql+asyncpg://postgres:change-me@db:5432/db_federation"
|
|
echo " account: postgresql+asyncpg://postgres:change-me@db:5432/db_account"
|
|
echo ""
|
|
echo " DATABASE_URL_ACCOUNT: postgresql+asyncpg://postgres:change-me@db:5432/db_account"
|
|
echo " DATABASE_URL_FEDERATION: postgresql+asyncpg://postgres:change-me@db:5432/db_federation"
|