Book a demo

Booster Club Software · the booster-club and PTA-board operations console

The booster console — your role, your campaigns, your treasury, your PII wall.

Booster Club Software is the operations home for booster officers, treasurers, and PTA boards. It is built around a first-class booster_pta role — a real, separate role in the platform, never folded into the school coordinator — with its own console, its own API routes, and its own data-layer privacy wall. A booster session reads zero student rows at the database engine. That is not a UI filter. It is a RESTRICTIVE Row Level Security policy that fires before any application code runs. Consent-as-architecture: the wall is the feature.

This is the booster-club operations and governance home — the role, the console, and the PII wall. The fundraising economics story (the cross-catalog donation lane, the FLOOR) lives at fundraising.software. The full platform story is at homeroom.software. The parent-teacher-organisation sibling is pta.network (an external sibling; the PTA mark is theirs). Booster gate-scan and concessions is a separate product at schoolbooster.network.

The PII wall is the headline: booster parents never see student data, by construction

Most booster and PTA software treats privacy as a permission checkbox somewhere in the settings. The data is there; it is just hidden behind a role flag that an application route can forget to check. Booster Club Software takes a different approach: the wall is enforced at the database engine, before the application reads any data at all.

deniesStudentData(booster_pta) === true — one source of truth

The platform has one predicate that decides whether a role must never receive the student-data grant: deniesStudentData. It returns true for exactly two roles: commissioned reps (account_manager) and booster/PTA parents (booster_pta). Both are denied by the same function, so the grant site and every route guard read the same answer. There is no secondary string comparison to drift.

Zero student rows at the database engine

A booster_pta session returns zero rows from every student-coupled table. This is not a WHERE clause in application code. It is a RESTRICTIVE Row Level Security policy at the database engine: RESTRICTIVE policies AND with tenant isolation before any application query can read a row. A route that forgets to check the role gets the same result: zero rows. The wall does not depend on the application remembering to apply it.

403 on club rosters, galleries, and cross-tenant aggregates

The directory endpoint calls denyStudentData before returning any family names. A booster_pta session gets a clean 403 — not an empty list, a clear prohibition. The gallery require-admin allow-list excludes booster sessions by the same construction. Cross-tenant aggregates are never visible. The console renders the honest “restricted” state rather than an empty table when the server says 403.

Donor identity never leaves the server

When a donation is recorded, the donor’s name is reduced to first-name plus last-initial at write time using the platform’s firstNameLastInitial transform. Campaign progress surfaces only sums and counts: settled gift total, pending gift total, goal percent, donor count. A treasurer sees that a campaign raised $4,200 from 37 donors at 84% of goal. The treasurer does not see who gave or how much each person gave. Donor identity is not stored in the progress aggregate.

Consent-as-architecture vs the incumbents’ loose sharing

A common failure mode in school-community software is storing family data in a shared pool and relying on role flags in the application layer to prevent disclosure. Application-layer flags can be bypassed by a new route, a configuration change, or an integration that queries the pool directly. The architectural answer is a data-layer wall: the booster session cannot read what it is not supposed to read, regardless of which route or integration is requesting it. The consent guarantee is structural, not procedural.

The booster_pta role is school-scoped, never platform-scoped

A booster_pta actor holds a school-scoped membership: they can see and act on campaigns, events, and treasury aggregates for their school only. They cannot read data from another school’s tenant. Tenant isolation is a separate RESTRICTIVE RLS policy that fires alongside the student-data wall, so a booster_pta session at School A cannot query School B’s campaigns even if School A and School B are on the same platform instance.

The booster console: what landed today (f75e8a89)

