feat(fase-12): nav gating + redirect guard + realtime publication
UI side:
* DesktopSidebar / BottomTabBar filter their entries by $enabledSections,
tag each entry with data-section, and BottomTabBar exposes a
data-section-count attribute so the grid is observable from tests.
* "lists" is force-shown unconditionally — the §12.3.4 always-one-
landing rule covers the edge case where every layer says OFF.
* (app)/+layout.svelte adds a $effect that, when the URL matches a
disabled section (/tasks, /notes, /search), goto's /lists and shows
a transient `section_disabled_for_collective` toast.
* Root +layout.svelte exposes the supabase singleton on window.__sb
in dev so the new Playwright spec can patch rows without a parallel
client; dead-code-eliminated in production builds.
DB side:
* Migration 023 grows by ALTER PUBLICATION supabase_realtime ADD TABLE
public.users + public.collectives + REPLICA IDENTITY FULL on both.
Without this membership the features.ts subscriptions get zero
events and SV-02 (collective toggle → realtime → member's nav
updates) silently fails. Caught while running the spec.
* pgTAP 015 grows from 16 to 20 assertions to cover publication
membership + REPLICA IDENTITY for both new realtime tables.
Paraglide messages: section_disabled_for_collective, the visibility
section titles + blurbs, section_label_* per SectionKey. Both en + es.
Playwright tests/e2e/section-visibility.test.ts (SV-01..SV-03):
SV-01 user toggle → nav reflects → /tasks redirects to /lists
SV-02 admin collective toggle → member sees it disappear in realtime
SV-03 collective ON beats user OFF — per-collective resolution
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
CREATE EXTENSION IF NOT EXISTS pgtap;
|
||||
|
||||
BEGIN;
|
||||
SELECT plan(16);
|
||||
SELECT plan(20);
|
||||
|
||||
-- ── Schema invariants ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -158,5 +158,47 @@ SELECT is(
|
||||
'SV-T16: an unknown section key returns true (default ON, no migration race)'
|
||||
);
|
||||
|
||||
-- ── Realtime publication membership ─────────────────────────────────────────
|
||||
-- features.ts subscribes to UPDATE events on users (own row) + collectives
|
||||
-- (active row). Without the publication membership those subscriptions
|
||||
-- receive zero events. REPLICA IDENTITY FULL keeps OLD-row DELETE payloads
|
||||
-- intact for the same callers down the line.
|
||||
|
||||
SELECT ok(
|
||||
EXISTS (
|
||||
SELECT 1 FROM pg_publication_tables
|
||||
WHERE pubname = 'supabase_realtime'
|
||||
AND schemaname = 'public'
|
||||
AND tablename = 'users'
|
||||
),
|
||||
'SV-T17: public.users is part of the supabase_realtime publication'
|
||||
);
|
||||
|
||||
SELECT ok(
|
||||
EXISTS (
|
||||
SELECT 1 FROM pg_publication_tables
|
||||
WHERE pubname = 'supabase_realtime'
|
||||
AND schemaname = 'public'
|
||||
AND tablename = 'collectives'
|
||||
),
|
||||
'SV-T18: public.collectives is part of the supabase_realtime publication'
|
||||
);
|
||||
|
||||
SELECT results_eq(
|
||||
$$ SELECT relreplident::text FROM pg_class c
|
||||
JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE n.nspname = 'public' AND c.relname = 'users' $$,
|
||||
$$ VALUES ('f') $$,
|
||||
'SV-T19: public.users has REPLICA IDENTITY FULL'
|
||||
);
|
||||
|
||||
SELECT results_eq(
|
||||
$$ SELECT relreplident::text FROM pg_class c
|
||||
JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE n.nspname = 'public' AND c.relname = 'collectives' $$,
|
||||
$$ VALUES ('f') $$,
|
||||
'SV-T20: public.collectives has REPLICA IDENTITY FULL'
|
||||
);
|
||||
|
||||
SELECT * FROM finish();
|
||||
ROLLBACK;
|
||||
|
||||
Reference in New Issue
Block a user