feat(schedule): publishable schedules via reveal-level enum#48
Merged
Conversation
Captures the grilling outcome for "make schedules publishable" (#46): - CONTEXT.md glossary with festival/edition/lineup/schedule/set/stage terminology and the resolved publish-state model (edition.published is separate from the schedule reveal level) - ADR-0001 records the decision to model schedule visibility as an ordered enum (draft < days < stages < full) on festival_editions, with the rejected alternatives (boolean, independent flags, versioned schedules, per-day granularity) https://claude.ai/code/session_01D6SJEwugBTwcYZt4ZzDQVC
We chose client-side hide over a public_sets view for simplicity. The wire leak is acknowledged; server-side hardening is the documented upgrade path.
Ordered enum draft < days < stages < full on festival_editions. Defaults to draft for new editions. Existing editions with published = true are backfilled to full so the migration does not silently hide currently-visible schedules.
scheduleReveal exposes: - isAtLeast(level, threshold) for ordered comparison - canShowDay / canShowStage / canShowTime predicates for per-field visibility checks (used where the time-of-day vs date distinction matters and a null check isn't enough) - maskSetForReveal for the common case of nulling embargoed fields on a set object before rendering
- New useScheduleReveal hook combining edition + admin status into canShowDay/canShowStage/canShowTime predicates - formatDayOnly helper in timeUtils for the day-only display path - SetMetadata, SetInfoCard, MultiArtistSetInfoCard, SetCardHeader, Timeline, ListSchedule now honour the level: stage badge appears at stages+, time range at full, date-only label at days/stages - Schedule tab placeholder is now gated by canShowTime instead of edition.published (decoupling the lineup-published gate from the schedule-revealed gate)
- Schedule reveal dropdown in the edition edit dialog (FestivalEditionManagement) with all four levels and a hint when the edition isn't published yet - ScheduleRevealAdminPanel on top of the Schedule tab with progressive Reveal Days / Reveal Stages / Reveal Times buttons. Each revealed step becomes a status badge with an undo button for demotion. Hidden for non-admins. - Loosen useUpdateFestivalEdition's editionData type to the generated Update shape so callers can patch a single field
#46) - ScheduleNotRevealedPlaceholder centralises the copy and varies it by level (draft / days / stages) - ScheduleTabIndicator renders an amber dot on the Schedule tab icon (desktop + mobile) when the schedule isn't at 'full' yet - Import wizard shows a 'Schedule is currently revealed at X' warning above the commit button when the current level is above draft, with a quick diff summary of what becomes public
…mment - Extract the schedule reveal Select + hint into its own component next to FestivalEditionManagement - Drop redundant comment in Timeline.tsx — the canShowTime check speaks for itself
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Deploy →
|
…button (#46) - Move reveal controls out of the user-facing Schedule tab; admins now see the same schedule view as regular users - New ScheduleRevealControl on the admin edition header: single button that advances to the next level (Reveal days -> stages -> times), with an undo arrow for demotion - Drop the isAdmin bypass from useScheduleReveal so the level rule is uniform; admin pages that need full visibility query sets directly
There was a problem hiding this comment.
Pull request overview
Adds progressive schedule reveal support for festival editions, allowing schedule visibility to move through draft → days → stages → full independently from edition publishing while updating public/admin UI and import warnings.
Changes:
- Adds the
schedule_reveal_levelenum/column, generated Supabase types, ADR/domain documentation, and reveal utility tests. - Masks schedule stage/time display across public set, artist, explore, schedule, and tab navigation surfaces.
- Adds admin controls for reveal level management and import warnings when committing changes to an already revealed schedule.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
supabase/migrations/20260530000000_add_schedule_reveal_level.sql |
Adds enum/column and promotes existing published editions to full. |
src/integrations/supabase/types.ts |
Regenerates Supabase types for the new enum/column. |
src/lib/scheduleReveal.ts |
Defines reveal ordering, predicates, and set masking helper. |
src/lib/scheduleReveal.test.ts |
Adds unit coverage for reveal behavior. |
src/lib/timeUtils.ts |
Adds day-only date formatting. |
src/hooks/useScheduleReveal.ts |
Exposes reveal predicates to UI components. |
src/hooks/queries/festivals/editions/useCreateFestivalEdition.ts |
Allows create payloads to include reveal level. |
src/hooks/queries/festivals/editions/useUpdateFestivalEdition.ts |
Broadens update payload typing for reveal-level updates. |
src/pages/admin/festivals/FestivalEditionManagement.tsx |
Adds reveal dropdown to edition edit/create form. |
src/pages/admin/festivals/ScheduleRevealLevelField.tsx |
Adds admin reveal-level select field. |
src/pages/admin/festivals/ScheduleRevealControl.tsx |
Adds progressive reveal/demote control. |
src/pages/admin/festivals/FestivalEdition.tsx |
Displays reveal controls in the admin edition header. |
src/routes/admin/festivals/$festivalSlug/editions/$editionSlug/import.tsx |
Passes current reveal level to import wizard. |
src/components/Admin/ScheduleImport/ScheduleImportWizard.tsx |
Threads reveal level through wizard state. |
src/components/Admin/ScheduleImport/ReviewStage.tsx |
Passes reveal level to the diff review step. |
src/components/Admin/ScheduleImport/DiffReviewStep.tsx |
Shows live-update warning when committing revealed schedules. |
src/pages/EditionView/tabs/ScheduleTab/ScheduleNotRevealedPlaceholder.tsx |
Adds level-aware schedule placeholder copy. |
src/pages/EditionView/tabs/ScheduleTab/list/ListSchedule.tsx |
Hides list schedule until exact times are revealed. |
src/pages/EditionView/tabs/ScheduleTab/horizontal/Timeline.tsx |
Hides timeline until exact times are revealed. |
src/pages/EditionView/tabs/ArtistsTab/SetCard/SetMetadata.tsx |
Masks stage/time metadata by reveal level. |
src/pages/SetDetails/SetInfoCard.tsx |
Masks single-artist set stage/time metadata by reveal level. |
src/pages/SetDetails/MultiArtistSetInfoCard.tsx |
Masks multi-artist set stage/time metadata by reveal level. |
src/pages/ExploreSetPage/SetExploreCard/SetCardHeader.tsx |
Masks explore-card date/time/stage details by reveal level. |
src/pages/EditionView/TabNavigation/ScheduleTabIndicator.tsx |
Adds not-fully-revealed schedule indicator. |
src/pages/EditionView/TabNavigation/MobileTabButton.tsx |
Displays schedule indicator on mobile nav. |
src/pages/EditionView/TabNavigation/DesktopTabButton.tsx |
Displays schedule indicator on desktop nav. |
docs/adr/0001-schedule-reveal-level.md |
Documents reveal-level architecture and tradeoffs. |
CONTEXT.md |
Adds shared domain glossary and publish-state definitions. |
…rning (#46) - useUpdateFestivalEdition was only invalidating festivalsKeys.all(); the editions-by-slug cache lives under ["festival-editions"], so changing schedule_reveal_level from the admin control kept the old level visible until reload - Extract the import-wizard live-commit alert into LiveCommitWarning
useScheduleReveal no longer threads admin status, so canShowDay/ canShowStage/canShowTime/maskSetForReveal no longer need the parameter. Cleaner call sites and tests.
chiptus
commented
May 30, 2026
TabConfig grows an optional Indicator component. Schedule tab wires ScheduleTabIndicator there; Desktop/Mobile buttons render config.Indicator generically instead of branching on config.key.
The stage filter and date-asc sort in useSetFiltering still read set.stage_id and set.time_start directly, so the embargoed fields leaked through filter/sort even after the badges and time labels were hidden in the cards. - maskSetForReveal now truncates time_start to date-only at days/stages so sorting can't infer time-of-day ordering - ArtistsTab masks the sets array before passing it into useSetFiltering, so the stage filter sees nulled stage_id at draft/days and the date sort sees day-granularity timestamps at days/stages
Reverted d326db9's data-layer mask in favour of a UI-layer fix: DesktopFilters and MobileFilters now hide the stage filter when canShowStage is false. Stays consistent with the user-facing hide-in-display rule, and the stage filter no longer renders a control that would silently return empty results at draft/days.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
schedule_reveal_levelenum (draft<days<stages<full) onfestival_editionsso the Core Team can release the schedule progressively, independently ofedition.published. Field visibility is masked client-side (perdocs/adr/0001-schedule-reveal-level.md); admin controls live in the edition edit dialog and on the Schedule tab.Closes #46.
Manual verification
Prereq: apply the new migration (
supabase/migrations/20260530000000_add_schedule_reveal_level.sql) and regenerate types.Admin
draft / days / stages / full. Toggle the Published switch off — the hint "Configured but not active — edition is not published" should appear when the level is abovedraft.draft.draft.draftthere should be no banner above the commit button. Bump the level on the edition todays(or higher) and re-enter the wizard — the warning "Schedule is days revealed. Committing will update what the public sees immediately…" should now appear above the commit button.Public (incognito or signed out)
full.draft: open the Schedule tab → "Schedule not yet published." On the Artists tab, set cards should show no stage badge and no time/day text.days. Reload. Schedule tab now reads "Day-by-day lineup is out — exact times coming soon." On the Artists tab, set cards should show a day label (e.g. "Fri, Aug 1") but no stage badge and no time-of-day.stages. Reload. Schedule tab reads "Stages assigned — exact times coming soon." Artist-tab set cards should show day and the stage badge, but still no time-of-day.full. Reload. The Schedule tab renders the full timeline / list as before, the amber dot disappears, and set cards show day + stage + time range.Generated by Claude Code