Skip to content

Commit 3995188

Browse files
committed
feat(portal,ops,sanity): add hybrid podcast workflow pipeline, needs_reschedule flow, and post-production rough cut + draft episode preview
1 parent fb41649 commit 3995188

11 files changed

Lines changed: 1729 additions & 108 deletions

File tree

‎apps/ops/src/App.tsx‎

Lines changed: 657 additions & 41 deletions
Large diffs are not rendered by default.

‎apps/sanity/schemas/documents/booking.ts‎

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,19 @@ export default defineType({
7171
}),
7272
defineField({
7373
name: 'status',
74-
title: 'Booking Status',
74+
title: 'Booking & Post-Production Workflow Status',
7575
type: 'string',
7676
options: {
7777
list: [
7878
{title: 'Pending Review / Calendar Hold (Opaque Busy)', value: 'pending'},
79+
{title: 'Needs Reschedule / On Hold (Awaiting Slot)', value: 'needs_reschedule'},
7980
{title: 'Approved (StreamYard Sent)', value: 'approved'},
8081
{title: 'Scheduled on Google Calendar', value: 'scheduled'},
8182
{title: 'Confirmed', value: 'confirmed'},
82-
{title: 'Recorded', value: 'recorded'},
83+
{title: 'Recorded (Raw Session Complete)', value: 'recorded'},
84+
{title: 'In Editing / Post-Production', value: 'editing'},
85+
{title: 'Rough Cut / Guest Review', value: 'guest_review'},
86+
{title: 'Ready to Publish', value: 'ready_to_publish'},
8387
{title: 'Published', value: 'published'},
8488
{title: 'Declined / Cancelled', value: 'cancelled'},
8589
],
@@ -91,6 +95,41 @@ export default defineType({
9195
title: 'Requested Recording Slot (UTC ISO)',
9296
type: 'datetime',
9397
}),
98+
defineField({
99+
name: 'previousSlotStartAt',
100+
title: 'Previous / Missed Recording Slot (UTC ISO)',
101+
type: 'datetime',
102+
description: 'Archived timestamp when a booking is moved to Needs Reschedule or rebooked.',
103+
}),
104+
defineField({
105+
name: 'rescheduleReason',
106+
title: 'Reschedule / On-Hold Reason',
107+
type: 'string',
108+
description: 'Context shown in Ops App and Guest Portal when a booking needs a new slot.',
109+
}),
110+
defineField({
111+
name: 'podcastSlug',
112+
title: 'Linked Podcast Episode Slug',
113+
type: 'string',
114+
description: 'Slug of the linked draft or published podcast episode in Sanity.',
115+
}),
116+
defineField({
117+
name: 'podcastDocId',
118+
title: 'Linked Podcast Document ID',
119+
type: 'string',
120+
description: 'Document ID of the linked draft or published podcast episode (for example, drafts.podcast-slug).',
121+
}),
122+
defineField({
123+
name: 'roughCutUrl',
124+
title: 'Unlisted YouTube / Rough-Cut Review URL',
125+
type: 'url',
126+
description: 'Unlisted YouTube video URL (or Descript/Frame link) embedded in the Guest Studio Portal for rough-cut review.',
127+
}),
128+
defineField({
129+
name: 'targetPublishDate',
130+
title: 'Target Episode Publish Date (UTC ISO)',
131+
type: 'datetime',
132+
}),
94133
defineField({
95134
name: 'recordingUrl',
96135
title: 'Recording Studio URL (StreamYard)',

‎apps/sanity/schemas/documents/podcast.ts‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,36 @@ export default defineType({
2222
],
2323
fields: [
2424
...contentType.fields,
25+
defineField({
26+
name: "workflowStage",
27+
title: "Post-Production Workflow Stage",
28+
type: "string",
29+
group: "podcast",
30+
options: {
31+
list: [
32+
{ title: "Recorded (Raw Session)", value: "recorded" },
33+
{ title: "In Editing / Post-Production", value: "editing" },
34+
{ title: "Rough Cut / Guest Review", value: "guest_review" },
35+
{ title: "Ready to Publish", value: "ready_to_publish" },
36+
{ title: "Published", value: "published" },
37+
],
38+
},
39+
initialValue: "editing",
40+
}),
41+
defineField({
42+
name: "bookingRef",
43+
title: "Linked Booking Document ID",
44+
type: "string",
45+
group: "podcast",
46+
description: "Document ID of the originating booking (for example, private.booking-...).",
47+
}),
48+
defineField({
49+
name: "roughCutNotes",
50+
title: "Post-Production & Scrub Notes",
51+
type: "text",
52+
group: "podcast",
53+
description: "Internal and guest/PR edit notes (such as visual cuts or PII checks) before publishing.",
54+
}),
2555
defineField({
2656
name: "podcastType",
2757
title: "Podcast Type",

‎apps/sanity/structure.ts‎

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,40 @@ export const editorialStructure: StructureResolver = (S) =>
136136
.schemaType("booking")
137137
.apiVersion("2025-02-19")
138138
.filter(
139-
'_type == "booking" && status in ["approved", "scheduled"] && (_id in path("private.**") || _id in path("*"))',
139+
'_type == "booking" && status in ["approved", "scheduled", "confirmed"] && (_id in path("private.**") || _id in path("*"))',
140140
)
141141
.defaultOrdering([
142142
{ field: "slotStartAt", direction: "asc" },
143143
]),
144144
),
145+
S.listItem()
146+
.title("Needs Reschedule / On Hold")
147+
.child(
148+
S.documentList()
149+
.title("Needs Reschedule / On Hold")
150+
.schemaType("booking")
151+
.apiVersion("2025-02-19")
152+
.filter(
153+
'_type == "booking" && status == "needs_reschedule" && (_id in path("private.**") || _id in path("*"))',
154+
)
155+
.defaultOrdering([
156+
{ field: "_updatedAt", direction: "desc" },
157+
]),
158+
),
159+
S.listItem()
160+
.title("Post-Production Pipeline (Recorded / Editing / Guest Review)")
161+
.child(
162+
S.documentList()
163+
.title("Post-Production Pipeline")
164+
.schemaType("booking")
165+
.apiVersion("2025-02-19")
166+
.filter(
167+
'_type == "booking" && status in ["recorded", "editing", "guest_review", "ready_to_publish"] && (_id in path("private.**") || _id in path("*"))',
168+
)
169+
.defaultOrdering([
170+
{ field: "_updatedAt", direction: "desc" },
171+
]),
172+
),
145173
S.divider(),
146174
S.listItem()
147175
.title("All Sponsor Leads & Deal Rooms")
@@ -372,6 +400,45 @@ export const editorialStructure: StructureResolver = (S) =>
372400
{ field: "_updatedAt", direction: "desc" },
373401
]),
374402
),
403+
S.listItem()
404+
.title("Pipeline: In Editing / Post-Production")
405+
.child(
406+
S.documentList()
407+
.title("In Editing / Post-Production")
408+
.schemaType("podcast")
409+
.filter(
410+
'_type == "podcast" && workflowStage in ["recorded", "editing"]',
411+
)
412+
.defaultOrdering([
413+
{ field: "_updatedAt", direction: "desc" },
414+
]),
415+
),
416+
S.listItem()
417+
.title("Pipeline: Rough Cut / Guest Review")
418+
.child(
419+
S.documentList()
420+
.title("Rough Cut / Guest Review")
421+
.schemaType("podcast")
422+
.filter(
423+
'_type == "podcast" && workflowStage == "guest_review"',
424+
)
425+
.defaultOrdering([
426+
{ field: "_updatedAt", direction: "desc" },
427+
]),
428+
),
429+
S.listItem()
430+
.title("Pipeline: Ready to Publish")
431+
.child(
432+
S.documentList()
433+
.title("Ready to Publish")
434+
.schemaType("podcast")
435+
.filter(
436+
'_type == "podcast" && workflowStage == "ready_to_publish"',
437+
)
438+
.defaultOrdering([
439+
{ field: "_updatedAt", direction: "desc" },
440+
]),
441+
),
375442
S.divider(),
376443
S.listItem()
377444
.title("Needs Release Checklist")

‎apps/site/src/lib/google-calendar.ts‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ async function syncPrivateShadowCalendarBlocks(opts: {
3939
"Private Calendar Block synced from alex@codingcat.dev",
4040
`Room: ${studioOrMeet}`,
4141
`Guest: ${opts.guestName} (${opts.company})`,
42-
...(opts.portalUrl
43-
? [`Guest Studio Portal: ${opts.portalUrl}`]
44-
: []),
42+
...(opts.portalUrl ? [`Guest Studio Portal: ${opts.portalUrl}`] : []),
4543
].join("\n"),
4644
location: studioOrMeet,
4745
status: "confirmed",

‎apps/site/src/lib/sanity/preview.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ export function resolvePreview({
5050
return { enabled: false };
5151
}
5252

53-
const token = env?.SANITY_API_READ_TOKEN;
53+
const token =
54+
env?.SANITY_API_READ_TOKEN ||
55+
env?.SANITY_API_WRITE_TOKEN ||
56+
env?.SANITY_AUTH_TOKEN ||
57+
env?.SANITY_WRITE_TOKEN;
5458
if (!token) {
5559
return { enabled: false };
5660
}

0 commit comments

Comments
 (0)