PM Onboarding & Handoff

Welcome to School Storytellers

You're running bi-weekly marketing reports for private K–12 schools. Most of the work is already automated — your job is the judgment layer: verify, polish, send. Plan on 15–30 minutes per school per cycle.

Day 1 — Get set up

0 of 8 done

The job — your bi-weekly rhythm

  1. Monday morning, open the dashboard. The banner tells you which schools are due this week. Reports are due 4 days after a reporting period closes.
  2. Open the school's report. Stats are already pulled from the ad platforms and GA4, and an AI draft of the overview, channel notes, next steps, and client email is waiting.
  3. Enter the inquiry counts — the one manual stat (lead schools). In the report's Inquiry Reconciliation section, enter how many inquiries each form received this period (log into the school's form dashboard — the link and Loom walkthrough are right there). Cost per inquiry = ad spend ÷ total inquiries, so this number drives the headline metric. Platform "leads" often miss form fills — your verified count is the truth. As soon as you save a count, the cost-per-inquiry on that report updates instantly.
  4. Refresh the AI draft so the words match the numbers. This is the easy step to forget: entering inquiry counts updates the cost-per-inquiry number right away, but the written Key Highlights and summary do not rewrite themselves. Click “Refresh AI draft” in the report (you can type a sentence of guidance first — e.g. "lead with the strong Meta results") and the narrative regenerates from the latest numbers on the spot. Then tighten anything that reads off — your edits are remembered and teach the next draft your style.
  5. Draft the email — don't send it yourself (for now). Compose it as a draft in Janet's inbox using the ready-made email in the report, then ping Janet that it's ready for review. She'll review and send. Don't click Mark sent yet — the dashboard should match reality, so only mark it once Janet confirms the email actually went out. After a few cycles, you'll start sending directly.
  6. After client calls: log any real question the client asked in the Client Questions box at the bottom of the dashboard. Good ones get promoted to Blog Ideas — that list drives our content.
