From 0a0f25cf56dfca4bde4da470c55aa992f3c76b2c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 18:44:21 +0000 Subject: [PATCH] Remove Pierce from /board and reassign his work Chloe takes the socials editor role, his socials leads, and three of his round 2 tasks (basketball RSVP form, social invites, socials calendar). Daryen books the RSF court. His round 2 set, round 1 row, member entry and submissions are removed. The live database gets the same changes once, on first load after deploy, tracked in a new board_changes table. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01QzNDQSmhjgKE63rwUnwcMq --- .env.example | 2 +- BOARD_SETUP.md | 2 +- components/board/SocialsTab.tsx | 4 +-- docs/board-preview.html | 27 +++++++--------- lib/board/roles.ts | 2 +- lib/board/setup.ts | 43 +++++++++++++++++++++++++ lib/board/starter-data.json | 50 ++++++++++++------------------ scripts/board-members.example.json | 9 +----- scripts/board-schema.sql | 6 ++++ 9 files changed, 86 insertions(+), 59 deletions(-) diff --git a/.env.example b/.env.example index 9c9073e..60f6f89 100644 --- a/.env.example +++ b/.env.example @@ -6,7 +6,7 @@ NEXT_PUBLIC_SITE_URL=https://www.getvindicated.org # Postgres service and reference it from the website service). DATABASE_URL= # Passwords for /board. Everyone on the board gets BOARD_PASSWORD (view and -# submit). Rana gets BOARD_ADMIN_PASSWORD (edit everything). Pierce gets +# submit). Rana gets BOARD_ADMIN_PASSWORD (edit everything). Chloe gets # BOARD_SOCIALS_PASSWORD (edit socials). Changing one signs out everyone # who used it. BOARD_PASSWORD= diff --git a/BOARD_SETUP.md b/BOARD_SETUP.md index 005585d..7e707a7 100644 --- a/BOARD_SETUP.md +++ b/BOARD_SETUP.md @@ -9,7 +9,7 @@ need a password. | Railway variable | Who gets it | What it unlocks | | ------------------------ | -------------------- | --------------------------------------- | | `BOARD_PASSWORD` | everyone on the board | view everything, submit assignments | -| `BOARD_SOCIALS_PASSWORD` | Pierce | also add, edit and delete socials | +| `BOARD_SOCIALS_PASSWORD` | Chloe | also add, edit and delete socials | | `BOARD_ADMIN_PASSWORD` | Rana | edit everything | Use three different passwords. People stay signed in on a device for 30 diff --git a/components/board/SocialsTab.tsx b/components/board/SocialsTab.tsx index 68189bb..c0698ac 100644 --- a/components/board/SocialsTab.tsx +++ b/components/board/SocialsTab.tsx @@ -142,7 +142,7 @@ export function SocialsTab() { title="Add a social" table="socials" fields={SOCIAL_FIELDS} - initial={{ title: "", date: "", time: "", location: "", kind: "b", status: "Idea", lead: "Pierce", cost: "", note: "" }} + initial={{ title: "", date: "", time: "", location: "", kind: "b", status: "Idea", lead: "Chloe", cost: "", note: "" }} onClose={() => setEditing(null)} onSaved={(v) => jumpTo(v.date)} /> @@ -233,7 +233,7 @@ export function SocialsTab() { ); })} -

Status runs Idea → Planning → Confirmed → Completed. Pierce leads socials unless noted.

+

Status runs Idea → Planning → Confirmed → Completed. Chloe leads socials unless noted.

); } diff --git a/docs/board-preview.html b/docs/board-preview.html index b49f96f..58f7aca 100644 --- a/docs/board-preview.html +++ b/docs/board-preview.html @@ -306,7 +306,7 @@

All socials

-

Status runs Idea → Planning → Confirmed → Completed. Pierce leads socials unless noted.

+

Status runs Idea → Planning → Confirmed → Completed. Chloe leads socials unless noted.

@@ -351,7 +351,6 @@

Board meeting · Sep 21, 2026

