fix: made migartion idempotent and fixed docker-compose

This commit is contained in:
Anish Sarkar 2026-01-15 13:26:23 +05:30
parent 32b8bb33f9
commit 35392c8e62
4 changed files with 65 additions and 7 deletions

View file

@ -8,10 +8,13 @@ services:
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/docker/postgresql.conf:/etc/postgresql/postgresql.conf:ro
- ./scripts/docker/init-electric-user.sh:/docker-entrypoint-initdb.d/init-electric-user.sh:ro
environment:
- POSTGRES_USER=${POSTGRES_USER:-postgres}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
- POSTGRES_DB=${POSTGRES_DB:-surfsense}
- ELECTRIC_DB_USER=${ELECTRIC_DB_USER:-electric}
- ELECTRIC_DB_PASSWORD=${ELECTRIC_DB_PASSWORD:-electric_password}
command: postgres -c config_file=/etc/postgresql/postgresql.conf
pgadmin:
@ -123,6 +126,8 @@ services:
- ELECTRIC_INSECURE=true
- ELECTRIC_WRITE_TO_PG_MODE=direct
restart: unless-stopped
# depends_on:
# - db
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/v1/health"]
interval: 10s

View file

@ -0,0 +1,48 @@
#!/bin/sh
# ============================================================================
# Electric SQL User Initialization Script (Docker deployments)
# ============================================================================
# Creates the Electric SQL replication user for Docker deployments.
#
# For local PostgreSQL users (non-Docker), this is handled by Alembic
# migration 66 (66_add_notifications_table_and_electric_replication.py).
#
# Both approaches are idempotent (use IF NOT EXISTS), so running both
# will not cause conflicts.
# ============================================================================
set -e
# Use environment variables with defaults
ELECTRIC_DB_USER="${ELECTRIC_DB_USER:-electric}"
ELECTRIC_DB_PASSWORD="${ELECTRIC_DB_PASSWORD:-electric_password}"
echo "Creating Electric SQL replication user: $ELECTRIC_DB_USER"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
DO \$\$
BEGIN
IF NOT EXISTS (SELECT FROM pg_user WHERE usename = '$ELECTRIC_DB_USER') THEN
CREATE USER $ELECTRIC_DB_USER WITH REPLICATION PASSWORD '$ELECTRIC_DB_PASSWORD';
END IF;
END
\$\$;
GRANT CONNECT ON DATABASE $POSTGRES_DB TO $ELECTRIC_DB_USER;
GRANT USAGE ON SCHEMA public TO $ELECTRIC_DB_USER;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO $ELECTRIC_DB_USER;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO $ELECTRIC_DB_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO $ELECTRIC_DB_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO $ELECTRIC_DB_USER;
-- Create the publication for Electric SQL (if not exists)
DO \$\$
BEGIN
IF NOT EXISTS (SELECT FROM pg_publication WHERE pubname = 'electric_publication_default') THEN
CREATE PUBLICATION electric_publication_default;
END IF;
END
\$\$;
EOSQL
echo "Electric SQL user '$ELECTRIC_DB_USER' and publication created successfully"

View file

@ -6,6 +6,11 @@ Revises: 65
Creates notifications table and sets up Electric SQL replication
(user, publication, REPLICA IDENTITY FULL) for notifications,
search_source_connectors, and documents tables.
NOTE: Electric SQL user creation is idempotent (uses IF NOT EXISTS).
- Docker deployments: user is pre-created by scripts/docker/init-electric-user.sh
- Local PostgreSQL: user is created here during migration
Both approaches are safe to run together without conflicts as this migraiton is idempotent
"""
from collections.abc import Sequence
@ -46,11 +51,11 @@ def upgrade() -> None:
"""
)
# Create indexes
op.create_index("ix_notifications_user_id", "notifications", ["user_id"])
op.create_index("ix_notifications_read", "notifications", ["read"])
op.create_index("ix_notifications_created_at", "notifications", ["created_at"])
op.create_index("ix_notifications_user_read", "notifications", ["user_id", "read"])
# Create indexes (using IF NOT EXISTS for idempotency)
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_user_id ON notifications (user_id);")
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_read ON notifications (read);")
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_created_at ON notifications (created_at);")
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_user_read ON notifications (user_id, read);")
# =====================================================
# Electric SQL Setup - User and Publication

View file

@ -44,7 +44,7 @@ export function NotificationPopup({
switch (status) {
case "in_progress":
return <Loader2 className="h-4 w-4 text-white animate-spin" />;
return <Loader2 className="h-4 w-4 text-foreground animate-spin" />;
case "completed":
return <CheckCircle2 className="h-4 w-4 text-green-500" />;
case "failed":
@ -73,7 +73,7 @@ export function NotificationPopup({
<ScrollArea className="h-[400px]">
{loading ? (
<div className="flex items-center justify-center py-8">
<Loader2 className="h-5 w-5 animate-spin text-white" />
<Loader2 className="h-5 w-5 animate-spin text-foreground" />
</div>
) : notifications.length === 0 ? (
<div className="flex flex-col items-center justify-center py-8 px-4 text-center">