Commit f75e8a89 landed the first-class booster_pta role: the DB enum value, the API route group, and the web console. The console has four built surfaces and two honest-early-access surfaces. Each is marked honestly below.

  1. Fundraiser campaigns — create and track. A booster officer creates a named campaign with an optional goal and an optional active window (POST /booster-pta/campaigns). The campaign rides the existing cross-catalog no-split donation lane: funds settle 100% to the school. There is no settlement leg to the platform or a studio; the split, if one is configured in the treasury, is a ledger allocation only and is never a transfer. Campaign list (GET .../campaigns) shows each campaign with its settled (paid) progress. Built
  2. Donations — on the no-split lane. A donation is created via POST .../campaigns/:campaignId/donations. The route decomposes the charge into gift and covered-fee legs (if the donor opts to cover processing), returns pending_payment plus a real client secret, and the paid status flips only when the payment_intent.succeeded webhook fires. No route in the platform ever fabricates a paid status. Built
  3. Campaign progress — sums and counts only. GET .../campaigns/:campaignId/progress returns: settled gift sum (paid donations only), pending gift sum (submitted but not yet confirmed by webhook), goal percent, and donor count. These are aggregate numbers. Donor identity is not in the response: the server stores and returns only the reduced first-name-plus-last-initial form at write time; the progress aggregate does not expose it at all. Built
  4. Treasurer aggregate rollup. GET /booster-pta/treasurer returns a rollup across all of the school’s campaigns: total settled gift sum, total pending gift sum, goal percent across all campaigns with goals, and total donor count. An optional advisory booster-split allocation (computeBoosterSplit) is included for reconciliation when the school has configured a split designation. The split is a ledger allocation: it drives the school’s own bookkeeping, not a platform transfer. Built
  5. Event coordination — fundraising-event config. POST /booster-pta/events creates a fundraising-event config row in draft status: a named event with a date, a venue, and a volunteer-slot structure. GET .../events/:eventId reads one event config. The named-slot structure lets a treasurer assign coordinator roles to an event before it runs. Built
  6. Membership dues designation. A campaign can be designated as membership_dues type via the additive campaign-type taxonomy. The designation is metadata: it records the campaign’s intent and drives the school’s own bookkeeping. The recurring billing leg — collecting dues on a schedule rather than as a one-time donation — is in early access. We name that plainly. Early access — recurring billing

Honest console states: ok, restricted, unavailable, none

The booster console never fabricates data or money state on error. The UI derives its availability union from the HTTP status the server actually returned. Four states, each rendered honestly.

ok ok

The server returned 200. The campaign list, progress totals, treasurer rollup, or event config is real data from the shipped engine. The console renders it directly. No fabrication.

restricted restricted

The server returned 403. This surface is off-limits for the current session — either the role does not hold the booster gate (a plain school staffer who is not a booster_pta or admin), or the surface is the student-data wall (denyStudentData fired on the directory endpoint for a booster_pta session). The console shows the honest restricted state rather than an empty table.

unavailable unavailable

The server returned 404 or 501, or the endpoint was unreachable. The booster/PTA module is not provisioned for this school, or the route is not yet live. The console shows the honest unavailable state rather than pretending the surface is empty.

none none

The server returned 200 but the result set is empty. No campaigns, no events, no treasury entries yet. The console shows an honest empty state (EmptyState component) rather than a placeholder or demo row.

Fundraiser creation and tracking: the cross-catalog no-split donation lane

A booster officer creates a fundraising campaign through the console or the API. The campaign runs on the existing cross-catalog donation lane — the same substrate the platform uses for yearbook-for-every-child funding, module catalog purchases, and other school-directed fundraising goals. There is no new money engine; the booster console is a surface over the existing lane.

The key property of the lane is its settlement model: funds settle 100% to the school’s account. The platform does not take a cut from what a donor contributes. The split, if one is configured, is a ledger allocation that drives the school’s own bookkeeping — it records which program or budget line a donation should be attributed to. It is never a transfer to a separate platform account. The school receives the full donation minus any donor-side processing fee the donor chose to cover.

Campaign progress is transparent: settled gift total (paid-only), pending gift total (submitted but not yet confirmed by the payment webhook), goal percent, and donor count. These are the numbers that matter for a treasurer’s report. The individual donor list is not in the progress response. Donor identity is reduced at write time and not surfaced in aggregate views.

For the complete story on the fundraising economics — how the FLOOR works, how the donor-side fee gross-up is computed, how the platform-eats-shortfall rule operates — see fundraising.software. That is the money product’s home; this page is the operations and governance home.

The treasurer view: aggregate rollups, not a donor list

A booster treasurer needs to know whether the campaign is on track, not who gave what. The treasurer aggregate is designed around that distinction.

Settled vs pending

The treasurer rollup splits the gift total into two buckets: settled (donations confirmed by the payment_intent.succeeded webhook — real, cleared funds) and pending (donations submitted but not yet confirmed by the webhook). The split matters for a treasurer’s report: pending donations may not clear. The console shows both, labeled honestly, rather than combining them into a single inflated total.

Goal percent

If a campaign was created with a goal, the progress response and the treasurer rollup include the goal percent: how far the settled total has progressed toward the goal. Goal percent is computed from settled funds only — pending donations do not inflate the progress bar. A campaign with no goal omits the percent rather than displaying a meaningless number.

Donor count

The progress response and the treasurer rollup include a donor count: the number of distinct donors who have made a settled donation to the campaign. Count only — no names, no amounts per person. A treasurer can see that 37 people contributed without seeing who each person is or how much each gave.

Advisory booster-split allocation