P("Yunchuan Wang","Research Analyst","Research & Legal","member17@example.com","(555) 555-0117"), P("Maria Miranda Nadsady","Legal Research","Research & Legal","member18@example.com","(555) 555-0118"), P("Chloe Yuching Lin","Outreach Lead · Social Media","Outreach","member19@example.com","(555) 555-0119",{ lead: true }), - P("Pierce Matthew Kosobayashi","Socials","Outreach","member20@example.com","(555) 555-0120"), P("Rami K Dakak","Research Analyst","Research & Legal","member21@example.com","(555) 555-0121") ]; const openSeats = {}; @@ -419,22 +418,21 @@

Board meeting · Sep 21, 2026

{ name:"Chloe", role:"Outreach Lead · Social Media", items:[ T("Post twice on @ucb_vindicated before Monday night","Link to each post"), T("2-week content calendar: what gets posted, which days, who makes each one","Doc link"), - T("Follow up with the high schools and YMCA programs you emailed in round 1 that haven't replied","Screenshot of each follow-up, plus a list of who replied")] }, + T("Follow up with the high schools and YMCA programs you emailed in round 1 that haven't replied","Screenshot of each follow-up, plus a list of who replied"), + T("RSVP form for VINdiBasketball (Sat Oct 17), posted on @ucb_vindicated","Form link and post link"), + T("Send invites for every social on the Socials calendar to the full member email list","Screenshot of the sent email showing the recipients"), + T("Keep the Socials calendar current: confirm each location and update it on the page","The updated calendar")] }, { name:"Noirit", role:"IVP · Price Is Right Lead", items:[ T("Price Is Right week 2 check: pipeline started, database set up, game screens running with placeholder data","GitHub commit links and a screenshot of the screens"), T("Sunday night: message every board member who hasn't submitted yet","Screenshot of the messages")] }, - { name:"Pierce", role:"Socials", items:[ - T("VINdiBasketball: set the date and book an RSF court","Booking confirmation"), - T("RSVP form for basketball, sent to Chloe to post","Form link"), - T("Send invites for every social on the Socials calendar to the full member email list","Screenshot of the sent email showing the recipients"), - T("Keep the Socials calendar current: confirm each location and update it on the page","The updated calendar")] }, { name:"Ian", role:"Software Lead", items:[ T("Get access to the website repo from Rizwaan or Ray","Screenshot showing access"), T("Assign 3 website-fix pull requests to Ryan and Ethan: write each fix as a GitHub issue with what's broken and what done looks like","Links to the 3 issues, each assigned to Ryan or Ethan")] }, { name:"Halima", role:"EVP · Partnerships", items:[ T("Reach out to 10 Berkeley student orgs that make videos, starting with Cal TV, about filming or collaborating with us","Screenshot of each sent email or DM, plus a list of the 10 orgs and who replied")] }, { name:"Daryen", role:"Communications Lead", items:[ - T("Call 5 local mechanics about recording a short video with us (carried over from round 1)","Call log: shop name, number, time called, what they said")] }, + T("Call 5 local mechanics about recording a short video with us (carried over from round 1)","Call log: shop name, number, time called, what they said"), + T("Book an RSF court for VINdiBasketball, Sat Oct 17, 2–4pm","Booking confirmation")] }, { name:"Jordan", role:"Data Lead", items:[ T("Project spec, including how many people you need (carried over)","Doc link"), T("Message James Cheng about the project (carried over)","Screenshot of the message"), @@ -447,7 +445,6 @@

Board meeting · Sep 21, 2026

["Ian","Follow up with Rizwaan, project spec","Marked completed"], ["Chloe","Event ideas, 5 mechanic calls, 10 high schools + YMCA","Marked completed"], ["Daryen","Help Halima, 5 mechanic calls","Not done"], - ["Pierce","Event ideas doc, workshop timeline, connect with Halima","Not done"], ["Jordan","Project spec, connect with James, answer Ray","Not done"] ]; document.getElementById("r1-count").textContent = `${round1.filter(r => r[2] !== "Not done").length} of ${round1.length} done`; @@ -522,13 +519,13 @@

Board meeting · Sep 21, 2026

/* ---------- socials ---------- */ // kind: b = Berkeley, x = UCSC x UCB, o = online, org = org date (not a social) const socials = [ - { date:"2026-10-17", time:"2:00–4:00pm", title:"VINdiBasketball", where:"RSF", kind:"b", lead:"Pierce", status:"Planning", cost:"Free. Optional boba after, self-pay.", note:"First Berkeley social. Court booking and RSVP form due Mon, Oct 12." }, + { date:"2026-10-17", time:"2:00–4:00pm", title:"VINdiBasketball", where:"RSF", kind:"b", lead:"Chloe", status:"Planning", cost:"Free. Optional boba after, self-pay.", note:"First Berkeley social. Court booking and RSVP form due Mon, Oct 12." }, { date:"2026-10-21", time:"9:00–10:00pm", title:"Skribbl night", where:"Discord", kind:"o", lead:"Chloe", status:"Planning", cost:"Free", note:"Open to all three chapters. Chloe posts the link that afternoon." }, { date:"2026-10-24", time:"Afternoon", title:"UCSC × UCB social", where:"San Francisco · spot TBD", kind:"x", lead:"Rana + Ashwin", status:"Idea", cost:"Self-pay", note:"Combined social with UCSC. Location still being decided." }, - { date:"2026-10-30", time:"5:00–8:00pm", title:"Glade Night + Chipotle", where:"Memorial Glade", kind:"b", lead:"Pierce", status:"Planning", cost:"Chipotle catering from the $240, if the Oct 13 budget allows", note:"Halloween eve, costumes optional. Last week of daylight before clocks change." }, + { date:"2026-10-30", time:"5:00–8:00pm", title:"Glade Night + Chipotle", where:"Memorial Glade", kind:"b", lead:"Chloe", status:"Planning", cost:"Chipotle catering from the $240, if the Oct 13 budget allows", note:"Halloween eve, costumes optional. Last week of daylight before clocks change." }, { date:"2026-11-06", time:"", title:"Price Is Right demo", where:"", kind:"org", lead:"Noirit", status:"", cost:"", note:"Not a social. No socials Nov 5–15." }, { date:"2026-11-18", time:"8:00–10:30pm", title:"Movie Night + Menchie's", where:"TBD", kind:"b", lead:"Daryen (movie), Chloe (Menchie's)", status:"Idea", cost:"Self-pay froyo", note:"" }, - { date:"2026-11-21", time:"1:00–4:00pm", title:"UCSC × UCB basketball", where:"Irvington Park, 41825 Blacow Rd, Fremont", kind:"x", lead:"Pierce + UCSC lead", status:"Idea", cost:"Free", note:"Meet-in-the-middle game, separate from VINdiBasketball. Outdoor court, first come. Backup: Karl Nordvik Park." }, + { date:"2026-11-21", time:"1:00–4:00pm", title:"UCSC × UCB basketball", where:"Irvington Park, 41825 Blacow Rd, Fremont", kind:"x", lead:"Chloe + UCSC lead", status:"Idea", cost:"Free", note:"Meet-in-the-middle game, separate from VINdiBasketball. Outdoor court, first come. Backup: Karl Nordvik Park." }, ]; const SOCIALS_KEY = "vin-socials-v1"; try { const saved = JSON.parse(localStorage.getItem(SOCIALS_KEY) || "null"); if (Array.isArray(saved) && saved.length) socials.splice(0, socials.length, ...saved); } catch (_) {} @@ -567,7 +564,7 @@

Board meeting · Sep 21, 2026

const card = document.getElementById("ev-card"); if (editEv !== null) { - const s = editEv === "new" ? { date: "", time: "", title: "", where: "", kind: "b", lead: "Pierce", status: "Idea", cost: "", note: "" } : socials[editEv]; + const s = editEv === "new" ? { date: "", time: "", title: "", where: "", kind: "b", lead: "Chloe", status: "Idea", cost: "", note: "" } : socials[editEv]; const opt = (v, cur, label) => ``; card.hidden = false; card.innerHTML = `

${editEv === "new" ? "Add a social" : "Edit " + esc(s.title)}

@@ -591,7 +588,7 @@

Board meeting · Sep 21, 2026

${editEv !== "new" ? `` : ""} -

Preview: edits save in this browser only. On the live site, Pierce and Rana can edit and everyone sees the change.

+

Preview: edits save in this browser only. On the live site, Chloe and Rana can edit and everyone sees the change.

`; } else if (openEv === null) card.hidden = true; diff --git a/lib/board/roles.ts b/lib/board/roles.ts index cebb4cd..b6a503f 100644 --- a/lib/board/roles.ts +++ b/lib/board/roles.ts @@ -1,7 +1,7 @@ // Who can do what on /board. People sign in with one of three passwords, // all set as environment variables in Railway: // BOARD_PASSWORD everyone on the board: view and submit -// BOARD_SOCIALS_PASSWORD socials editor (Pierce): also add/edit/delete socials +// BOARD_SOCIALS_PASSWORD socials editor (Chloe): also add/edit/delete socials // BOARD_ADMIN_PASSWORD admin (Rana): edit everything // Where assignment submissions are emailed. diff --git a/lib/board/setup.ts b/lib/board/setup.ts index a8e3661..6a8fcd8 100644 --- a/lib/board/setup.ts +++ b/lib/board/setup.ts @@ -55,6 +55,7 @@ async function setup() { if (await empty("board_meetings")) { for (const m of starter.meetings) await sql`INSERT INTO board_meetings ${sql(m)}`; } + await removePierce(sql); } const OLD_IAN = "Start the /board page on getvindicated.org from this preview"; @@ -82,3 +83,45 @@ async function retaskRound2(sql: ReturnType) { } }); } + +type Round2 = [string, string, [string, string][]][]; + +// Pierce left the board on Oct 11. Removes him, his assignments and +// submissions, gives his socials work to Chloe and the court booking to +// Daryen, and makes Chloe the lead on his socials. Runs once per database. +async function removePierce(sql: ReturnType) { + const round2 = starter.round2 as Round2; + const added: Record = { + Chloe: [ + "RSVP form for VINdiBasketball (Sat Oct 17), posted on @ucb_vindicated", + "Send invites for every social on the Socials calendar to the full member email list", + "Keep the Socials calendar current: confirm each location and update it on the page", + ], + Daryen: ["Book an RSF court for VINdiBasketball, Sat Oct 17, 2–4pm"], + }; + await sql.begin(async (tx) => { + const [first] = await tx`INSERT INTO board_changes (name) VALUES ('2026-10-11-remove-pierce') + ON CONFLICT DO NOTHING RETURNING name`; + if (!first) return; + + await tx`DELETE FROM board_members + WHERE lower(email) = 'pierce.kosobayashi@berkeley.edu' OR name ILIKE '%Kosobayashi%'`; + await tx`DELETE FROM board_submissions WHERE person = 'Pierce'`; + await tx`DELETE FROM board_assignments WHERE person = 'Pierce'`; + await tx`UPDATE board_socials SET lead = replace(lead, 'Pierce', 'Chloe') WHERE lead LIKE '%Pierce%'`; + + for (const [person, tasks] of Object.entries(added)) { + const [, role, items] = round2.find(([p]) => p === person)!; + const [last] = await tx`SELECT max(sort) AS sort, max(due_date) AS due FROM board_assignments + WHERE round = 2 AND person = ${person}`; + let sort = (last?.sort ?? 0) + 1; + for (const task of tasks) { + const [, proof] = items.find(([t]) => t === task)!; + const [exists] = await tx`SELECT 1 FROM board_assignments WHERE round = 2 AND person = ${person} AND task = ${task}`; + if (exists) continue; + await tx`INSERT INTO board_assignments (round, person, person_role, task, proof_required, due_date, sort) + VALUES (2, ${person}, ${role}, ${task}, ${proof}, ${last?.due ?? starter.dueRound2}, ${sort++})`; + } + } + }); +} diff --git a/lib/board/starter-data.json b/lib/board/starter-data.json index cc08a14..f1852c1 100644 --- a/lib/board/starter-data.json +++ b/lib/board/starter-data.json @@ -16,6 +16,18 @@ [ "Follow up with the high schools and YMCA programs you emailed in round 1 that haven't replied", "Screenshot of each follow-up, plus a list of who replied" + ], + [ + "RSVP form for VINdiBasketball (Sat Oct 17), posted on @ucb_vindicated", + "Form link and post link" + ], + [ + "Send invites for every social on the Socials calendar to the full member email list", + "Screenshot of the sent email showing the recipients" + ], + [ + "Keep the Socials calendar current: confirm each location and update it on the page", + "The updated calendar" ] ] ], @@ -33,28 +45,6 @@ ] ] ], - [ - "Pierce", - "Socials", - [ - [ - "VINdiBasketball: set the date and book an RSF court", - "Booking confirmation" - ], - [ - "RSVP form for basketball, sent to Chloe to post", - "Form link" - ], - [ - "Send invites for every social on the Socials calendar to the full member email list", - "Screenshot of the sent email showing the recipients" - ], - [ - "Keep the Socials calendar current: confirm each location and update it on the page", - "The updated calendar" - ] - ] - ], [ "Ian", "Software Lead", @@ -86,6 +76,10 @@ [ "Call 5 local mechanics about recording a short video with us (carried over from round 1)", "Call log: shop name, number, time called, what they said" + ], + [ + "Book an RSF court for VINdiBasketball, Sat Oct 17, 2–4pm", + "Booking confirmation" ] ] ], @@ -139,12 +133,6 @@ "missing", "Not done" ], - [ - "Pierce", - "Event ideas doc, workshop timeline, connect with Halima", - "missing", - "Not done" - ], [ "Jordan", "Project spec, connect with James, answer Ray", @@ -159,7 +147,7 @@ "title": "VINdiBasketball", "location": "RSF", "kind": "b", - "lead": "Pierce", + "lead": "Chloe", "status": "Planning", "cost": "Free. Optional boba after, self-pay.", "note": "First Berkeley social. Court booking and RSVP form due Mon, Oct 12." @@ -192,7 +180,7 @@ "title": "Glade Night + Chipotle", "location": "Memorial Glade", "kind": "b", - "lead": "Pierce", + "lead": "Chloe", "status": "Planning", "cost": "Chipotle catering from the $240, if the Oct 13 budget allows", "note": "Halloween eve, costumes optional. Last week of daylight before clocks change." @@ -225,7 +213,7 @@ "title": "UCSC × UCB basketball", "location": "Irvington Park, 41825 Blacow Rd, Fremont", "kind": "x", - "lead": "Pierce + UCSC lead", + "lead": "Chloe + UCSC lead", "status": "Idea", "cost": "Free", "note": "Meet-in-the-middle game, separate from VINdiBasketball. Outdoor court, first come. Backup: Karl Nordvik Park." diff --git a/scripts/board-members.example.json b/scripts/board-members.example.json index 22268b4..b6cdcb3 100644 --- a/scripts/board-members.example.json +++ b/scripts/board-members.example.json @@ -141,13 +141,6 @@ "phone": "(555) 555-0118", "lead": true }, - { - "name": "Pierce Matthew Kosobayashi", - "role": "Socials", - "team": "Outreach", - "email": "member20@example.com", - "phone": "(555) 555-0119" - }, { "name": "Rami K Dakak", "role": "Research Analyst", @@ -155,4 +148,4 @@ "email": "member21@example.com", "phone": "(555) 555-0120" } -] \ No newline at end of file +] diff --git a/scripts/board-schema.sql b/scripts/board-schema.sql index 0b72b77..81bdc6e 100644 --- a/scripts/board-schema.sql +++ b/scripts/board-schema.sql @@ -69,3 +69,9 @@ CREATE TABLE IF NOT EXISTS board_meetings ( summary text NOT NULL DEFAULT '', recording_url text NOT NULL DEFAULT '' ); + +-- One-time data changes already applied to this database (see lib/board/setup.ts). +CREATE TABLE IF NOT EXISTS board_changes ( + name text PRIMARY KEY, + applied_at timestamptz NOT NULL DEFAULT now() +);