Releases · The trail behind us
What we shipped,in order.
No hype, no spinners — every meaningful change to P4cely since open beta. Most recent at the top. Click any release to expand the change list.
- v2.0.4 · New-season (v2.70) replays parse again1 change
- FIX
Replays from the new Rocket League season (v2.70) couldn't be analyzed and failed with 'rrrocket exited with code 1' — both through the Discord coach bot's auto-detect and the dashboard upload. The June game update added new data to the replay format (World Cup and anonymized-name attributes) that our replay parser didn't recognize yet, so it rejected every v2.70 replay at the very first step. We've updated the parser (rrrocket 0.11.1 → 0.11.3, which adds full v2.70 support) and new-season replays now parse normally. If one of your replays failed with this error, just re-upload or re-sync it — the analysis runs the second time.
- FIX
- v2.0.3 · Pro→Star upgrade and quota counting fixes2 changes
- FIX
Upgrading from Pro to Star now works in one step, with your launch discount applied automatically. The upgrade button was opening a brand-new checkout, which the payment provider rejects when you already have an active subscription ('You already have an active subscription') — so the switch never went through and the 30% code could never apply. It now switches your existing subscription to Star in place, prorated for the rest of your current cycle, with the discount attached. If your account's billing link had been lost to a dropped webhook in the past, the upgrade now repairs it on the fly by matching your email instead of dead-ending at a fresh checkout.
- FIX
Fixed a quota over-count where your monthly replay counter could climb past the number of replays you'd actually analyzed. When a parse was retried or its match was removed mid-flight, the worker could leave a 'phantom' slot on the counter without a matching replay. Every retry and failure path now refunds the exact slot it consumed (the right pool and the right month), so the counter can't drift up anymore. Affected accounts were reconciled back to their real usage.
- FIX
- v2.0.2 · Replay and session share links6 changes
- NEW
Share links are live for match reports and session debriefs. Copy a public URL from the owner page and send it to a coach, teammate, friend, or Discord thread — the viewer can open it without signing in and gets the full read-only coaching surface.
- NEW
Session debriefs can be shared too. The public session page shows the coach narrative and the match summaries that fed it, so a coach can review the whole ranked block instead of one replay at a time.
- NEW
Reset link disables the old URL and gives you a fresh one. Under the hood this rotates the UUID token and resets the view counter; the previous link returns the same not-found response as any invalid token.
- POLISH
Shared links generate rich previews for chat apps, with dynamic match/session Open Graph images instead of a generic logo card. Public pages are marked noindex/nofollow because the URL itself is the credential.
- POLISH
Owners can see a simple share view count. Preview crawlers and owner probes do not inflate it, and the public endpoints share one 60 requests/minute rate-limit bucket per IP.
- FIX
Post-review hardening: migration 0020 now enables pgcrypto before using gen_random_uuid(), the public API trims owner-probe projections to only fields it returns, and the share modal clipboard fallback is scoped to its own input instead of querying the whole document.
- NEW
- v2.0.1 · Mobile polish + analysis correctness fixes15 changes
- FIX
Wasted boost metric label corrected. The Metrics tab said the unit was '% of time', but it's actually '% of boost collected' — what fraction of every unit of boost you picked up landed above the 88-cap. The label change is purely cosmetic, the math was correct. Spurred by Mimical asking how the metric works after his Coach Report cited 9% wasted while two pro replays showed 14%; the pro baseline aggregates ~30 replays per pro per mode, so two reference games don't dictate the cohort median.
- FIX
Goal participation no longer says '0% participation' when your team got shut out. The metric is now null on shutouts, which means the baseline comparison stops bucketing every clean-sheet loss as bottom-tier. Same treatment for possession share in 1v1 — you're always 100% of your team's touches, so the metric is now skipped rather than wasting a row.
- FIX
First-touch win rate is no longer deflated for 3v3 players whose teammates linger near the ball. The metric only counts a contested first touch when at least one player from each team is within 300uu of the ball when possession flips. Before, a teammate hovering near a duel would steal an attempt and silently drop your win rate.
- FIX
Team boost advantage now requires a real margin (>=10 boost across the team) before counting a frame as advantaged. The previous +1-boost-counts-as-advantage rule inflated the metric for matches where running totals oscillated around parity.
- FIX
Lowest-boost streak no longer requires strict zero. Players rotating with 1-2 boost on the meter (common at Diamond+ where economy management leaves rotating dust) now correctly trigger the moment when they sit practically empty for 10+ seconds. The hint state shows the real minimum boost observed during the streak instead of hard-coding 0.
- POLISH
Demos in chaotic teamfights are no longer dropped as duplicates. The dedup window on the demo replication shrunk from 5s to 2s, matching RL's actual post-respawn immunity. Two demos on the same victim within 2s are definitionally the same physical impact; anything longer was previously lost.
- POLISH
Shot-quality and kickoff frame lookups now binary-search the timeline instead of linearly scanning every frame for every event. Irrelevant in a normal match (~6000 frames + ~20 events), meaningful for bulk reprocessing.
- FIX
Pro picker cards no longer collapse on mobile. On narrow viewports the roster grid was missing an explicit single-column fallback, so the cards rendered as content-sized tracks and only the tagline was visible. The same bug pattern was hiding inside the match Overview, Heatmap stat tiles, and Metrics expanded breakdown — all three now render correctly at 375px and up.
- POLISH
Rank comparison table is readable on phones. The sticky 'Metric' column on /dashboard/ranks used to take 56% of an iPhone viewport, leaving almost no room for the seven rank columns it was supposed to compare against. The sticky column now shrinks to 140px on mobile and expands back to 200px on tablets and larger.
- POLISH
Trends charts breathe again on small screens. The per-metric chart cards used to render at a fixed 160px height regardless of viewport, which squashed the Y-axis to the point where the labels were unreadable. The charts now scale up gradually — 176px on mobile, 192px on tablet, 208px on desktop.
- POLISH
Session debrief match list and Lobby tab opponent pills now truncate cleanly on mobile instead of letting long mode/result/score strings push the timestamp off-screen. Match titles use the full available width and ellipsis when they need to.
- POLISH
Onboarding wizard and Profile settings footer buttons now wrap properly on narrow screens. The 'Skip / Continue' and 'Discard / Save' button pairs used to cram together with a 20px gap that didn't wrap predictably; they now stack with a smaller 8px gap on mobile and the original 20px on tablets and up.
- POLISH
Match timeline legend and tick axis now use smaller text on mobile so the ten marker categories and five time ticks all fit on a 375px viewport without wrapping into four lines or overlapping.
- POLISH
AccountMenu dropdown can no longer exceed the viewport height on short screens (mobile landscape, small laptops). It now caps at the viewport height minus the topbar and scrolls internally if menu items overflow.
- POLISH
Manual upload dropzone, dashboard PulseStrip stats, Platform connection pills, Terms/Privacy data lists, and the admin filter row all received the same treatment — explicit mobile-first base classes, smaller mobile gaps, and consistent breakpoint ramps. Eighteen files updated; no functional changes.
- FIX
- v2.0 · open beta · Star tier, quota top-up packs, and the launch promo6 changes
- NEW
Star (€24.99/month) is live. 150 replays per month, deep Coach Report with recommended drills, long-term coaching memory across sessions, the full 25-match Trends slider, and AI Q&A chat inside replays and sessions. Built for players who want the full coaching surface, not just the report card.
- NEW
Quota top-up packs. Out of replays mid-month and don't want to upgrade? Pro and Star users can now buy bonus replays one-shot: Pack S (+10 / €3.99), Pack M (+25 / €8.99, smart pick), Pack L (+50 / €14.99). Bonus replays burn at the end of the calendar month — buy what you'll use. A bonus pool meter on /billing tracks remaining replays in real time, and the dashboard quota meter shows the bonus tier above the base.
- NEW
Star launch promo for existing Pro users. Every user on Pro at launch received a single-use Polar discount code by email — 30% off Star for the first 3 months (€17.49/mo instead of €24.99). Codes expire 30 days from issue. The code is also pinned to /billing as a banner so it's never lost in an inbox.
- POLISH
Pro stays €7/month with 50 replays and the same shorter Coach Report you've had. Three features moved up to Star: the deep narrative version of the Coach Report (you keep the summary version), recommended drills, and AI Q&A chat inside replays and sessions. Pro keeps its position as the analytics-for-the-price tier, with Star sitting above for power users.
- FIX
Back-button no longer freezes checkout and sign-in buttons. Clicking Buy on a top-up pack or Continue with Steam/Epic redirects you to a third-party host; hitting the browser back button used to leave the React loading state stuck, so the buttons stayed disabled and stuck on 'Opening…'. The page now detects bfcache restore and resets the loading state cleanly.
- POLISH
Tier-aware refunds. When a parse fails (unsupported mode, perspective ambiguity, etc.) the slot is refunded to whichever pool it came from — base monthly quota or bonus pool — instead of always crediting the base. The match row now carries the consumption kind so the refund path can't double-credit or short-change.
- NEW
- v2.0.0 · Session coverage clarity, baseline chips, cleaner trends5 changes
- FIX
Long session debriefs now explain exactly what they analyzed. If a session has more than eight games, the debrief header reads like '8 of 13 matches analyzed' instead of making five games look missing. The older games stay in your match history; the AI summary intentionally focuses on the latest eight in the stretch. Past-session previews use the same wording, so the count is consistent before and after you open the debrief. Myst caught the trust gap.
- NEW
Session averages now show compact comparison chips when the data is comparable: vs your rank median and vs your selected pro median. The chips are direction-aware, so lower wasted boost or less time empty reads as better, while higher avg boost, supersonic time, and shots read as better. Mixed-mode and private sessions skip the chips rather than pretending the baseline is apples-to-apples.
- POLISH
Session debriefs now have Older and Newer controls in the header, so reviewing several debriefs no longer means backing out to the Past sessions list every time.
- FIX
Trends charts no longer let the 'Your avg' and 'Rank median' line labels overlap. The fragile inline labels are gone; a stable legend sits above the chart grid, and each chart footer still carries the exact average and median values.
- FIX
Dashboard session grouping now uses the same 45-minute session gap as the worker and API. A client-only 90-minute grouping path could make the sidebar show a larger session than the debrief engine would analyze; the surfaces now agree.
- FIX
- v1.7.9 · Trends percent fix, session averages, dashboard return links3 changes
- FIX
Trends charts no longer show percentages in the thousands. The parser stores percentage metrics as percentage points (`14` means `14%`), but the chart formatter was treating them like fractions and multiplying by 100 again. Boost waste, time empty, supersonic, and slow-speed charts now use the same scale as the Metrics tab and baseline data. The yellow rank reference line also reads `Rank median` instead of `Rank p50`, and the chart reserves enough room so the label isn't clipped.
- NEW
Session averages. Open any past session debrief and you'll now see a compact metrics panel above the coach narrative: average boost, wasted boost, time empty, supersonic time, slow-speed time, and shots per match. The Past sessions list also gets quick chips for avg boost, waste, and supersonic so you can compare session to session without opening every debrief. The API computes these from the existing per-match metrics tied to each session — no migration or backfill needed. Asked for by Myst.
- POLISH
Trends, Homework, Past sessions, and Rank benchmarks now all have a shared `Back to dashboard` link at the top of the page. The link uses the same compact icon-button treatment across the four surfaces, so deep dashboard pages no longer feel like dead ends.
- FIX
- v1.7.8 · Opponent profiles, rank benchmark pages, partner-stats fix, hardened sign-in redirect6 changes
- NEW
Opponent profiles. Every replay's Lobby tab now lists the opponents you faced as clickable pills above the metric breakdown. Tap one and you land on a dedicated page that aggregates every analyzed match you've played against that player — head-to-head record (wins / losses / draws), your boost-discipline average across those games next to theirs, your goals-per-match next to theirs, and a one-line read on where the difference actually lives. The data is yours alone: only matches uploaded under your account count toward the aggregate, so a smurf you face once doesn't suddenly inherit the wider community's stats. Opponents without a usable platform id (Steam guests in some private lobbies) don't get a pill — there's no stable identity to aggregate against. Direct-link a profile URL anywhere; the page is auth-gated and noindex so it stays a private deep link.
- NEW
Public rank benchmark pages. Pacely now publishes a page per (rank, mode) combination at `/ranks/<rank>/<mode>` showing the P25 / P50 / P75 distribution for boost discipline, supersonic time, slow-speed positioning, wasted boost, and time at zero boost — the same five metrics the coach report grounds its claims against. These pages are SEO-targeted (visible to anyone, not just signed-in users) and aggregate from the same nightly baseline refresh that powers the in-app comparisons. If a teammate asks 'what's a normal boost average at Diamond 2v2?', the URL is the answer. Private/custom-lobby baselines are excluded from this surface — only ranked-play distributions are exposed.
- FIX
Partner-server admin stats now show real numbers. The Discord coach bot's `/pacely-admin status` command reports how many uploads the partner server has produced this month — under the hood the worker writes to a `discord_bot_uploads` audit table when a parse succeeds or fails, and the slash command counts those rows. The success path was setting the audit row to `enqueued` on upload but never updating it to `ready`/`parse_failed`/`rejected_mode` once the worker finished. Result: every partner admin saw 'reports generated: 0' regardless of actual volume. Now the worker closes the audit row terminally on every parse outcome (idempotent under BullMQ retries) and the admin command reflects reality.
- FIX
Hardened the post-sign-in redirect. After completing Steam or Epic OAuth the dashboard reads a `next` parameter from the URL to land you back where you started. The previous guard refused absolute URLs and protocol-relative paths (`//evil.com`) but let URL-encoded variants through — `/%09//evil.com`, `/%2F/evil.com`, `/%68ttps://evil.com` and similar. None of these would have caused account compromise on their own (Steam and Epic both reject off-origin redirect URIs), but a crafted link could have sent a user from a legitimate sign-in to a fake page after authentication. The guard now percent-decodes, strips control characters and whitespace, folds backslashes, and refuses absolute URLs after decoding — both server-side and client-side as defense in depth. Legitimate paths like `/dashboard?next=/match/abc` keep working.
- POLISH
Discord coach bot's perspective picker (the dropdown that asks 'which player are you?' when auto-detect can't tell) is now fully test-covered. The flow shipped to production last night with no test harness; the rebuild adds unit cases for the uploader-identity guard (which prevents another guild member from hijacking someone else's perspective click), the quota-exceeded path, and every poll-outcome branch including the re-poll-needs-perspective edge case.
- POLISH
Internal: SSRF allowlist on the Discord CDN attachment fetch. The bot uploads a replay by pulling its URL from a Discord CDN host; the helper now refuses anything that isn't `cdn.discordapp.com` or `*.discordapp.net` over HTTPS, with no userinfo segment. Defense-in-depth against the rare path where the bot service token leaks; rejections are logged at `error` for operator alerting.
- NEW
- v1.7.7 · In-game clock, drill re-curation, debrief UUID leak, 5→7 manual upload, timezone display7 changes
- FIX
Coach report timestamps now match what you saw on the in-game clock. Previously every timestamp the AI cited was actually replay wall-clock seconds — that includes post-goal celebrations, kickoff countdowns, and the pre-match pause, none of which the Rocket League scoreboard counts. A goal scored at 4:32 in a 3-goal match was getting cited as 7:52 in the narrative, off by ~30 seconds per prior goal and compounding through overtime. YolkedJoka spotted it: 'my ranked games did not have several hours of overtime lol.' Now in-game seconds are the canonical axis for every event the model can cite, plus the match duration shown on the overview tab. New reports written from today onward use the fixed clock; old reports keep their stored values until a backfill pass runs them through the worker again.
- FIX
Training pack codes re-curated from prejump.com. Three codes in the catalog were dead (404 on prejump, error in RL): Wall Shot Consistency (F5C7-…), Poquito Ground Shots (097C-…), and Counter-Attack Reset (5E3A-…). Two more were live but trained the wrong thing: the 'Boost Management 48 Boost' pack used to rely on a Psyonix setting that was removed in a 2025 update, and the 'Recovery Training' pack got mapped to four drills it doesn't actually train (pad routes, slow play, powerslide tempo) when it's a lobbed-ball recoveries pack. 16 of 23 drills get new codes; 7 keep what they had after re-verifying. YolkedJoka caught the broken ones.
- FIX
AI session debrief no longer pastes raw match UUIDs into the narrative. Myst sent a screenshot of a debrief that read 'Specifically, in match a74e4866-0827-41c7-bc7c-9064c2d82514 at 04:13' — the model interpreted the internal ID as a citation token because the prompt said 'time citation (matchId or MM:SS)'. The prompt now feeds 'match 1', 'match 2'… ordinals instead of UUIDs, and the rules forbid pasting any raw identifier. New narratives reference matches the way you'd talk about them ('match 3 at 1:42 elapsed').
- NEW
Manual upload cap raised from 5 to 7 files per drop. A typical 1-2 hour ranked session is 6-8 games — at the old cap you had to split a session in two batches, which sometimes pushed the second half outside the 45-minute window the session-grouper uses, so a single night's games came out as two separate sessions. Seven matches one of the most common session sizes from the Discord feedback. The monthly quota (10 Free / 50 Pro) is unchanged. Asked for by Myst.
- FIX
Match times now show the wall-clock you actually played in, not a timezone-shifted version. Myst's session card showed 4:40-5:09 PM for games she played around 8 PM EST — the replay file stores the player's local clock without any timezone tag, but our parser was treating it as UTC, so the browser was re-converting and shifting it. The display now treats those values as 'the clock you saw' and renders them straight through. Side benefit: if you check the dashboard from a different timezone than where you played, the times stay consistent across devices.
- POLISH
Bare MM:SS timestamps in the coach narrative now read 'X:XX elapsed' so there's no ambiguity with the in-game countdown clock. The first time the model writes a timestamp in a report it looks like '0:19 elapsed' instead of '0:19' — once a reader sees the suffix once, the chronology of the rest of the narrative reads cleanly. Both YolkedJoka and Cranddy had hit confusion in opposite directions (one read elapsed as countdown, the other read countdown as elapsed) — the suffix removes the guess.
- POLISH
Schema bumped to v7 again. Forward-only: every parse from today onward carries the corrected in-game clock on durations and event timestamps. Old matches keep working but their AI reports keep showing the stored wall-clock values until they're rerun through the worker — the next replay you upload will use the new clock.
- FIX
- v1.7.6 · Positioning metrics, manual session close, bulk combined report6 changes
- NEW
Metrics tab now surfaces positional, role, and team-play numbers alongside Boost/Pace/Events. New rows include time spent as first man, mid man, and last man; share of time in your offensive, midfield, and defensive thirds; first-touch win rate; possession share; goal participation; and average shot quality. These were already being computed under the hood and the model was using them in your coach reports — they just never had a dedicated panel. Direction tags are deliberately neutral for the role and zone metrics because the 'good' value depends on your role (a 3v3 defender benefits from a high last-man number, a striker from a high first-man number), so those rows stay uncoloured. Asked for explicitly by johnny on Discord and indirectly by Myst.
- NEW
Trends dashboard picks up the same set of new metrics. Two are in the default chart grid (first-touch win rate, goal participation) since johnny called those out by name; the rest live in the metrics picker for opt-in. Old matches uploaded before today appear as gaps in the new chart lines — the data point simply didn't exist yet for them.
- NEW
Manual session close. New 'End session now' icon button in the top bar (next to the pause-sync toggle). Click it after your last game and the system locks the session in immediately instead of waiting 45 minutes for the auto-close to fire. If two or more matches were in that session, the combined session debrief generates right away. The next match you play starts a fresh session. Idempotent — clicking it twice in the same window is a quiet no-op. Asked for by johnny.
- NEW
Bulk upload combined report. When you drop two or more replays at once into the manual upload zone, you'll see a 'Combine into one report' toggle. Turn it on and the AI analyses all the replays as a single coaching session, focused on patterns that repeat across the games rather than one-off variance from this teammate or that lobby. Each replay still consumes one analysis slot like normal; the combined report is value-add on top — you don't get charged extra for it. Asked for by tඩkyට on Discord. Defaults to off so casual two-file drops keep the familiar per-match report shape unless you explicitly opt in.
- POLISH
Live-session feedback in the match-list sidebar. A fresh first match in an active session now shows an 'Active session · 1 match so far' pill with a pulsing dot, so you can tell the auto-grouping is preparing to absorb your next game instead of treating the current one as a standalone. The sidebar also keeps polling at a slower cadence (about every 30 seconds) when you've played a match in the last 90 minutes — so a new replay arriving from PsyNet sync shows up without you needing to refresh. Outside the active-session window, polling stops entirely like before.
- POLISH
Schema bumped to v7. Forward-only: every parse from today onwards carries the new role / zone / team blocks. Old matches keep working but render the new bars as 'Not available' until you re-upload or re-sync. No backfill is needed — the next session of games you play will populate the trends naturally.
- NEW
- v1.7.5 · Hotfix: email verification was failing for ~10 hours3 changes
- FIX
Email verification through the dashboard banner was broken between roughly 1:30 AM and 12:30 PM CEST today. If you signed up via Steam or Epic and tried to verify your real email address during that window, you would have hit a 'Verification failed' redirect on every click, even with a fresh resend. The cause was on my end: yesterday's v1.7.4 ship added a database safety check for one-time-use confirmation links, but the database table that backs that check wasn't created on production before the code went live. Every legitimate click was treated as a replay attempt and rejected. The table is now in place, the affected users (about 26 of you) just need to click 'Resend verification' once more and the new link will work first try. Sorry for the friction, this one was 100% on me.
- POLISH
Hardened the error handling around that same code path so a similar production outage can't be silently masked as user behavior again. The confirmation route now distinguishes a real 'this link was already used' from an infrastructure failure (table missing, FK violation, connection drop), and the latter surfaces in the error logs at the right severity instead of being treated like a replayed click.
- POLISH
Tightened a Postgres function (the trigger that auto-stamps 'last updated' timestamps on session labels) by locking down its schema search path. This addresses a Supabase security advisory and removes a theoretical schema-shadowing attack vector. Behavior is unchanged.
- FIX
- v1.7.4 · Post-launch hardening: faster pages, safer perimeter8 changes
- POLISH
Under-the-hood performance pass after the recent launch surge. The match-detail page now fetches its five independent pieces (metrics, played rank, coach report, drill state, last resolved drill) in a single parallel batch instead of five sequential round-trips — cuts ~30-50ms of pure DB latency per click. The sidebar's session-grouped view, which was doing a quadratic JS loop over your entire ready-match history on every dashboard load, is now a single Map lookup; for users with 200+ matches that's a noticeable snappiness gain. Polling cadence relaxed from 5s to 10s on both the match list and detail views — invisible to you (typical parses take 30-90s), meaningful to the database.
- POLISH
Rate limiting now lives on every API endpoint. 100 requests per minute per IP as a baseline, with health checks and billing webhooks exempt (the latter has its own HMAC signature verification). The limit is backed by our existing Redis so it survives process restarts and applies across all Fly machines. This is what stops a credential-stuffing run on OAuth, a brute-force sweep on email-change tokens, or a sync-call flood from dragging down the whole service for everyone else.
- POLISH
First-load JavaScript on the match-detail page is smaller. The Heatmap, Timeline, Lobby, and Metrics tabs now load only when you click them, instead of being shipped to every user who opens a replay. Overview and Coach Report stay statically imported because that's where almost everyone lands. If you only ever look at Overview, you no longer pay the bandwidth or parse cost of the canvas-heavy heatmap code.
- POLISH
Database indexes added to the tables every authenticated request touches — matches list, status filter, PsyNet dedup lookup, billing webhook out-of-order guard, chat sessions. Before today, the matches table had no indexes at all and was doing a sequential scan on every page load. Combined with the parallel-query change above, the dashboard should feel meaningfully crisper at any history size. Production database connection pools were also right-sized down so Supabase's pooler doesn't run out of slots under burst load.
- FIX
Email-change confirmation links are now single-use. Previously, if you ever forwarded a 'Confirm your new email' message to yourself across devices, or if the link sat in your browser history, anyone with that URL could replay it for the full 24-hour validity window to keep flipping your email back and forth. The first valid click now consumes the link; the second sees the standard 'verification error' redirect.
- FIX
Quota counter is now race-safe. Two replays parsing at the exact same moment — both crossing the monthly cap — could previously both decrement and leave the counter one below the cap, silently giving you one extra match. The increment plus cap-check are now a single transaction, and the database rejects any negative value as a safety net. Plus a small piece of debug-only PsyNet sync routing (the dry-run override that let internal triage peek at any Epic player's match history) is now admin-locked.
- POLISH
Production logging trimmed by ~95%. The API was emitting an access-log line for every single request at the noisy info level — most of which were uninteresting 2xx responses. We now log only warnings, errors, and the explicit security/billing events we actually care about. Audit trail unchanged, just without the 200-line-per-second floor that was inflating log-aggregator cost.
- FIX
Small footgun cleanups: webhook HMAC comparison now operates on raw bytes instead of base64 strings (functionally equivalent today, less fragile under future maintenance); replay upload-confirm fetches the row with both id-and-ownership in one query instead of fetching then checking; SQL interval calculation in the homework endpoint moved from raw-SQL string concatenation to a typed parameterized predicate; JSON-LD structured-data escapes extended (>, &, JS line separators) so user-controlled content can't break out of the script tag even if it ever reaches that surface.
- POLISH
- v1.7.3 · Private 4v4 lobby played 3v3 no longer rejected, plus louder rename errors2 changes
- FIX
Private matches set up in a 4v4 lobby but actually played 3 vs 3 (or 2 vs 2) were being rejected at upload as '4v4 (Chaos) isn't supported'. The mode detector was reading the lobby cap from the replay header instead of counting the actual players on each team — so a perfectly normal 3v3 Soccar game that happened to live inside a 4v4 lobby got hard-rejected as Chaos. It now counts the real roster (and falls back to the lobby cap only if the roster info is missing). Genuine 4v4 with 4 per team still rejects, since no baselines exist for Chaos. Reported on Discord this evening — turnaround was about an hour.
- POLISH
Renaming a session in the sidebar now surfaces failures as a toast instead of silently reverting to the unnamed state. Previously, if the API rejected the rename (rare, but possible during a deploy, on a flaky network, or with a stale tab), the check-mark click looked successful but the chip popped back to 'Name session' with no indication anything went wrong. Now you get a clear 'Couldn't save the session name' toast with the underlying reason, so you can retry or refresh. Same treatment for the clear-label flow.
- FIX
- v1.7.2 · Quota leak fix, delete replay, name your sessions3 changes
- FIX
Fixed a quota leak that double-charged Pro users who picked the player perspective on a replay. The match-history count now matches the quota meter exactly. Four affected accounts were reconciled directly — if you're one of them, you've already got your monthly slots back. The path was: PsyNet couldn't auto-detect you in the replay → you picked yourself from the dropdown → that re-analysis silently consumed an extra slot without showing a new match. Now the re-parse correctly reuses the original slot.
- NEW
Delete a match from your history. Useful for the lobby-restart case (you queued, the lobby died, you don't want that ghost match dragging your trends), or any replay you'd rather not see in your session timeline. Two-click confirm in the match detail page. Heads-up: deleting does NOT refund a monthly slot — otherwise users could delete losing games to free up Pro quota, which would quietly break the whole pricing model. PsyNet auto-sync will not re-ingest a replay you've deleted.
- NEW
Name your sessions. Click the pencil next to a session card and label it 'Scrim vs Team X', 'Tournament prep', 'Ranked grind', whatever helps you find it later. 50 characters max. Labels persist as long as the first match in the session is around, and survive new matches being added to the same session window. Asked for by Myst on Discord this morning — went straight from feedback to shipped on the same day.
- FIX
- v1.7.1 · Non-soccar reject, full v3 reports, elapsed clock3 changes
- FIX
Hoops, Dropshot, and other non-Soccar replays are now rejected upfront with a clear 'Hoops isn't supported' message instead of being silently analyzed as 2v2 Soccar (which produced nonsense feedback like 'whiff at 5:36' on a saved Hoops shot). No quota is spent on rejected replays. The check fires both at upload time and inside the worker, so PsyNet auto-synced replays are also covered. Snowday and Rumble overlay onto standard arenas and aren't detectable from the replay header — they still get through, but the detector is one file away from being extended if it becomes a real issue.
- FIX
AI coach reports (v3) now show all four sections — Summary, How the match unfolded, Things to improve, Done well — for every match. Previously the report could appear truncated to just Summary + drills, reading like 'you played perfectly except one thing', because the model was storing the Improve/Done-well content in structured JSON fields that the UI wasn't rendering. The fix is purely on the rendering side, so every existing v3 report in your history now shows in full — no re-analysis needed.
- FIX
Match timestamps in the AI narrative now read as elapsed time from kickoff (0:00 → 5:00) instead of the in-game countdown clock (5:00 → 0:00). The countdown format was being consistently misread as elapsed, making chronological narratives look reversed ('save at 4:53, first goal at 2:47' read as late → early). Elapsed format follows sports-convention and the chronology now reads naturally: smaller numbers happen earlier in the match.
- FIX
- v1.7.0 · Manual replay upload, in the dashboard2 changes
- NEW
Drag and drop replay files straight into the dashboard. Useful for two cases auto-sync can't help with: scrim or unranked sessions where tracking was off before you queued up, and quota efficiency — pick specifically which replays you want analyzed instead of letting PsyNet decide what gets the slot. Sequential queue handles up to 25 files per drop with per-file progress bars; each one moves from 'Preparing upload' through 'Validating replay' to 'Queued for analysis', and your match-list sidebar updates the moment a replay lands. Runs alongside the existing PsyNet auto-sync — both feed the same parse pipeline, the same monthly quota, and the same coach report.
- POLISH
Free accounts uploading a replay outside their picked focus mode now get a clear Pro upsell dialog explaining the gate — what wasn't analyzed, why, and the two ways out (switch focus mode in settings, or upgrade to Pro for any-mode analysis). The replay isn't counted against your monthly quota when the gate trips, and the file row stays visible in amber so you can decide what to do without losing track of what you dropped.
- NEW
- v1.6.1 · Dashboard rebuild: editorial layout, semantic colour, collapsible sidebar8 changes
- POLISH
Dashboard layout rebuilt from the ground up. The populated dashboard now leads with a status masthead (live indicator, tracking duration, rank/mode/quota chips), an asymmetric Today + Trends row, a Sessions + Homework + Ranks bento, and a slim account footer — replacing the old equal-width three-column broadsheet. The empty-state and standing-by views were also rebuilt as focused heroes; the previous Watching screen was reflowing once a second, which is gone.
- POLISH
Match list sidebar can now be collapsed to a slim 48px rail with one click. Your preference is remembered across sessions via local storage. The active page in the top bar gets a clearer indicator so you can tell at a glance whether you're looking at Matches, Homework, Trends, or Sessions.
- POLISH
Three banner styles (email verification, mode drift, unreviewed sessions) collapsed onto one notification card pattern. Win, loss, and draw indicators across the dashboard now use a desaturated editorial palette in oklch instead of the previous oversaturated Tailwind 300-tone hex — same information, calmer reading.
- POLISH
Reduced-motion accessibility. If your system requests reduced motion, every hover lift, spring transition, and live-pulse animation on the dashboard is now collapsed to near-instant. Functional state changes still happen — just without the motion.
- FIX
Open coach report card on the dashboard no longer offers a Browse all matches in session link to a destination that doesn't exist yet. The single Open coach report row now mentions the session size in its hint instead.
- FIX
Backgrounded dashboard tabs no longer burn a one-minute timer for no reason. The Pulse heartbeat that keeps Last sync · Next radar copy fresh now pauses while the tab is hidden and re-syncs on focus.
- FIX
Session debriefs landing while the dashboard is open now show up within ~60 seconds on the Sessions card, instead of going stale forever and requiring a manual page reload.
- FIX
Accessibility cleanups in the account footer and notification banners (valid HTML list structure, screen-reader landmarks instead of polite live regions on persistent banners).
- POLISH
- v1.6.0 · Homework, Trends, and a smarter coach8 changes
- NEW
Homework tab is live for everyone (free and pro). Every drill the coach has ever recommended you across all your matches now lives at /dashboard/homework as a single inbox. Three actions per drill: Done, Snooze (7 days), Skip. The TopBar shows a small badge with how many drills you still owe yourself, capped at 9+. State persists across sessions and devices, and the next coach reports check whether you're actually working on what was assigned.
- NEW
Trends dashboard for Pro at /dashboard/trends. Each metric (boost average, supersonic %, time at zero, shots, and more) gets a line chart over your last 25 matches with an improving / stable / declining badge that respects the metric's direction. When we have a baseline for your rank in the selected mode, the rank p50 line is overlaid so you can see where you stand. Free users get a 5-match preview window so they can taste the feature without paying.
- NEW
Mechanical detector: the coach now spots whiffs in your replay and recommends specific training packs when you whiff multiple times in a match. Mechanical drills appear in the per-match To try next card with a small purple Mechanical badge, and the coach report cites each whiff by countdown timestamp (you whiffed at 4:37, 3:14, 1:48) so you can re-watch them.
- NEW
Sessions view: the match list sidebar now groups your matches by play session (consecutive games close together in time) instead of one giant scroll list. Each session shows a quick W-L tally at a glance.
- POLISH
Coaching trust restoration batch (six fixes). The coach now remembers what it said about you in previous reports and won't repeat the same critique three matches in a row, rotates drill recommendations when you haven't moved on a focus area, cites specific moments more often instead of generic verdicts, and drops the false continuity narrative that pretended to track multi-game arcs that didn't exist.
- POLISH
Bright theme is available alongside the existing dark theme; toggle it from the avatar menu. Sidebar gains a search-by-player-name filter so you can find a specific match faster. Quota and tracking countdown labels are clearer about what they represent.
- FIX
Manual perspective pick on a match (the dialog that appears when we couldn't auto-detect which player is you) now disambiguates by name + team instead of just the platform primary id. Fixes a corner case where two players in the same match shared a display name and we'd pick the wrong one.
- POLISH
Internal AI cost optimization: standardized to gemini-3.1-flash-lite for both tiers. Reduces our monthly inference bill by roughly 85%. No user-visible change to coach report quality on the metrics we track; we'll keep an eye on it and revert if anyone notices regressions in pro-tier writeups.
- NEW
- v1.5.8 · Less friction on the Epic link step4 changes
- FIX
The Pause Sync toggle we shipped earlier today (v1.5.7) was only rendering inside the empty-state dashboard — Pro users with any matches at all couldn't actually find it. Moved it into the persistent TopBar next to the Sync from Rocket League button so it's reachable from anywhere in the app. Pause / Resume still gated to Pro accounts; nothing changes for Free users.
- POLISH
Tightened the Epic auth-code paste dialog after a beta tester said the format felt like a guessing game. The textarea hint now says 'Paste anything — full JSON, just the code, with or without quotes. We parse it for you' instead of implying you have to keep the braces. The parser was already permissive; the copy now matches.
- POLISH
Added a short privacy note in the same dialog header: 'This code only tells us which Epic account is yours so we can find your replays. We never see your payment info, friends list, or anything else inside your Epic account.' Epic's own warning at the OAuth screen is generic and reads scary; this disclaimer makes clear what we actually do with the code.
- POLISH
The dashboard helper walkthrough is no longer a forced auto-play. It now has player controls — pause, previous step, next step, restart — and you can click on any of the five progress dots at the top to jump straight to that step. Keyboard shortcuts work too (space to play/pause, arrow keys to step, R to restart). One tester said they had to watch the whole thing twice to catch a detail; now they don't.
- FIX
- v1.5.7 · Pause sync when you want to spread out coaching2 changes
- NEW
Pro accounts can now pause replay sync from the dashboard. If you grind 50 ranked a week you don't have to burn your monthly coaching quota in the first ten days anymore — hit Pause Tracking and the scheduler stops pulling from PsyNet. When you click Resume, tracking restarts from that moment forward. Matches you play while paused aren't backfilled by design — Resume is a fresh checkpoint, not a catch-up. There's a confirmation dialog so nobody trips into it by accident. Free stays on the monthly quota; the pause toggle is a Pro perk.
- FIX
Removed the 'Issue 02' / 'Issue 01' labels next to the Watching and Welcome indicators on the dashboard. They were meant as magazine-style edition numbers but kept reading as error codes — especially when a user landed on the dashboard while their replays hadn't synced yet. The pulsing live-status dot was doing the work the label was supposed to do anyway; the suffix was just adding noise.
- NEW
- v1.5.6 · Auto-detection, no toggle required3 changes
- NEW
Replays are now analyzed in their actual lobby type automatically. The Ranked / Private toggle we shipped this morning is gone — there's nothing to flip anymore. Upload or sync any replay and the system figures out whether it was a ranked match or a scrim, then compares against the matching pro baseline (ranked vs ranked, scrim vs scrim). One less setting to remember.
- NEW
Pro accounts also get full mode auto-detection. If you're on Pro and have, say, 3v3 selected as your default lens but jump into a 2v2 with a friend, the 2v2 replay still gets analyzed instead of being rejected as "mode mismatch". If your current pro doesn't cover that mode the comparison band stays empty, but the rank-based comparison and the coach report still run. Free accounts keep the mode lock since that's the upgrade gate.
- POLISH
Match-detail's mode-mismatch warning now points Free users at the upgrade page rather than the preferences page, since switching modes on Free isn't an option. The card explains that Pro analyzes any mode automatically.
- NEW
- v1.5.5 · Ranked vs scrim, finally a real switch4 changes
- NEW
A Ranked / Private toggle now lives next to the game mode picker in the TopBar — only when you're on 3v3, since that's the only mode where pros consistently play both. Flip it and your replays are analyzed under the matching lobby type — ranked replays compared against the pro's ranked baseline, scrims against their scrim baseline. The two never get blended. Until today the toggle simply didn't exist in the UI, so every private/custom replay you uploaded was silently rejected as "mode mismatch" no matter who you were. Scrim-only 3v3 players, in particular, had nothing to look at; that's fixed now.
- NEW
The Ranked / Private switch is available to Free accounts too. The game mode (1v1 / 2v2 / 3v3) stays locked to one choice on Free, since that's the meaningful upgrade gate — but locking the lobby axis on top would mean scrim-only Free players literally cannot use the product, which we never intended. Pro scrim baselines were already being built in the background for every active pro, so opening this up costs nothing on our end.
- POLISH
Match cards in the sidebar now show a small "PRIVATE" tag next to the mode label when a row is a private/custom lobby. Neutral metadata styling — not a warning, just an at-a-glance signal so you can spot which matches were scrims vs ranked without opening each one. Hovering the tag explains what it actually changes ("compared against the pro's scrim baseline, not ranked").
- POLISH
Reworked the match card layout so the italic score (e.g. 6-3) no longer collides with the relative timestamp on the right. The top row is now match identity (mode + score), the bottom row is context (arena · duration · time ago). The score gets its own visual lane, and the card reads in two clean rows instead of one cramped one.
- NEW
- v1.5.4 · Pro activation, automatic again2 changes
- FIX
Paying for Pro now actually flips your account to Pro without manual intervention. Polar's webhook deliveries to our API had been silently failing signature verification all morning — the webhook secret stored on our end had drifted out of sync with what Polar was using to sign requests, so every "subscription created" notice was being rejected at the door. Five paying customers were on Free for hours before this was caught. Two of them were stuck mid-window; their accounts have been promoted server-side (no action needed on their part), and the secret on our end is now sync'd so any future checkout flips to Pro within seconds of payment.
- POLISH
Added a checklist in our operational notes for rotating the Polar webhook secret without dropping deliveries — copy from the post-reset modal (not the static read-only display), set on Fly immediately, verify the digest changed, sign a probe locally to confirm match. The previous failure mode was that the dashboard kept showing a pre-rotation value after a partial reset, so the operator copied a stale secret without realising.
- FIX
- v1.5.3 · Email verification, end-to-end4 changes
- FIX
Email verification now works for Steam/Epic OAuth signups. Beta testers landing through the platform login were never receiving the "confirm your email" mail — the old flow asked Supabase to send it but the admin endpoints it used never actually invoke the mailer, so the dashboard would promise "check your inbox" against a mail that never went out. The post-profile-completion email is now generated, signed and delivered end-to-end by P4cely itself via Resend, with a confirmation link that lands users back on the dashboard with a verified state. Existing users who were stuck mid-flow have been recovered server-side.
- FIX
The "verify your email" banner now disappears in-session the moment you click the confirmation link, instead of sticking around until you log out and back in. Same applies to the "email verified" toast that confirms it landed.
- POLISH
Removed the obsolete "Link a Google email" banner that appeared on Steam/Epic dashboards — the new email-verification flow already gives Steam/Epic accounts a real inbox association without needing a separate Google link.
- POLISH
Streamlined the post-signup onboarding to a single editorial wizard (pro → mode → rank). The legacy 2-step picker that some users were still landing on has been retired; the new wizard already shows which pros are available on Free vs reserved for Pro upfront, so you never click into a pro that the save will reject.
- FIX
- v1.5.2 · Mobile-first sweep4 changes
- FIX
Coach setup (onboarding wizard) is no longer truncated on iOS Safari. The header (logo + 'Substep XX of 03') was overflowing on narrow viewports — the right-side counter collided with the wordmark and the right edge clipped 'OF 03'. The logo now scales down on mobile, the counter abbreviates to 'Step XX/03', and the section padding tightens to leave room for the content. Same fix applied to the Profile completion screen.
- POLISH
Full responsiveness pass across the app for mobile-first viewports (375px iOS Safari and up). Marketing pages (hero, pricing, FAQ, footer, terms/privacy/changelog), auth screens (login, profile, email-verify banner), the match-detail tabs (Lobby player rows, Timeline track labels, Coach report markdown tables/code), the TopBar avatar dropdown, settings frame and the Pro picker's Free-roster banner — all rebalanced so nothing overflows or stacks awkwardly on a phone. Tablet/desktop layouts unchanged.
- POLISH
Coach Report tables and long code blocks now scroll horizontally on mobile instead of breaking the page. Long links wrap on word boundaries instead of pushing the column wider than the screen. Markdown text sizes scale down a notch on phones for comfortable reading without zooming.
- FIX
Account menu dropdown no longer escapes the viewport on small phones — its width is now clamped to the screen instead of forcing a fixed 256px that overflowed past the right edge on iPhone SE-class devices.
- FIX
- v1.5.1 · Pro quota, visible2 changes
- FIX
Pro's 50 matches/month cap is now actually enforced. The pricing page has promised 50/month since Pro launched, but the code path treated Pro as unlimited internally — so a determined power user could exceed the cap silently. Upload presign and the worker parse gate now both check the 50/month ceiling, and a parse failure refunds the slot the same way it does on Free.
- POLISH
The TopBar quota meter is now visible on Pro instead of hiding when you upgrade. Pro users see 'X/50 matches this month' alongside the Pro badge — same shape as Free's 'X/10' — so the monthly allotment is at-a-glance instead of invisible until you hit it. The tooltip and the upgrade link still only appear for Free.
- FIX
- v1.5.0 · The Pacely Daily9 changes
- NEW
Free tier doubled: 10 matches per month, up from 5. Existing free accounts get the higher cap immediately — no resync needed, the next quota refresh after this release just sees the new ceiling.
- NEW
The /dashboard landing page was redesigned as an editorial broadsheet — "The Pacely Daily". The masthead carries a date and an issue number that climbs with every match you upload. The big block is the lead story, generated from your most recent session: a headline that adapts to the win/loss split, a drop-cap paragraph reading the score against your rank baseline, and a row of result dots so you can take in the session at a glance. Below that, a three-column spec strip (Index · Member · Position) and a two-column footer for rank benchmarks + platform wiring.
- NEW
The match-list sidebar now groups your matches into sessions instead of one row per match — 200 individual matches collapse to roughly 30 session cards. Each card shows a row of result dots, the win/loss tally, and a verdict letter for the session; tap to expand and see the underlying matches. The latest session is open by default.
- NEW
Pro dossiers (/pros/[slug]) gained a Previous / Next flip-through at the bottom of the page so you can sweep through the roster without jumping back to the index. Hovering the next pro's name previews their team accent color before the click.
- NEW
New homepage section: a six-question FAQ in the same editorial register as the rest of the front page, distilled from real Discord and X replies — what Pacely is, whether it replaces coaches, who can use it, what game modes are supported, what data we read, and how it makes money.
- NEW
Onboarding helper: brand-new users now see a 60-second walkthrough card next to the platform-connection panel on the empty dashboard. Click it for a self-running animation of the link-Steam-or-Epic flow. Dismiss it once and it stays gone.
- POLISH
The sidebar scroll experience got a make-over: the column fades softly into the top and bottom edges instead of cutting at a hard line, the scrollbar is now a thin rail rather than the bulky native one, and the filter chips are tucked behind a single collapsible toggle with a one-line summary of what's active. The previous setup wasted vertical real estate that the match list needed.
- POLISH
Icons refresh: the favicon and apple-touch-icon now use the new rounded red Pacely mark and are sharper at every density (the previous favicon was a placeholder SVG that broke on some browsers). Tab + bookmark + iOS home-screen + Android PWA all pick up the new icon automatically.
- POLISH
The homepage footer dropped the oversized "P4cely" italic wordmark at the bottom — it was filler back when the page closed on a small legal strip, and the new FAQ section above it makes that flourish redundant.
- NEW
- v1.4.1 · Hardening sweep7 changes
- FIX
Replay parse retries no longer risk debiting your monthly slot twice. The worker now claims a queued match atomically and refunds the slot if a re-delivery arrives after the first run already succeeded.
- FIX
Replay uploads larger than ~25 MB are rejected up-front with a clear error instead of being silently parsed (real Rocket League replays are 0.5–2 MB; anything over the cap is almost certainly a corrupted or unrelated file).
- FIX
If your sign-in token expires mid-session, the dashboard now silently refreshes it once instead of surfacing a generic error toast. If the refresh fails you land on the sign-in page with your destination preserved.
- FIX
Confirming a replay you didn't own returned a 403 (which leaked whether that match existed for someone else). Both "doesn't exist" and "not yours" now return the same 404 so existence isn't leakable.
- POLISH
Aerial-percent and pace metrics are now computed only on live play (goal replays and post-match frames are skipped), and the wheels-off-the-ground threshold was tightened so ordinary ground driving no longer registers as airborne. Newly-parsed matches will show slightly different numbers; older matches keep their original values until re-parsed.
- POLISH
Rank-baseline percentiles for small cohorts are more accurate. We switched to linear-interpolated quantiles (the same formula NumPy uses by default), so a percentile is a real percentile instead of a nearest-sample approximation. Mostly invisible on large pro cohorts; meaningful for ranks with thinner sample windows.
- POLISH
Internal hardening pass: tighter CORS cache-key behaviour, capped agent-token revocation cache, scoped /me PATCH so a leaked agent token can't change your pro / mode / rank, a 5-minute hard ceiling on each replay parse so a hung outbound call can't starve the queue, and an automated test that fails CI if any new DB table is missing row-level security.
- FIX
- v1.4.0 · Rank-aware coaching8 changes
- NEW
Coach reports now read your match against both pros AND your own rank tier in the same paragraph ("for your rank, ~50% boost-in-tank is the bar most reach by Diamond — yours was 42%"). Rank baselines exist for every tier from silver to Supersonic Legend across 1v1 / 2v2 / 3v3, so the dual-percentile read fires whenever you have a rank declared.
- NEW
Session debriefs. When you finish 2+ matches in a session and haven't opened any of the per-match reports, a debrief lands in your inbox that ties the matches together — recurring patterns, drill follow-up, what to take into your next session. Pro gets the full ~500-word debrief; Free gets a 180-word summary plus the upgrade nudge. A banner on the dashboard shows the unviewed count.
- NEW
Rank benchmarks throughout the dashboard. New /dashboard/ranks page renders a comparative table of every rank tier across the 5 highest-signal metrics for your active mode — see exactly where your tier sits vs the ones above and below. New Lobby tab in match detail puts every player (teammates + opponents) on a shared scale per metric, with an MVP crown and a "best in lobby" pill. Settings gets a rank mini-card with your tier median + p25-p75 spread. The match-detail header now pins the rank you were at when the match was played, not just your current rank.
- NEW
Opponent micro-analysis. When the team across the field dominated the exact metric the coach flagged as your weakest area, the report calls out the gap with concrete numbers — "opponents averaged 14% boost wasted vs your 22%" — so the priority isn't abstract.
- POLISH
Coach reports got longer and denser. Pro reports now target ~500 words with an 800-word ceiling (was a hard cap at 600 with no positive target — most stopped well below it). New "How the match unfolded" section sets the chronological scene before the prescriptions land, so you can place each suggestion in the flow of the actual game.
- POLISH
The match-detail header rank pill now reads as the public-facing tier + division (e.g. "Champion III · Div II") with a tooltip showing matches-played-at-that-rank. The previous label exposed the raw TrueSkill μ score as "MMR", which looks like a 2-digit number and confused everyone — that's gone.
- FIX
Positioning heatmap proportions. The previous render dropped ~10% of data along each sidewall and silently squashed everything within ±20% of the goal mouths because two coordinate constants were swapped. New heatmaps render with full lobby coverage. Matches uploaded before this release keep their old (incorrect) heatmaps until re-parsed.
- FIX
Replay uploads no longer stall after a worker deploy. Each worker rolling-restart used to trigger a background baseline-refresh fan-out at boot, which could starve new replay parses for 90+ minutes if the refresh ran into BallChasing rate limits. Boot-time fan-out removed and per-cycle batches shrunk so this can't happen again.
- NEW
- v1.3.2 · Self-serve subscription management2 changes
- NEW
Manage your Pro subscription without writing in. The Pro panel on /billing now opens a Polar-hosted customer portal where you can cancel, swap card, update billing details and download every past invoice — all live, no email round-trip. Cancellation keeps Pro features active until the end of the billing period you already paid for.
- POLISH
The Pro pricing CTA on the homepage now routes straight to the upgrade flow on /billing instead of dropping you on the dashboard with no instructions on how to actually subscribe.
- NEW
- v1.3.1 · Pro plan goes live3 changes
- NEW
Pacely Pro (€7/mo) is now purchasable. Polar.sh handles checkout, EU VAT and the credit-card flow as Merchant of Record — they are the legal seller, so the EU compliance burden lives with them and not with us. No credit-card data ever touches our servers; cancel any time from your account.
- NEW
Upgrade flow: clicking "Upgrade to Pro" anywhere in the app (billing page, quota meter, upgrade button on the dashboard) opens a Polar-hosted checkout. After payment you land back on the dashboard with Pro features unlocked — 50 matches/month, switch pros and playlists any time, Q&A chat per match.
- POLISH
Billing webhook hardening: signature verification follows the Standard Webhooks spec end-to-end, with explicit replay protection (±5 minute timestamp window) and delivery-level deduplication, so a delayed retried webhook can never resurrect a cancelled subscription.
- NEW
- v1.3.0 · Coach reports that fit the match3 changes
- NEW
Coach reports adapt to how the match actually went. Dominate? You'll see 1 thing to keep an eye on and 2 things you did well. Rough loss? Two clear priorities and one realistic line so the report doesn't read like a pile-on. The rigid 'always 3 errors, 1 good thing' layout is gone — the structure now reflects the game, not a template.
- POLISH
Reports lost the fake continuity. The coach no longer opens with 'last match I told you to…' when you might never have actually read the previous report. Match-level advice stays focused on the match in front of you; cross-match patterns will live in the upcoming session debrief.
- FIX
Every existing match report has been regenerated in the new format. If you reopen an older match, the report has structure that matches its performance grade and reflects only what happened in that match.
- NEW
- v1.2.2 · All-mode sync, focus-mode training4 changes
- NEW
Rocket League auto-sync now imports every supported replay mode instead of silently skipping matches outside your selected playlist. 1v1, 2v2, ranked 3v3 and private 3v3 all land in your history and are analyzed against the matching pro baseline for that replay's real mode.
- POLISH
The match index no longer hides off-focus modes by default. Your selected mode now behaves like a training focus, while the sidebar's All filter means your complete synced history.
- FIX
Heatmap comparisons now request the pro baseline for the match's actual mode and lobby type, so a synced 1v1 no longer compares against your 2v2 focus baseline.
- FIX
Coach Analysis copy now reflects reality: replay reports usually appear within a few seconds, not over the next few hours.
- NEW
- v1.2.1 · Tracking forward, smarter heatmap, fresher index13 changes
- NEW
Tracking-forward sync: when you click "Sync from Rocket League" for the first time, Pacely sets a checkpoint instead of pulling stale history. Only matches you play AFTER that moment land in your index — so your free quota goes to fresh games where the coach report can actually help you next session, not to last month's rage-quits.
- NEW
Watching dashboard: brand-new empty state for the gap between linking Rocket League and your first tracked match. Pulsing radar, live counter ("Watching for 12s"), next-poll countdown — reads like Strava's between-runs view, not a generic "no matches yet" page.
- NEW
Heatmap Compare view: a single divergent map showing exactly where you spend more time than your reference pro (rose) versus less (emerald). Replaces the side-by-side blue maps that buried subtle positional differences. Whole-match, single-glance coaching.
- NEW
"NEW" pill on freshly synced matches in the sidebar, with a slide-in animation as they arrive. Click the match and the pill clears — a quiet way to know which replays you still haven't reviewed.
- NEW
Background-sync toast: when the periodic poller lands a new match in the index, you get a "X new match(es) synced" notification — no more wondering if a refresh would surface something new.
- NEW
Tier-gated sync button: Free's "Sync from Rocket League" is now a status indicator ("Auto-sync next 8m") that respects the auto-poll cadence. Pro can still hit it any time for an instant manual fetch.
- NEW
Epic auth dialog redesigned in the editorial register — numbered step rows, proper marketing-display title, plus clipboard auto-detect: paste-or-copy the Epic JSON anywhere and the dialog auto-fills the code when you come back.
- POLISH
Heatmap intensity scale: each map now normalises to its own peak. The pro's 30-match aggregate no longer fades against your single-match cluster, and your hot zones stay legible against the pro's. Cluster shape is the comparable signal — magnitude was always misleading across asymmetric samples.
- POLISH
"Member since" on the dashboard now reflects when you joined Pacely, not when your platform identity first appeared. Survives session resets the way users actually expect.
- POLISH
Dashboard empty state copy aligned with tracking-forward: "Linking Rocket League sets your monitoring checkpoint" instead of the old "Sync pulls the last ~20 matches" promise we no longer make.
- FIX
Google account linking after platform signin no longer trips an SSL error on localhost setups — the auth callback now respects the original request protocol instead of hardcoding HTTPS.
- FIX
Platform-claim success toast now names the correct provider — "Your Epic Games account is now linked" instead of always saying "Steam" regardless of which one you actually linked.
- FIX
Mid-claim redirect loop fixed: when finishing a Google link from a Steam/Epic seed account, the dashboard no longer bounces you to the profile page mid-flow because of a dropped session header.
- NEW
- v1.2.0 · Auto rank, locked playlists, EU-friendly billing14 changes
- NEW
Rank is now read straight from Rocket League. Once you connect your platform account, Pacely syncs your tier and MMR after every parsed match — the manual rank picker steps aside in favour of a read-only "Synced from Rocket League" badge.
- NEW
Rank progression chart in Settings — your MMR over time on the currently selected playlist, drawn from every PsyNet snapshot we've captured so far.
- NEW
Free-tier playlist lock: once you finish onboarding, Free locks you to the playlist you picked. The TopBar mode toggle and Settings show the other modes with a small lock pill instead of letting you switch silently.
- NEW
Free-tier reference-player lock: the same rule extends to your chosen pro. Free picks one pro at onboarding and stays with them; Pro switches both pro and playlist any time.
- NEW
Match list now defaults to your active playlist after onboarding — no more 1v1 noise on a Free 3v3 account, no more confusion when a Pro user switches mode.
- NEW
Lenient drift hint: a Free user who hasn't played their locked playlist in a month but is active in another mode now sees an editorial nudge above the dashboard suggesting Pro.
- NEW
Switched payments to Polar.sh as Merchant of Record — they handle EU VAT and are the legal seller, so Pacely can launch in the EU without a P.IVA. Checkout opens on Polar; no credit-card data ever touches our servers.
- POLISH
Pricing copy aligned across the homepage, /billing and the Terms: Free clearly says "1 pro, 1 playlist (locked)"; Pro clearly says "Switch pro & playlist any time". The old "Unlimited" line is replaced with the honest "50 matches / month" cap.
- POLISH
Initial PsyNet backfill for Pro users respects the chosen playlist instead of grabbing whatever was most recent.
- POLISH
Welcome row on the dashboard now greets you by your nickname instead of the synthetic platform pseudo-email (the "Hi steam-12345" was unintentional).
- POLISH
Map names for Mannfield Dusk, AquaDome, Parc de Paris and Forbidden Temple variants — older arena codes no longer fall through to the underscore-strip fallback.
- FIX
Timeline pill markers near the end of a match no longer overflow the right edge of the track. Late-game events now anchor cleanly at the boundary while keeping their min-width for clickability.
- FIX
Rank progression chart edge cases: single snapshot now renders a visible point, constant-MMR series gets a horizontal centerline, and the SVG box keeps a 16:5 aspect ratio so mobile no longer letterboxes the chart.
- FIX
Oski's pro-picker tile is no longer blank — the avatar pointed at a renamed file that was never shipped.
- NEW
- v1.1.1 · The roster, public10 changes
- NEW
Public roster index at /pros — editorial grid of every pro Pacely tracks, in homepage order, with a team filter for the bigger orgs.
- NEW
Public per-pro dossier at /pros/[slug] — atmospheric photo banner, italic display name in the team's accent colour, four-discipline percentile bars, and BallChasing source replay links for every aggregated row.
- NEW
Per-pro editorial subhead on the dossier — a verified quote or notable moment for fourteen of the fifteen pros, sourced from Liquipedia, BLAST.tv, GGRecon and the players' own posts. No invented copy.
- NEW
Country flag + full country name on the pro byline (was a bare 'MA' / 'DK' code). Falls back gracefully when the flag CDN is blocked.
- NEW
Roster nav entry-points across the marketing surface — top header, footer Resources column, homepage hero tertiary strip, and a breadcrumb on the dossier itself.
- POLISH
Percentile labels rewritten as low / typical / high (was p25 / p50 / p75), with a one-shot reading caption above the cards — no per-row tooltip needed.
- POLISH
Per-team accent palette refined for Gentle Mates, Ninjas in Pyjamas, Shopify Rebellion, Geekay Esports and NRG. Propagates to homepage hover, index card border, and dossier paint.
- POLISH
Pro byline trimmed to Team / Origin / Last refresh / Reading window — the empty 'Total replays: 0' placeholder is gone.
- FIX
Dossier accent now correctly inherits the team palette. The previous cascade let the dark-theme neutral and the marketing red each override the per-pro accent in different ways; the colour is now anchored as an inline style on the dossier root.
- FIX
Roster card border on hover paints with the team's primary, not the marketing red default — fixed via a single slug → accent resolver shared between homepage and roster index.
- NEW
- v1.1.0 · Pro × mode dossiers11 changes
- NEW
Public pro dossier at /pros/[slug] — editorial press-room layout with per-mode percentile bars and BallChasing source links for every aggregated replay.
- NEW
Onboarding wizard at /onboarding/pro-mode — pick your reference pro and the discipline you want analyzed (1v1 ranked, 2v2 ranked, 3v3 ranked, 3v3 private). The dashboard now gates on having both set.
- NEW
Strict per-pro × per-mode × is_private baselines: comparisons no longer fall back across modalities, so private 3v3 gets compared against private 3v3 only.
- NEW
Pre-parse mode gate on upload — replays whose mode doesn't match your selection are rejected at upload-confirm with a mode_mismatch status (amber badge in the match list, dedicated panel in the detail view) instead of silently skewing the report.
- NEW
Weekly baseline cron fans out 4 refresh jobs per stale pro (1v1 ranked + 2v2 ranked + 3v3 ranked + 3v3 private) covering 10 pros per tick.
- POLISH
Baseline rolling window extended from 30 to 60 days — better aligned with pro tournament cadence.
- POLISH
Match-detail Metrics and Heatmap tabs now read the selected pro from the user-prefs store instead of prop drilling — copy stays in sync the moment you switch pro.
- FIX
Bucketing scheme made p50 reachable: values exactly at the median now classify as p50 instead of being absorbed into p75.
- FIX
detectIsPrivate regex tightened — Unranked / Exhibition / Lan no longer misclassified as private lobbies.
- FIX
Recommended drills card no longer surfaces the placeholder XXXX-XXXX-XXXX-XXXX training pack code as a copyable CTA.
- FIX
4v4 dropped from app-level filters and types — the enum value remains in Postgres for historical rows but no UI surface offers it any more.
- NEW
- v1.0.4 · Mobile-ready11 changes
- NEW
Match-list drawer on mobile — full match index now reachable from the TopBar below the lg breakpoint.
- NEW
Dynamic Open Graph image at the edge — every shared link now previews with the editorial card.
- NEW
Sitewide SEO metadata: per-page titles, OG/Twitter cards, viewport, theme-color (light + dark).
- NEW
Privacy & Terms pages live, written end-to-end in plain language.
- POLISH
Section steppers redesigned: inline editorial marker (Section / One) instead of a 140px watermark that overlapped headlines on 1440–1700px viewports.
- POLISH
TopBar collapses gracefully below md — non-essential badges hide, drawer trigger surfaces.
- POLISH
Marketing footer wordmark scales down without clipping ascenders on narrow phones.
- POLISH
±20% jitter on match polling so concurrent sessions don't fan into the API on the same tick.
- FIX
Contrast bumped on /login ("Steam or Epic" connector) and /settings/platforms ("Not linked") so they pass WCAG AA on dark.
- FIX
Platform account claim loop fixed — merging Steam/Epic with Google no longer drops profile settings or traps you in an onboarding loop.
- FIX
Removed the "works best on desktop" mobile banner — the dashboard is now genuinely responsive top to bottom.
- NEW
- v1.0.3 · Editorial pass8 changes
- NEW
/billing redesigned in the editorial register — Free strip + Pro card with brand-red upgrade pill, sparkles micro-interaction.
- NEW
/dashboard/settings rebuilt as a workshop-bench: sticky left rail, hairline rules between blocks, no card-in-card chrome.
- NEW
Profile completion flow at /onboarding/profile — first/last name, nickname, contact email captured right after Steam/Epic signin.
- NEW
Dashboard match-detail tabs scroll horizontally on mobile so all five tab labels stay legible.
- POLISH
AccountMenu now shows the real nickname + contact email instead of the synthetic platform handle.
- POLISH
Mode-tile copy on onboarding rewritten with coach vocabulary (3v3 = RLCS main stage, rotation discipline).
- FIX
Pro picker no longer skipped after profile completion — gate is now DB-authoritative (current_pro_id), not a stale Zustand value from a previous browser session.
- FIX
Pricing copy aligned across home and /billing (€7/mo, €70/yr — was inconsistent at €9 in one place).
- NEW
- v1.0.2 · One door for sign-in4 changes
- NEW
Unified /login + /register: Steam OpenID and Epic Games OAuth are the only entry points. No more email/password.
- NEW
Marketing homepage rebuilt around the editorial register — italic display headlines, mono caps eyebrows, hairline rules, brand-red accent.
- POLISH
Steam linking double-toast suppressed (React StrictMode dedupe via toast id).
- FIX
Match list 500 traced to a Drizzle migration drift — schema and journal re-aligned.
- NEW
- v1.0.1 · PsyNet sync hardening4 changes
- NEW
Trial-Pro slot surfaced in the quota meter so trial-tier matches don't look like over-quota errors.
- FIX
Mutex on manual + periodic PsyNet sync killed the quota_exceeded race.
- FIX
Empty-list polling gap closed after async sync click — the sidebar now updates without a manual refresh.
- FIX
Failed matches hidden from the user-facing list (still queryable internally for triage).
- NEW
- v1.0.0 · Open beta3 changes
- NEW
First public open beta of P4cely. Steam/Epic sign-in, replay sync, AI coach report, four-tab match detail (Overview, Coach Report, Metrics, Heatmap, Timeline).
- NEW
Pro-baselined comparisons across the RLCS roster — match-by-match tape, not just stats.
- POLISH
Migrated BullMQ off pay-per-command Redis to a self-hosted Fly Redis app — sustainable for indie scale.
- NEW
Want to be notified when something ships? Sign in once, and we'll send you a single line of email per release — never marketing.