The treasurer endpoint accepts an optional flag that requests the advisory booster-split allocation from computeBoosterSplit. When included, the response carries a breakdown of how the settled total would allocate across the configured program or budget designations for the school’s bookkeeping. This is advisory: it drives the school’s own ledger. It is not a transfer. The school receives the full settled sum; the allocation is a categorization for the school’s books.

Event coordination and volunteer coordination

A booster organisation runs more than campaigns — it runs events. A bake sale, a carnival, a car wash, a gala. Each has a date, a venue, and a set of volunteer roles to fill. The booster console includes event config management as a first-class surface alongside fundraiser tracking.

A fundraising-event config row records the event: a name, a date, a venue label, and a structured set of named volunteer slots. Named-slot posture means each slot has a label (registration desk, setup crew, kitchen, parking) and a headcount needed. The config is created in draft status; a booster officer drafts the event before the volunteer call goes out.

Volunteer signup routing — sending the named slots to potential volunteers and collecting confirmations — depends on the platform’s communication provider configuration. The structure is built; the delivery is key-gated. A school that has configured a communication provider key can route the signup to volunteers. A school without one has the structure but not the delivery. We name this plainly.

The event coordination surface is distinct from the box-office, gate-scan, and concessions surface at schoolbooster.network. The booster console event config is the pre-event planning tool: drafting the event, naming the slots, and coordinating volunteers. The gate-scan and till operations on the night of the event are the schoolbooster.network surface.

Membership dues: what is built, what is early access

Booster and PTA organisations often collect annual or semester membership dues. The platform supports dues as a fundraiser campaign designation today. The recurring billing leg is in early access.

Dues as a campaign designation — built today

A campaign can be designated as membership_dues via the additive campaign-type taxonomy. The designation is metadata: it records the campaign’s purpose and drives the school’s own bookkeeping. A single dues collection (a one-time donation to a dues campaign) works today on the existing donation lane. The campaign shows up in the treasurer rollup like any other campaign. Built

Recurring dues billing — early access

Collecting dues on a schedule — an annual renewal, a semester installment — requires a recurring billing leg. The recurring billing infrastructure is in early access. We name that plainly. A booster organisation that needs recurring dues collection today can run it as a one-time donation campaign and manage the renewal manually; the recurring automation is the early-access leg we are building toward. Early access — recurring billing

Why the booster_pta role is first-class, not a permission toggle

A common pattern in school software is to give a coordinator role a “booster access” permission checkbox. The coordinator keeps their existing role; the checkbox adds a capability. The problem with this pattern is that the resulting session still carries the coordinator role’s full data access. A single toggled permission is not a data-layer wall. If the coordinator role can read the student census, and the checkbox does not revoke that, the booster user can still read student data.

The platform solves this with a separate role. A booster_pta actor is a distinct database session type. The deniesStudentData predicate returns true for this role, which means the student_data_ok grant is withheld. The RESTRICTIVE RLS policy that reads that grant returns zero rows on every student-coupled table. This is not conditional on what other roles the actor might hold: a booster_pta session is a booster_pta session, and the wall is always up.

The role is school-scoped: a booster_pta actor holds a membership at a specific school and can only read and act on that school’s data. Multi-school booster accounts (a district-level PTA with chapters at multiple schools) each hold school-scoped memberships; the platform does not aggregate across schools in a single booster session.

The console gate mirrors this: the web console renders only for a booster_pta session (or a school or district admin who may also operate the console). Any other role sees the honest restricted EmptyState. The gate is a UI affordance; the server re-checks the booster role on every route before returning data.

Common questions

Is booster_pta a real role or a permission overlay on school_coordinator?

It is a real, separate role: a first-class value in the platform’s user-role enum, with its own DB entry, its own API route group, its own require-booster gate, and its own web console surface. It is never folded into school_coordinator. A school coordinator and a booster/PTA parent are separate actors with separate access profiles. The coordinator may access student data (if their role permits it); the booster_pta role is always denied student data at the data layer.

Can a booster session see the family directory?

No. The directory endpoint calls denyStudentData, which returns 403 for a booster_pta session. The console renders the honest restricted state for the directory when the session is booster_pta. A school official (adviser or admin) may access the consent-cleared directory; a booster parent may not. This is enforced server-side on every request, not just in the UI.

What does the treasurer see and what is hidden?

The treasurer sees settled gift total, pending gift total, goal percent, and donor count across all campaigns. No individual donor names, no per-donor amounts. Donor identity is reduced to first-name plus last-initial at write time; the progress aggregate does not surface even that — it surfaces only the count. A treasurer who needs a reconcilable donation record can request the optional advisory split allocation, which categorizes the settled total by program designation for the school’s own books.

