Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@
## 2026-06-18 - Route heavy search reads to read replica
**Learning:** `backend/api/search.py` needs the primary database session for current provider and tenant configuration, but the heavy email and attachment search query can use the read-only session from `db.session.get_readonly_db`.
**Action:** Keep provider/config resolution on `Depends(get_db)` and route only the read-only search query through `Depends(get_readonly_db)` so search load moves to replicas without replica-lagging fresh configuration reads.

## 2026-06-19 - Email owner/date lookup index
**Learning:** Inbox and reply-wait queries commonly scope `email_records` by `user_id` and `organization_id` before ordering or filtering by `date`, so separate single-column indexes still leave the planner with avoidable sort/filter work.
**Action:** Keep `ix_email_records_owner_date` on `(user_id, organization_id, date)` in both the SQLAlchemy model and bootstrap backfill SQL when optimizing owner-scoped email timelines.
6 changes: 6 additions & 0 deletions backend/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,12 @@ class Email(Base):
"message_id",
name="uq_emails_owner_message_id",
),
Index(
"ix_email_records_owner_date",
"user_id",
"organization_id",
"date",
),
)

id: Mapped[int] = mapped_column(primary_key=True)
Expand Down
4 changes: 4 additions & 0 deletions backend/scripts/bootstrap_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ def _get_create_indexes_statements() -> list[Executable]:
"CREATE INDEX IF NOT EXISTS ix_email_records_organization_id "
"ON email_records (organization_id)"
),
text(
"CREATE INDEX IF NOT EXISTS ix_email_records_owner_date "
"ON email_records (user_id, organization_id, date)"
),
text(
"CREATE INDEX IF NOT EXISTS ix_sender_relationships_owner_source "
"ON sender_relationships "
Expand Down
19 changes: 19 additions & 0 deletions backend/tests/test_bootstrap_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from db.models import (
CalendarWritebackSource,
ConnectorSignalEvent,
Email,
ProjectFolder,
SecurityAuditEvent,
SenderRelationship,
Expand Down Expand Up @@ -103,6 +104,11 @@ def test_schema_backfill_adds_email_indexes(monkeypatch):
"create index if not exists ix_email_records_organization_id" in statement
for statement in statements
)
assert any(
"create index if not exists ix_email_records_owner_date" in statement
and "user_id, organization_id, date" in statement
for statement in statements
)
assert any(
"drop index if exists ix_email_records_message_id" in statement
for statement in statements
Expand Down Expand Up @@ -414,6 +420,19 @@ def test_sender_relationship_model_declares_source_unique_index():
assert "source_thread_id" in expression_text


def test_email_model_declares_owner_date_index():
indexes = {index.name: index for index in Email.__table__.indexes}

owner_date_index = indexes["ix_email_records_owner_date"]

assert owner_date_index.unique is False
assert [column.name for column in owner_date_index.columns] == [
"user_id",
"organization_id",
"date",
]


def test_tenant_config_model_declares_owner_scope_unique_index():
indexes = {index.name: index for index in TenantConfig.__table__.indexes}

Expand Down
Loading