fix: harden frontdoor and usage ingestion

This commit is contained in:
fawney19
2026-05-22 23:57:38 +08:00
parent 6ef6cbade2
commit d18b13a91a
25 changed files with 1363 additions and 252 deletions

View File

@@ -0,0 +1,21 @@
-- Usage is a historical fact table. Terminal usage events can arrive after
-- mutable catalog/auth rows have been disabled or deleted, so these snapshot
-- identity columns must not make ingestion depend on current dimension rows.
ALTER TABLE ONLY public.usage
DROP CONSTRAINT IF EXISTS usage_provider_id_fkey;
ALTER TABLE ONLY public.usage
DROP CONSTRAINT IF EXISTS usage_provider_endpoint_id_fkey;
ALTER TABLE ONLY public.usage
DROP CONSTRAINT IF EXISTS usage_provider_api_key_id_fkey;
ALTER TABLE ONLY public.usage
DROP CONSTRAINT IF EXISTS usage_api_key_id_fkey;
ALTER TABLE ONLY public.usage
DROP CONSTRAINT IF EXISTS usage_user_id_fkey;
ALTER TABLE ONLY public.usage
DROP CONSTRAINT IF EXISTS usage_wallet_id_fkey;

View File

@@ -583,80 +583,12 @@ END $mig$;
--
-- Name: usage usage_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
-- Usage is a historical fact table. Snapshot identity columns such as
-- user_id/api_key_id/provider_endpoint_id/provider_api_key_id/wallet_id
-- intentionally do not carry foreign keys because terminal usage events may
-- arrive after those mutable dimension rows have been disabled or deleted.
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_api_key_id_fkey FOREIGN KEY (provider_api_key_id) REFERENCES public.provider_api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_endpoint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_endpoint_id_fkey FOREIGN KEY (provider_endpoint_id) REFERENCES public.provider_endpoints(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_model_usage_counts user_model_usage_counts_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--

View File

@@ -7,7 +7,7 @@ use tracing::info;
// Generated by build.rs from schema/bootstrap/postgres.
pub(crate) static EMPTY_DATABASE_SNAPSHOT_SQL: &str =
include_str!(concat!(env!("OUT_DIR"), "/empty_database_snapshot.sql"));
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260520010000;
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260522000000;
const PUBLIC_BASE_TABLE_COUNT_SQL: &str = r#"
SELECT COUNT(*)::BIGINT

View File

@@ -312,6 +312,7 @@ fn empty_database_snapshot_covers_current_cutoff_versions() {
20260519130000,
20260520000000,
20260520010000,
20260522000000,
]
);
}
@@ -393,6 +394,34 @@ fn empty_database_snapshot_sql_includes_usage_body_blobs_and_audit_admin_role()
assert!(EMPTY_DATABASE_SNAPSHOT_SQL.contains("usage_count bigint DEFAULT 0 NOT NULL"));
}
#[test]
fn usage_identity_foreign_keys_are_decoupled_for_historical_ingestion() {
let migration = POSTGRES_MIGRATOR
.iter()
.find(|migration| migration.version == 20260522000000)
.expect("usage identity foreign key decoupling migration should be embedded");
for constraint in [
"usage_provider_id_fkey",
"usage_provider_endpoint_id_fkey",
"usage_provider_api_key_id_fkey",
"usage_api_key_id_fkey",
"usage_user_id_fkey",
"usage_wallet_id_fkey",
] {
assert!(
migration
.sql
.contains(format!("DROP CONSTRAINT IF EXISTS {constraint}").as_str()),
"migration should drop {constraint}"
);
assert!(
!EMPTY_DATABASE_SNAPSHOT_SQL.contains(format!("ADD CONSTRAINT {constraint}").as_str()),
"fresh bootstrap snapshot should not recreate {constraint}"
);
}
}
#[test]
fn empty_database_snapshot_sql_includes_payment_gateway_and_plans() {
assert!(EMPTY_DATABASE_SNAPSHOT_SQL.contains("payment_provider character varying(64)"));
@@ -1179,6 +1208,7 @@ fn pending_migrations_from_applied_skips_versions_already_applied() {
20260519130000,
20260520000000,
20260520010000,
20260522000000,
]
);
}