What's New
The latest features and improvements shipped to Picklebeast.
May 2026
May 20, 2026
Mobile App
Camp Admin in the Mobile App — Run Camps from Your Phone
The full camp management surface — list, create, edit, sessions, intake forms, badges, challenges, day-of operations, sales tax, recaps — now lives in the mobile app alongside parent and coach surfaces. Coach drop-off, parent broadcasts, attendance, and Kid Mode all on one device.
- Every web camp-admin action now available in the React Native app under Club Admin → Camps
- Coach day-of: roster check-in/out, attendance, emergency contacts, pickup PIN, parent broadcast, page-a-parent
- Two-panel mobile intake form editor with library + drag-reorder + single save
- Kid Mode inside the parent app — parent-attest challenges, streaks, XP, level, passport, badges (no AI, no minor data collection)
- Full session lifecycle: open registration → start → complete → cancel-with-refunds, all from mobile
- Sales tax settings + remittance report mobile parity
May 17, 2026
Club Admin
Camp Intake Forms — Collect Exactly What Each Camp Needs
Build a per-camp intake form from reusable building blocks, then let parents finish the detailed disclosures after they register — with automatic reminders until every required item is done.
- Two-panel drag-and-drop intake form editor with a reusable question library
- Built-in modules: medical & allergies, emergency contact, pickup authorization, photo consent, t-shirt size
- Custom toggle, free-text, and dropdown questions plus a custom liability-waiver document
- Parents complete the form via a secure magic link or in the app — no login required
- Automatic 7/3/1-day completion reminders that stop once the form is done
May 15, 2026
Mobile App
Kids Camps in the Parent App — Register, Check In, and Track Your Camper
Parents now run their kids' camp life entirely from the Picklebeast app — browse a club's camps, register and pay, sign the waiver, and pull up a QR check-in code for every camp day.
- Browse a club's open camps, see day-by-day or full-camp pricing, and read the cancellation policy before registering
- Multi-select drop-in days and pay for all of them in one Stripe payment
- Add a camper inline during registration — no separate setup step
- My Camps screen with Active and Past tabs and a next-day hint
- A scannable QR check-in code for every camp day, plus inline waiver signing
- Camp days surface in the home imminent panel and sync to your device calendar (siblings collapse into one event)
- Co-parents see the same registrations; cancel with an upfront refund estimate
May 14, 2026
Club Admin
Tournament & League Templates — Spin Up Recurring Events in 10 Seconds
Save any finished tournament or league as a reusable template. Spin up new instances with name + start date — every other config decision copies over. Personal vs. club-shared visibility, library at Programs → Templates, and a Start-from-a-template picker on New Tournament.
- Save as template button on every tournament & league admin page (show, edit) and the index 3-dots menu
- Re-save flow detects an existing template from the same source and offers Update existing / Save as new — never silent duplicates
- Personal templates are private to the creator; Club-shared templates are visible to every admin of the club
- Templates library at /club_admin/:club_id/templates with three tabs (Tournaments / Leagues / Events) and per-card usage_count + last-used date
- Click Use on any card → modal collects name + start date → POST /instantiate → redirect to the new event's edit page in seconds
- Start-from-a-template picker appears at the top of New Tournament — skips the form entirely when you have at least one accessible template
- Time offsets are relative — a division scheduled 2h after the earliest in the template stays 2h after the new anchor, regardless of your new start time
- Caps: 100 templates per club, 50 personal templates per user — no runaway library growth
- Atomic usage_count increment (DB-level UPDATE, no Ruby-side race) + last_used_at on every instantiation
- Soft-fails on missing locations: instantiate without a location and let the operator pick one in the editor
- Platform-owner dashboard at /platform_owner/templates_dashboard surfaces total templates, total instantiations, adopting clubs, and the top templates by usage
- Demo seed mints 3 tournament + 3 league templates per club so the library has realistic content on a freshly-reset demo
- Full TDD: 80+ specs across services, requests, system, and demo-seed coverage. Two end-to-end Capybara flows verify the JS glue.
May 14, 2026
Club Admin
Camp Registration Embed Widget — Sell Summer Camps from Your Own Website
Drop a single iframe on your club's marketing site. Parents pick weeks, enter their camper, pay via Stripe Connect — no Picklebeast account needed to book. Every paying parent auto-creates a Picklebeast account and receives a magic-link welcome email to finish setup.
- Single-line iframe embed with brand-color theming (CSS variables flow through into the Stripe Elements iframe too)
- N campers × M weeks in one cart with sibling discounts applied intra-cart
- Pessimistic 30-minute capacity hold during payment so a parent on Stripe Elements doesn't lose their seat
- Stripe Connect destination charges route to your connected account; widget bundles N registrations under one PaymentIntent
- Auto-created parent accounts use a magic-link 6-digit code (no temp passwords ever transmitted) — every authenticated surface gates on password_set_at until claimed
- Deferred waiver / medical / pickup completion with T+1d/T+3d/T+7d reminder cadence; CampCheckInService blocks attendance until done
- Existing email matches an existing User: attach without duplicate; member discount only after explicit sign-in (no email-enumeration leak)
- Optional co-parent fields (both become full Users with equal management rights via a join table)
- Admin embed-config KPI strip: registrations, revenue, avg cart size, abandonment % — last 30 days
- WL parity: WL clubs get noreply@{slug}.picklebeast.com sender + branded claim-account page
- Cloudflare-style abuse controls: rack_attack throttles per IP + per email, reCAPTCHA v3 on initiate_payment, 40-line cart cap
- Webhook-delivery safety net: every 5 min reconciler queries Stripe directly to catch stuck payment_processing sessions
May 13, 2026
Leagues
League Ties — Time-Capped & Single-Game Formats
Tied regular_season matches are now a first-class result. The score modal shows a 'Complete as Tie' confirmation when the game count is even; standings credit point differential without W/L; DUPR receives each game as its own submission so ratings still move.
- Tied matches recorded honestly — winner_id stays null, status='completed', tied?=true
- Rung ladder ordering unchanged — existing wins → PD → H2H → prior_rung_rank chain handles ties naturally
- Win percentage now follows USTA convention — ties excluded from the denominator (1W-1T = 1.000, not 0.500). No-tie leagues unchanged.
- DUPR per-game submission — each LeagueMatchGame submitted as its own DUPR match with its own dupr_match_id; retries skip games already accepted (idempotent)
- Parent dupr_submission_status='partial' when some game submissions fail; the next batch sweep retries only the failed games
- Playoff, MLP encounter, and challenge-ladder matches still require a winner — validation rejects ties on those formats
- Mobile + web scoring modals show 'Complete as Tie?' confirmation only when match.tieable is true (server-resolved per match)
- Parity tripwire spec locks in the documented asymmetry: leagues allow ties, tournaments do not
May 13, 2026
Tournaments
Rotating-Partner Tournaments — Solo Sign-Up Mixers
A tournament registration mode where players sign up alone instead of with a partner. The system generates a round-robin schedule that rotates partner pairings every round; per-player standings feed an automatic playoff bracket. Available on every plan.
- New Registration Mode row in the tournament wizard's Default Format step — Pre-formed Team / Rotating Partners
- Picking Rotating Partners auto-couples the bracket type to Round Robin (the only compatible format) and disables MLP / Team Captain
- Per-division override available — mix a Doubles + Rotating Partners division with a regular Doubles + Pre-formed Team division in the same event
- Player registration overlay (web + mobile) skips the partner-selection step entirely for individual_rotating divisions; backend forces registration_type='individual'
- Schedule generator runs the 1-factorization of K_n algorithm to maximize unique partnerships within the roster (8/16/24-player rosters ideal)
- Audit page surfaces conflicts (player in two simultaneous matches), partner duplications (same pair twice), and opponent-imbalance variance before publish
- Score submission uses a winning_side + points API — no team_one_id/team_two_id required because partnerships are dynamic per match
- Per-player standings (W / L / PF / PA / Differential / Rank) on the public division show page Standings tab; mobile parity
- One-click playoff generation pairs the top finishers (high-low default) into stable teams, builds a single-elim bracket, fans out push notifications
- Match-completion + court-assigned push notifications resolve recipients via tournament_match_participants — no team rows required
- Late registration blocked once the schedule generates (the rotation table can't be extended without regeneration); player sees a clear 'Registration closed' message
- Full E2E spec walks creation → 8 registrations → schedule → score every match → standings → playoff → champion. 155+ specs covering API, mailer, badge evaluation, Command Center rendering, and full integration paths
May 12, 2026
Mobile
Saved for Next Visit — Cart Auto-Resume on Reservation
Members can park a cart at your club. When they book their next reservation, a push notification surfaces it — confirm to charge, discard to clear. The order is queued for the start of their session, so the food is ready when they arrive.
- Cart 'Next reservation' chip — when no upcoming reservation, taps save the cart as a QueuedOrderIntent and clear the deferred lines from the live cart
- Reservation create hook — auto-fires a push when the booking member has an active saved cart at the same club
- Review screen — items, snapshot total, Confirm or Discard CTAs, with price-drift re-confirm if any line price changed since save
- 30-min cool-down per (member, club) — rapid back-to-back bookings only fire one push
- Status re-validation at fire time — cancelled reservations don't generate misleading pushes
- Club-local timezone in the push body — non-PT members see times in their club's timezone, not UTC
- 30-day saved-cart expiry with a 5-day-before reminder push (separately toggleable from the reservation-match push)
- Settings → Notifications → Mobile Ordering exposes all 5 SPO push keys for independent member control
- Strava/Apple chip aesthetic in the cart sheet — low-alpha brand tint on selected pickup chips, no more full-saturation 'blocked blue' fill
- BrandedLoader splash refresh — transparent claws-marks asset, 2× default size, no back chevron
May 12, 2026
Club Admin
Court Calendar Management — Edit Courts, Block Time, and Set Hours Without Leaving the Calendar
Manage every court from one screen. Click a court header to rename, recolor, or take it offline. Block off time for maintenance, events, lessons, or private rentals — one-time or weekly recurring. Set per-location operating hours inline. The calendar repaints in place; the front desk never sees stale state.
- Inline court edit modal — click any court header on the timeline or grid to rename, change number/display order, pick a color, change surface type, toggle indoor/outdoor + lighting + covered, mark unavailable with a public reason
- Block Court button — open a modal to block off time on any court for maintenance, event, lesson, tournament, private rental, closure, or other; one-time blocks support full date/time range with public reason + internal notes
- Repeat Weekly toggle — extend any block to a recurring weekly or biweekly pattern with day-of-week chip selector and optional end date; generates a full year of occurrences up front
- Hours button — inline modal to edit per-location operating hours; 4 quick presets (extended, standard, business, 24/7) plus per-day open/close/closed toggles
- Permission gating — Block Court requires can_manage_court_blocks; court editing requires can_manage_courts; hours requires can_manage_locations. Sidebar lock icons for lower-tier staff
- Live calendar repaint after every mutation — no manual reload, scroll position preserved (CLAUDE.md §3.8 compliant)
- Cancelled blocks no longer falsely subtract from cross-club marketplace availability counts or coach-slot conflict checks (3 .active scope fixes shipped)
- Hardened: overlap-on-update validation closed; DB-level exclusion constraint added for race-safe production; mass-assignment IDOR via club_location_id closed; XSS via JSONB hours key closed
May 12, 2026
Tournaments
Command Center at Scale — Run a 100-Division Tournament Without Drowning
A compact rail with smart presets (Live / Attention / Pinned / All) gives operators focus on tournaments with 50, 80, even 100 divisions. Pin up to 12 to follow live, view up to 4 in a 2×2 grid, share a focus URL with a scorer so they see only their divisions.
- Compact left rail — one row per division, with state dot + match-counter + live-count + attention badge + pin + view icons
- Smart presets — Live / Attention / Pinned / All. Smart fallback: 'Live' auto-promotes to 'All' if nothing is live yet so the rail never lands empty
- Pin up to 12 divisions, server-persisted so an operator can pin from desktop and pick up on iPad
- Share button copies a focus URL with ?pinned=12,15&preset=pinned. Recipient sees 'Save as my default' pill to persist
- View icon adds up to 4 divisions to a side-by-side 2×2 grid (hard-capped, never more); 1-col on narrow viewports
- Click any rail row to enter focus mode — only that division shows below, with a smooth scroll + highlight pulse
- Aggregate poll updates rail counters every 10s/30s focused/hidden. Deep poll only fires for pinned divisions
- Auto-collapses the club-admin sidebar so wide tournaments get maximum horizontal room
- First-visit coachmark on 20+ division tournaments (once per user)
- AI chat: query_command_center_state + query_command_center_attention tools surface tournament state in natural language
- Mobile + tablet parity — phone shows full-screen rail with stack-push detail; tablet shows rail + detail pane side-by-side
- Cross-repo parity tripwire spec — backend constants and mobile TypeScript types fail the suite if they drift
- Legacy 3-up grid stays as a safety fallback below the rail; flag-flip rollback with zero data migration risk