40 lines
1.2 KiB
Python
40 lines
1.2 KiB
Python
"""C4C — index the access timeline, so retention and history are cheap
|
|
|
|
Two reads matter and neither had an index:
|
|
|
|
- the history endpoint, filtering one tenant's `access` events by date;
|
|
- the retention sweeper, finding events older than the policy.
|
|
|
|
Both are `(tenant_id, module, created_at)`. Partial on `module = 'access'`,
|
|
because ordinary activity is far more numerous and does not share these
|
|
queries — indexing it here would triple the index for no reader.
|
|
|
|
Retention itself is a **setting**, not a constant: how long access records are
|
|
kept is the sort of thing a customer contract specifies, and it must be
|
|
answerable without a deploy. See `ACCESS_LOG_RETENTION_DAYS`.
|
|
|
|
Revision ID: c4_1_access_log_retention
|
|
Revises: c4_0_grant_expiry
|
|
"""
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision = "c4_1_access_log_retention"
|
|
down_revision = "c4_0_grant_expiry"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.create_index(
|
|
"ix_activity_logs_access_timeline",
|
|
"activity_logs",
|
|
["tenant_id", "created_at"],
|
|
postgresql_where=sa.text("module = 'access'"),
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_index("ix_activity_logs_access_timeline", table_name="activity_logs")
|