Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
82c6dd0
feat: Integrate Electric SQL for real-time notifications and enhance …
AnishSarkar22 Jan 12, 2026
f441c7b
feat: Enhance Electric SQL integration and update notification handling
AnishSarkar22 Jan 12, 2026
93d17b5
feat: Implement notification system with real-time updates and Electr…
AnishSarkar22 Jan 12, 2026
4460574
refactor: Update NotificationPopup and use-notifications for improved…
AnishSarkar22 Jan 12, 2026
38f907e
feat: Implement Electric SQL replication setup for notifications table
AnishSarkar22 Jan 12, 2026
271ddff
refactor: Add indexing functions with notification support
AnishSarkar22 Jan 13, 2026
b0bdbf1
feat: gogole drive custom notification system
AnishSarkar22 Jan 13, 2026
7a92ecc
Merge remote-tracking branch 'upstream/dev' into feat/replace-logs
AnishSarkar22 Jan 13, 2026
e38e6d9
feat: Add notifications table and integrate Electric SQL for real-tim…
AnishSarkar22 Jan 13, 2026
59a8ef5
refactor: Remove deprecated create_connector_indexed_notification met…
AnishSarkar22 Jan 13, 2026
12671ed
feat: Enhance document processing notifications and refactor related …
AnishSarkar22 Jan 13, 2026
48b67d9
fix: remove the document processing UI which used polling
AnishSarkar22 Jan 13, 2026
f250fa1
feat: Implement real-time indexing state management for connectors
AnishSarkar22 Jan 13, 2026
0e0aec1
refactor: Update indexing status display in connector components
AnishSarkar22 Jan 13, 2026
34230bd
refactor: Enhance connector form submission and tooltip styling
AnishSarkar22 Jan 13, 2026
64c032d
fix: some UI changes for notification popup
AnishSarkar22 Jan 13, 2026
536f3ec
chore: Update .env.example and docker-compose.yml for Electric SQL co…
AnishSarkar22 Jan 13, 2026
4fd380a
fix: the env.example for docker
AnishSarkar22 Jan 13, 2026
99bd2df
Merge remote-tracking branch 'upstream/dev' into feat/replace-logs
AnishSarkar22 Jan 13, 2026
5bd6bd3
chore: ran both frontend and backend linting
AnishSarkar22 Jan 13, 2026
fede741
fix: fixed notifications table and Electric SQL replication setup. Re…
AnishSarkar22 Jan 13, 2026
69f46ff
feat: Add notifications API routes and integrate with frontend
AnishSarkar22 Jan 13, 2026
9d0f5b4
fix: Ensure notification updates are reliable during error handling
AnishSarkar22 Jan 13, 2026
460dc0d
feat: Enhance notification model and UI components
AnishSarkar22 Jan 13, 2026
18ec954
chore: ran frontend linting
AnishSarkar22 Jan 13, 2026
1ea0475
refactor: Improve indexing notification handling and return values
AnishSarkar22 Jan 14, 2026
7023223
chore: ran backend linting
AnishSarkar22 Jan 14, 2026
df0f488
fix: UI while indexing
AnishSarkar22 Jan 14, 2026
9b9fde9
Merge remote-tracking branch 'upstream/dev' into feat/replace-logs
AnishSarkar22 Jan 14, 2026
5712336
fix: fixed UI while indexing
AnishSarkar22 Jan 14, 2026
7a9a14a
feat: fixed migration for electric-sql
AnishSarkar22 Jan 14, 2026
ee3a0a9
fix: made electric user and password hardcoded
AnishSarkar22 Jan 14, 2026
e28be9d
feat: centralize Electric SQL user credentials in configuration
AnishSarkar22 Jan 14, 2026
2e0f742
Merge remote-tracking branch 'upstream/dev' into feat/replace-logs
AnishSarkar22 Jan 14, 2026
31a5581
feat: add notifications table and Electric SQL replication setup
AnishSarkar22 Jan 14, 2026
94e6512
chore: ran backend linting
AnishSarkar22 Jan 14, 2026
8ceccc4
feat: added electric-sql docker-compose
AnishSarkar22 Jan 14, 2026
f7f1187
Merge remote-tracking branch 'upstream/dev' into feat/replace-logs
AnishSarkar22 Jan 15, 2026
32b8bb3
feat: add notifications table and configure Electric SQL replication
AnishSarkar22 Jan 15, 2026
35392c8
fix: made migartion idempotent and fixed docker-compose
AnishSarkar22 Jan 15, 2026
eb1ddf0
feat: docker all in one setup for electric-sql and edited comments in…
AnishSarkar22 Jan 15, 2026
703ec08
feat: Reduce memory footprint for PGlite, Implement user-specific Ele…
AnishSarkar22 Jan 15, 2026
56dd2b4
feat: Enhance notification syncing and querying logic
AnishSarkar22 Jan 15, 2026
ab63b23
Merge remote-tracking branch 'upstream/dev' into feat/replace-logs
AnishSarkar22 Jan 15, 2026
b9dc785
chore: ran frontend and backend linting
AnishSarkar22 Jan 15, 2026
9ddcd4f
feat: added docs for electric-sql + pglite
AnishSarkar22 Jan 15, 2026
351f6eb
refactor: optimize connector status hook and update class name for de…
AnishSarkar22 Jan 15, 2026
aea3040
refactor: update sidebar components for improved styling and consistency
AnishSarkar22 Jan 15, 2026
4cde221
chore: ran linting
AnishSarkar22 Jan 15, 2026
85ca04c
refactor: remove deprecated composer and assistant UI components
AnishSarkar22 Jan 15, 2026
28aa481
refactor: improve chat UI and greeting logic
AnishSarkar22 Jan 15, 2026
a05fe3c
refactor: update document mention picker styling for improved visibil…
AnishSarkar22 Jan 15, 2026
138347c
fix: docker-compose vite dependency for fuma-docs
AnishSarkar22 Jan 15, 2026
eb1f39b
fix: run automatic alembic migrations for docker-compose
AnishSarkar22 Jan 15, 2026
52f2aac
chore: update docker-compose and documentation for PostgreSQL configu…
AnishSarkar22 Jan 15, 2026
8024195
fix: add env.example and docs
AnishSarkar22 Jan 15, 2026
4281e6f
refactor: update ActiveConnectorsTab and ChatShareButton components f…
AnishSarkar22 Jan 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ services:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/docker/postgresql.conf:/etc/postgresql/postgresql.conf:ro
- ./scripts/docker/init-electric-user.sql:/docker-entrypoint-initdb.d/init-electric-user.sql:ro
environment:
- POSTGRES_USER=${POSTGRES_USER:-postgres}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
- POSTGRES_DB=${POSTGRES_DB:-surfsense}
command: postgres -c config_file=/etc/postgresql/postgresql.conf

pgadmin:
image: dpage/pgadmin4
Expand Down Expand Up @@ -110,6 +113,23 @@ services:
# - redis
# - celery_worker

electric:
image: electricsql/electric:latest
ports:
- "${ELECTRIC_PORT:-5133}:3000"
environment:
- DATABASE_URL=postgresql://electric:electric_password@db:5432/${POSTGRES_DB:-surfsense}?sslmode=disable
- ELECTRIC_INSECURE=true
- ELECTRIC_WRITE_TO_PG_MODE=direct
depends_on:
- db
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/v1/health"]
interval: 10s
timeout: 5s
retries: 5

frontend:
build:
context: ./surfsense_web
Expand All @@ -122,8 +142,12 @@ services:
- "${FRONTEND_PORT:-3000}:3000"
env_file:
- ./surfsense_web/.env
environment:
- NEXT_PUBLIC_ELECTRIC_URL=${NEXT_PUBLIC_ELECTRIC_URL:-http://localhost:5133}
- NEXT_PUBLIC_ELECTRIC_AUTH_MODE=insecure
depends_on:
- backend
- electric

volumes:
postgres_data:
Expand Down
11 changes: 11 additions & 0 deletions scripts/docker/electrify-tables.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Electrify tables for Electric SQL sync
-- This tells Electric SQL which tables to sync
-- Run this after running migrations

-- Electrify notifications table
ALTER TABLE notifications ENABLE ELECTRIC;

-- You can electrify other tables as needed:
-- ALTER TABLE documents ENABLE ELECTRIC;
-- ALTER TABLE logs ENABLE ELECTRIC;

30 changes: 30 additions & 0 deletions scripts/docker/init-electric-user.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-- Create Electric SQL replication user
-- This script is run during PostgreSQL initialization

DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_user WHERE usename = 'electric') THEN
CREATE USER electric WITH REPLICATION PASSWORD 'electric_password';
END IF;
END
$$;

-- Grant necessary permissions
GRANT CONNECT ON DATABASE surfsense TO electric;
GRANT USAGE ON SCHEMA public TO electric;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO electric;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO electric;

-- Grant permissions on future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO electric;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO electric;

-- Create the publication that Electric SQL expects
-- Electric will add tables to this publication when shapes are subscribed
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_publication WHERE pubname = 'electric_publication_default') THEN
CREATE PUBLICATION electric_publication_default;
END IF;
END
$$;
23 changes: 21 additions & 2 deletions scripts/docker/init-postgres.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,18 @@ fi
# Configure PostgreSQL
cat >> "$PGDATA/postgresql.conf" << EOF
listen_addresses = '*'
max_connections = 100
shared_buffers = 128MB
max_connections = 200
shared_buffers = 256MB

# Enable logical replication (required for Electric SQL)
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10

# Performance settings
checkpoint_timeout = 10min
max_wal_size = 1GB
min_wal_size = 80MB
EOF

