POST /v1/lead-scoring/score now evaluates in the request, applies an overall AI deadline, and stores the completed run only after scoring. Idempotency is kept by (app_id, account_id, request_id) with a body fingerprint. Removes the webhook outbox, scheduler/recovery loop, app lead_scoring permission, credential audit events, seed_demo and generate_secret scripts, and the tests that covered them. Trims tests to behavior of the new flow.
101 lines
4.0 KiB
Python
101 lines
4.0 KiB
Python
"""Initial schema for the unreleased AI Platform."""
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision = "0001_initial"
|
|
down_revision = None
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.create_table(
|
|
"app_credentials",
|
|
sa.Column("app_id", sa.String(128), primary_key=True),
|
|
sa.Column("verifier", sa.String(64), nullable=False, unique=True),
|
|
sa.Column("active", sa.Boolean(), nullable=False),
|
|
sa.Column(
|
|
"created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
|
|
),
|
|
sa.Column(
|
|
"updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
|
|
),
|
|
)
|
|
op.create_table(
|
|
"admin_users",
|
|
sa.Column("email", sa.String(254), primary_key=True),
|
|
sa.Column("password_hash", sa.String(512), nullable=False),
|
|
)
|
|
op.create_table(
|
|
"admin_sessions",
|
|
sa.Column("id", sa.String(64), primary_key=True),
|
|
sa.Column(
|
|
"admin_email", sa.String(254), sa.ForeignKey("admin_users.email"), nullable=False
|
|
),
|
|
sa.Column("csrf_hash", sa.String(64), nullable=False),
|
|
sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False),
|
|
)
|
|
op.create_table(
|
|
"ai_profiles",
|
|
sa.Column("version", sa.String(64), primary_key=True),
|
|
sa.Column("model", sa.String(128), nullable=False),
|
|
sa.Column("provider", sa.String(32), nullable=False, server_default="aihub"),
|
|
sa.Column("base_url", sa.String(2048)),
|
|
sa.Column("system_prompt", sa.String(8000), nullable=False),
|
|
sa.Column("timeout_seconds", sa.Integer(), nullable=False),
|
|
sa.Column("limits", sa.JSON(), nullable=False),
|
|
sa.Column("active", sa.Boolean(), nullable=False, server_default=sa.false()),
|
|
)
|
|
op.create_table(
|
|
"ai_profile_audit_events",
|
|
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
sa.Column("actor", sa.String(254), nullable=False),
|
|
sa.Column("version", sa.String(64), nullable=False),
|
|
sa.Column("provider", sa.String(32), nullable=False),
|
|
sa.Column(
|
|
"occurred_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
|
|
),
|
|
)
|
|
op.create_table(
|
|
"scoring_runs",
|
|
sa.Column("id", sa.String(36), primary_key=True),
|
|
sa.Column(
|
|
"app_id", sa.String(128), sa.ForeignKey("app_credentials.app_id"), nullable=False
|
|
),
|
|
sa.Column("account_id", sa.String(255), nullable=False),
|
|
sa.Column("request_id", sa.String(36), nullable=False),
|
|
sa.Column("fingerprint", sa.String(64), nullable=False),
|
|
sa.Column("request", sa.JSON(), nullable=False),
|
|
sa.Column("profile_version", sa.String(64), nullable=False),
|
|
sa.Column("status", sa.String(24), nullable=False),
|
|
sa.Column("rule_score", sa.Integer()),
|
|
sa.Column("ai_score", sa.Integer()),
|
|
sa.Column("ai_confidence", sa.Float()),
|
|
sa.Column("ai_reasoning", sa.String(2000)),
|
|
sa.Column("error_code", sa.String(64)),
|
|
sa.Column("final_score", sa.Integer()),
|
|
sa.Column("degraded", sa.Boolean(), nullable=False, server_default=sa.false()),
|
|
sa.Column("result_mode", sa.String(32)),
|
|
sa.Column("breakdown", sa.JSON()),
|
|
sa.Column("ai_evidence", sa.JSON()),
|
|
sa.Column(
|
|
"created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False
|
|
),
|
|
sa.Column("completed_at", sa.DateTime(timezone=True)),
|
|
sa.UniqueConstraint(
|
|
"app_id", "account_id", "request_id", name="uq_run_app_account_request"
|
|
),
|
|
)
|
|
for column in ("app_id", "status", "created_at"):
|
|
op.create_index(f"ix_scoring_runs_{column}", "scoring_runs", [column])
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_table("scoring_runs")
|
|
op.drop_table("ai_profile_audit_events")
|
|
op.drop_table("ai_profiles")
|
|
op.drop_table("admin_sessions")
|
|
op.drop_table("admin_users")
|
|
op.drop_table("app_credentials")
|