⚡ The "I changed a number but nothing updated" rhythm. Every save travels through GitHub and takes about a minute to go fully live. So when you change an inquiry count: (1) the report you're looking at updates the numbers instantly; (2) click Refresh AI draft to update the written summary (it won't rewrite on its own); (3) the home dashboard card catches up about a minute later. If the hub still shows the old number, that's just the ~1-minute lag — give it a moment and reload. The report in front of you is always current; the hub follows.
Lead schools also get a Landing Page Conversion funnel (sessions on each form's landing page → inquiries). It appears automatically once GA4 is connected for the school — nothing for you to switch on.
Miss a week? Nothing breaks. The pipeline archives the period with final stats anyway (it'll show a "Not sent" badge in Past reports) and rolls to the next period automatically. You can still open the archived snapshot and send late — but the goal is no more "Not sent" badges from here on.

The schools

SchoolTypeJudged onGroupNotes
Sacred Heart ChicagoLeadCPL · strong <$150, alert >$300Week AVerify form fills (creds in LastPass). No Loom yet.
Lauralton HallTrafficCPC · strong <$0.50, alert >$2Week ANo form fills to verify.
The Quaker SchoolTrafficCPC · strong <$0.50, alert >$2Week ANo form fills to verify.
Maclay SchoolLeadCPL · strong <$150, alert >$300Week BForm fills via Loom walkthrough.
Tandem FriendsArchivedSpring 2026 wrap-up delivered. No action needed.

Week A and Week B alternate, so you write at most 3 reports one week and 1 the next — never all 4 at once.

What's automated (so you don't redo it)

A pipeline runs every morning (~8am ET). It pulls Google Ads, Meta, and GA4 numbers straight from each platform's API (the Coefficient sheet stays on as an automatic backup if an API call fails), updates every stat and comparison on the dashboard, archives finished periods with a permanent snapshot, advances to the next period, and generates the AI draft once a period closes. The ↻ Run pipeline now button at the top of the dashboard runs the same job on demand (give it ~1 minute, then refresh).

If a platform's login expires, the school's card shows a red "<API> token expired — re-authenticate (Janet)" flag. That one's not yours to fix — just text Janet; re-connecting an ad account is account-level work she owns.

You never need to: enter ad stats by hand, compute deltas, create snapshots, or move a school to its next reporting period.

Onboarding a new school

When a new school signs, you're adding one config file — schools/<slug>.json. The pipeline discovers it automatically on its next run and fills in every stat. The only thing that has to be right by hand is the config: is it a Lead or Traffic school, the right ad-account IDs, and (for lead schools) the inquiry-form setup.

Use the “+ Add school” button at the top of the dashboard — it's the easiest way and it builds the config correctly by construction (no copy-paste mistakes). A short form opens:

  1. Fill it in: school name (the web-address slug auto-fills), the campaign objective (generate inquiries · event RSVPs · drive traffic · awareness — it picks the right report template and shows you which metric it'll use), the first report period's start & end dates, location/grades/market, and the optional Notion hub + form-fill Loom links.
  2. Add each inquiry form (lead schools): one row per form — the form name and its landing-page URL. The landing-page URL powers the conversion funnel (GA4 sessions on that page ÷ inquiries). You can always add or retire forms later from the report itself.
  3. Click “Create school.” It writes the config and shows a “Hand to Janet” card with the exact next step.
  4. Janet wires up access (the one step that can't be done in the form, because it's her ad-account credentials): grant GA4/Meta/Google read access, then add the school's account IDs to the Vercel env maps — GOOGLE_ADS_CUSTOMER_IDS, META_AD_ACCOUNTS, GA4_PROPERTY_IDS — each keyed by the new slug.

Until Janet wires access, the new school shows empty stats — that's expected. The next pipeline run (or the ↻ Run pipeline button) pulls its first set of numbers automatically.

Advanced: the command-line scaffolder

The button calls the same builder as this CLI. If you'd rather script it (or hand it to Claude Code in a fresh chat — “onboard a new school”):

node scripts/new-school.mjs --slug=oak-ridge --name="Oak Ridge School" \
     --type=lead --start=2026-09-07 --end=2026-09-20 \
     --location="Oak Ridge, TN" --grades="K–12" \
     --form="Visit Us|https://www.oakridge.org/admissions/visit-us"   # repeatable, lead only

--type=traffic for cost-per-click schools (no forms/Loom); --hide-traffic to drop the website-traffic section. Then refresh the registry (node scripts/registry.mjs) and commit.

The School Registry (docs/school-registry.md) is the one-page source of truth for every school's config — type, thresholds, sheet/tabs, where each account ID lives, Notion + Loom links.

Tools recap

ToolWhat forAccess
HubstaffTime tracking — timer on for all workEmail invite
The dashboardReports, statuses, guide, content logreports.schoolstorytellers.com — no login
LastPassSchool form-dashboard credentialsSign up free, then Janet shares each school's password to your account
NotionEach school's hub page (linked from its card)Shared to your email — accept the invites
LoomForm-fill walkthroughsLinks above

Who to ask

Janet (hello@jgstudio.co) — anything: access, client context, judgment calls on a report before it goes out, scope questions. Bias toward asking over stewing; a 2-minute question beats an hour of guessing.

Your first cycle, concretely

  1. Check the dashboard banner for what's due this week.
  2. Open that school's report — read the AI draft top to bottom.
  3. Verify form fills against the school's form dashboard.
  4. Draft the client email in Janet's inbox and ping her that it's ready for review.
  5. Wait for Janet's confirmation that it went out — then click Mark sent. Done until the next due date.

This week's follow-ups (June 2026)

On Jun 19 we cleaned up The Quaker School's season-trend chart and fixed all its report dates to run Monday–Sunday. A few related items were left for next week — none block sending reports. Hand each one to Claude Code as its own chat (name the problem). Full notes: docs/reporting-followups.md in the repo.

  1. Make future reports keep CPC + clicks automatically. The pipeline (api/advance-period.js, ~line 81) only saves spend + impressions to each new trend point. For the traffic schools (Quaker, Lauralton) it should also save clicks and CPC so those charts stay filled in. Small code change — highest priority.
  2. Check Lauralton Hall for the same date problems we just fixed on Quaker (weekly leftover points / Tuesday-start dates). Also: its Meta sync was stalled — backfill in Coefficient if still behind.
  3. Spot-check Maclay + Sacred Heart — confirm their trends are clean Monday–Sunday biweekly too.
  4. Fix the stale Meta history import in Coefficient — the Raw. Fb Ads tab stopped updating Feb 2025, so 2026 Meta lives in a different tab. We pulled Quaker's early-2026 numbers from the Notion reports instead; re-point the import if you want it all from Coefficient.
  5. (Optional) Quaker's archived report file names still use old end-dates — harmless, the period shown inside is correct. Skip unless it confuses anyone.
  6. (Carryover) Add Quaker's GA4: Total users by Date import in Coefficient — the website-traffic section turns on once it exists.