What is the difference between settled and pending in the treasurer view?

Settled means the payment_intent.succeeded webhook fired: the payment cleared and the gift is real money. Pending means the donation was submitted and the server returned pending_payment, but the webhook has not fired yet (the payment may still fail). The treasurer view shows both, labeled honestly, because pending donations may not become real funds. The progress bar and goal percent use settled funds only.

How does the donation lane work? Does the platform take a cut?

Donations run on the cross-catalog no-split lane: funds settle 100% to the school. There is no settlement leg to the platform or a studio from a donation. For the complete economics story — the FLOOR, the donor-side fee gross-up, the platform-eats-shortfall rule — see fundraising.software. Money is honest-off on this page.

What is the difference between boosterclub.software and schoolbooster.network?

boosterclub.software is the role, console, and PII-wall operations home: fundraiser creation and tracking, the treasurer aggregate, event config management, and governance. schoolbooster.network is the season-and-program-run platform: box-office gate-scan, concessions POS, reserved seating, and the exact-cent split engine for game night and show night. Both are distinct products on the same platform substrate. A booster organisation may use both; they serve different moments in the club’s operating rhythm.

What is the difference between boosterclub.software and fundraising.software?

fundraising.software is the money product: the cross-catalog donation economics, the FLOOR (the school never nets less than the gift minus the disclosed take), and the donor-side fee gross-up. boosterclub.software is the governance and operations surface: the booster_pta role, the console, the treasurer view, and the PII wall. The two cross-link each other. A booster officer working in the boosterclub.software console is running campaigns on the fundraising.software money rails.

Is pta.network the same as boosterclub.software?

No. pta.network is a separately owned sibling domain with a trademark flag on the PTA mark. It is a parent-teacher-organisation sibling — cross-linked here as a related surface — not the same product or the same brand as Booster Club Software. boosterclub.software does not claim the PTA mark.

What is the console state when the booster module is not provisioned?

The console shows the unavailable state. The server returns 404 or 501 when the booster/PTA module is not provisioned for the school. The console renders the honest unavailable EmptyState rather than pretending the surface is empty or showing a demo. A school that has not enabled the booster console sees that it is not available, not a blank campaign list.

Are recurring membership dues available today?

Partially. A dues campaign can be created and donations collected against it today on the one-time donation lane. The recurring billing leg — automatic renewal on a schedule — is in early access. We name that plainly. A booster organisation that needs recurring dues today can manage renewals manually via one-time campaigns; the automation is the early-access leg.

How is the booster_pta role added to an existing user account?

The role is provisioned via the school’s admin surface, which adds the booster_pta membership for a user at the school. The DB role is set by the ALTER TYPE ... ADD VALUE IF NOT EXISTS migration pattern (the platform’s 0065/0243 idiom for additive enum extension). A user can hold a booster_pta membership at one school; separate memberships at separate schools are separate rows.

Related surfaces

The booster console connects to the platform through the shared fundraising substrate, the family surface, and the flagship brand home.

fundraising.software

The fundraising money product: the cross-catalog donation lane, the FLOOR (the school never nets less than the gift minus the disclosed take), and the donor-side fee gross-up. boosterclub.software cross-links here for the money story.

pta.network

The parent-teacher-organisation sibling (external; the PTA mark belongs to that brand). A related surface for PTA boards. boosterclub.software cross-links it as a sibling without claiming the PTA mark.

parentsoftware.app

The family-facing surface: the place a parent views their student’s records, publications, and communications. Distinct from the booster/PTA officer console, which is a school-operations surface.

homeroom.software

The flagship platform brand home: the full product story, all roles, the consent substrate, and the complete picture of the platform behind the booster console.

What is built and what is honest-off

The booster_pta first-class role — a real DB enum value with its own console, its own API route group, its own require-booster gate — is built and running today (f75e8a89). The PII wall — deniesStudentData(booster_pta) === true, zero student rows at the data layer, 403 on the directory for a booster session — is built and running today. Fundraiser creation and tracking on the cross-catalog no-split donation lane — campaign create, donation with honest pending_payment state, settled progress (sums and counts only), donor count — is built and running today. The treasurer aggregate rollup (settled vs pending gift sums, goal percent, donor count, optional advisory split allocation) is built and running today. Event coordination (fundraising-event config rows, named volunteer slots) is built today. Membership dues as a campaign designation is built today. The recurring billing leg for dues is early access. Volunteer reminder fan-out is key-gated and honest-off without configured provider keys. No competitor brand names appear here. Money, pricing, and checkout are not on this page.