cat >> "$PGDATA/pg_hba.conf" << EOF
Expand All @@ -45,6 +55,15 @@ CREATE USER $POSTGRES_USER WITH PASSWORD '$POSTGRES_PASSWORD' SUPERUSER;
CREATE DATABASE $POSTGRES_DB OWNER $POSTGRES_USER;
\c $POSTGRES_DB
CREATE EXTENSION IF NOT EXISTS vector;

-- Create Electric SQL replication user
CREATE USER electric WITH REPLICATION PASSWORD 'electric_password';
GRANT CONNECT ON DATABASE $POSTGRES_DB TO electric;
GRANT USAGE ON SCHEMA public TO electric;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO electric;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO electric;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO electric;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO electric;
EOF

echo "PostgreSQL initialized successfully."
Expand Down
20 changes: 20 additions & 0 deletions scripts/docker/postgresql.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# PostgreSQL configuration for Electric SQL
# This file is mounted into the PostgreSQL container

listen_addresses = '*'
max_connections = 200
shared_buffers = 256MB

# Enable logical replication (required for Electric SQL)
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10

# Performance settings
checkpoint_timeout = 10min
max_wal_size = 1GB
min_wal_size = 80MB

# Logging (optional, for debugging)
# log_statement = 'all'
# log_replication_commands = on
57 changes: 57 additions & 0 deletions surfsense_backend/alembic/versions/60_add_notifications_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Add notifications table

Revision ID: 60
Revises: 59
"""
from collections.abc import Sequence

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "60"
down_revision: str | None = "59"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
"""Upgrade schema - add notifications table."""
# Create notifications table
op.execute(
"""
CREATE TABLE IF NOT EXISTS notifications (
id SERIAL PRIMARY KEY,
user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
search_space_id INTEGER REFERENCES searchspaces(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
title VARCHAR(200) NOT NULL,
message TEXT NOT NULL,
read BOOLEAN NOT NULL DEFAULT FALSE,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ
);
"""
)

# 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"])

# Set REPLICA IDENTITY FULL (required by Electric SQL for replication)
# This allows Electric SQL to track all column values for updates/deletes
op.execute("ALTER TABLE notifications REPLICA IDENTITY FULL;")

# Note: ElectricSQL 1.x dynamically adds tables to the publication when
# clients subscribe to shapes. No need to manually create publications.


def downgrade() -> None:
"""Downgrade schema - remove notifications table."""
op.drop_index("ix_notifications_user_read", table_name="notifications")
op.drop_index("ix_notifications_created_at", table_name="notifications")
op.drop_index("ix_notifications_read", table_name="notifications")
op.drop_index("ix_notifications_user_id", table_name="notifications")
op.drop_table("notifications")
37 changes: 37 additions & 0 deletions surfsense_backend/app/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,12 @@ class SearchSpace(BaseModel, TimestampMixin):
order_by="Log.id",
cascade="all, delete-orphan",
)
notifications = relationship(
"Notification",
back_populates="search_space",
order_by="Notification.created_at.desc()",
cascade="all, delete-orphan",
)
search_source_connectors = relationship(
"SearchSourceConnector",
back_populates="search_space",
Expand Down Expand Up @@ -629,6 +635,25 @@ class Log(BaseModel, TimestampMixin):
search_space = relationship("SearchSpace", back_populates="logs")


class Notification(BaseModel, TimestampMixin):
__tablename__ = "notifications"

user_id = Column(
UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=False, index=True
)
search_space_id = Column(
Integer, ForeignKey("searchspaces.id", ondelete="CASCADE"), nullable=True
)
type = Column(String(50), nullable=False) # 'document_processed', 'connector_indexed', 'user_mentioned', etc.
title = Column(String(200), nullable=False)
message = Column(Text, nullable=False)
read = Column(Boolean, nullable=False, default=False, server_default=text("false"), index=True)
notification_metadata = Column("metadata", JSONB, nullable=True, default={})

user = relationship("User", back_populates="notifications")
search_space = relationship("SearchSpace", back_populates="notifications")


class SearchSpaceRole(BaseModel, TimestampMixin):
"""
Custom roles that can be defined per search space.
Expand Down Expand Up @@ -773,6 +798,12 @@ class User(SQLAlchemyBaseUserTableUUID, Base):
"OAuthAccount", lazy="joined"
)
search_spaces = relationship("SearchSpace", back_populates="user")
notifications = relationship(
"Notification",
back_populates="user",
order_by="Notification.created_at.desc()",
cascade="all, delete-orphan",
)

# RBAC relationships
search_space_memberships = relationship(
Expand All @@ -799,6 +830,12 @@ class User(SQLAlchemyBaseUserTableUUID, Base):

class User(SQLAlchemyBaseUserTableUUID, Base):
search_spaces = relationship("SearchSpace", back_populates="user")
notifications = relationship(
"Notification",
back_populates="user",
order_by="Notification.created_at.desc()",
cascade="all, delete-orphan",
)

# RBAC relationships
search_space_memberships = relationship(
Expand Down
Loading