From 2953f0b2d7b39fad3914f726d20647e887abe447 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Mon, 20 Jul 2026 16:52:53 +0800 Subject: [PATCH] fix: permit chart profile upserts --- .../apply-supabase-profile-migrations.yml | 4 +++- .../src/hooks/use-birth-time-guided-journey.ts | 2 +- ...60718104000_chart_profiles_upsert_id_grant.sql | 6 ++++++ frontend/tests/birth-time-user-errors.test.ts | 6 ++++++ frontend/tests/chart-profile-upsert-grant.test.ts | 15 +++++++++++++++ tests/test_supabase_profile_migration_workflow.py | 1 + 6 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 frontend/supabase/migrations/20260718104000_chart_profiles_upsert_id_grant.sql create mode 100644 frontend/tests/chart-profile-upsert-grant.test.ts diff --git a/.github/workflows/apply-supabase-profile-migrations.yml b/.github/workflows/apply-supabase-profile-migrations.yml index 96ac8053..b479a410 100644 --- a/.github/workflows/apply-supabase-profile-migrations.yml +++ b/.github/workflows/apply-supabase-profile-migrations.yml @@ -46,6 +46,7 @@ jobs: frontend/supabase/migrations/20260718100000_repair_missing_chart_profiles.sql \ frontend/supabase/migrations/20260718102000_recover_missing_profile_rows.sql \ frontend/supabase/migrations/20260718103000_profile_birth_time_declaration_grants.sql \ + frontend/supabase/migrations/20260718104000_chart_profiles_upsert_id_grant.sql \ "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/tmp/profile-migrations/" - name: Apply profile migrations using VPS database URL @@ -74,7 +75,8 @@ jobs: tmp/profile-migrations/20260718080000_profiles_service_role_account_upsert_selects.sql \ tmp/profile-migrations/20260718100000_repair_missing_chart_profiles.sql \ tmp/profile-migrations/20260718102000_recover_missing_profile_rows.sql \ - tmp/profile-migrations/20260718103000_profile_birth_time_declaration_grants.sql + tmp/profile-migrations/20260718103000_profile_birth_time_declaration_grants.sql \ + tmp/profile-migrations/20260718104000_chart_profiles_upsert_id_grant.sql do echo "applying $(basename "$SQL_FILE")" cat "$SQL_FILE" | docker run --rm -i postgres:16-alpine \ diff --git a/frontend/src/hooks/use-birth-time-guided-journey.ts b/frontend/src/hooks/use-birth-time-guided-journey.ts index 052419d3..8fac6fbb 100644 --- a/frontend/src/hooks/use-birth-time-guided-journey.ts +++ b/frontend/src/hooks/use-birth-time-guided-journey.ts @@ -113,7 +113,7 @@ export function useBirthTimeGuidedJourney(input: GuidedJourneyInput): BirthTimeG publish: onJourney, })) latest.current = turn; }).catch((caught: unknown) => { - setError(caught instanceof Error ? caught.message : "当前步骤暂时无法完成,请重试。"); + setError(birthTimeUserError(caught)); }).finally(() => { release(); setPending(false); diff --git a/frontend/supabase/migrations/20260718104000_chart_profiles_upsert_id_grant.sql b/frontend/supabase/migrations/20260718104000_chart_profiles_upsert_id_grant.sql new file mode 100644 index 00000000..c63b9180 --- /dev/null +++ b/frontend/supabase/migrations/20260718104000_chart_profiles_upsert_id_grant.sql @@ -0,0 +1,6 @@ +begin; + +-- PostgREST upsert may include the unchanged conflict key in its update set. +grant update (id, role, profile, updated_at) on table public.chart_profiles to authenticated; + +commit; diff --git a/frontend/tests/birth-time-user-errors.test.ts b/frontend/tests/birth-time-user-errors.test.ts index 2bbf1219..fd611a84 100644 --- a/frontend/tests/birth-time-user-errors.test.ts +++ b/frontend/tests/birth-time-user-errors.test.ts @@ -1,4 +1,5 @@ import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; import test from "node:test"; import { birthTimeUserError } from "../src/lib/birth-time-user-error.ts"; @@ -12,3 +13,8 @@ test("birth-time errors never expose browser implementation messages", () => { test("birth-time errors preserve a safe server message", () => { assert.equal(birthTimeUserError(new Error("候选结果已变化")), "候选结果已变化"); }); + +test("all guided journey mutations normalize implementation errors", () => { + const source = readFileSync(new URL("../src/hooks/use-birth-time-guided-journey.ts", import.meta.url), "utf8"); + assert.equal((source.match(/setError\(birthTimeUserError\(caught\)\)/g) ?? []).length, 2); +}); diff --git a/frontend/tests/chart-profile-upsert-grant.test.ts b/frontend/tests/chart-profile-upsert-grant.test.ts new file mode 100644 index 00000000..dd7decaf --- /dev/null +++ b/frontend/tests/chart-profile-upsert-grant.test.ts @@ -0,0 +1,15 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import test from "node:test"; + +const migration = readFileSync( + new URL("../supabase/migrations/20260718104000_chart_profiles_upsert_id_grant.sql", import.meta.url), + "utf8", +); + +test("authenticated chart-profile upserts may update their unchanged conflict id", () => { + assert.match( + migration, + /grant\s+update\s*\(\s*id\s*,\s*role\s*,\s*profile\s*,\s*updated_at\s*\)\s+on\s+table\s+public\.chart_profiles\s+to\s+authenticated/i, + ); +}); diff --git a/tests/test_supabase_profile_migration_workflow.py b/tests/test_supabase_profile_migration_workflow.py index a7840760..1b518975 100644 --- a/tests/test_supabase_profile_migration_workflow.py +++ b/tests/test_supabase_profile_migration_workflow.py @@ -27,6 +27,7 @@ def test_profile_migration_workflow_includes_chart_library_and_birth_time_profil assert "20260718100000_repair_missing_chart_profiles.sql" in text assert "20260718102000_recover_missing_profile_rows.sql" in text assert "20260718103000_profile_birth_time_declaration_grants.sql" in text + assert "20260718104000_chart_profiles_upsert_id_grant.sql" in text def test_profile_migration_workflow_does_not_reference_missing_sql_files() -> None: