Repository navigation
Feat/dashboard detail and combine - #2
Merged
Merged
Conversation
Walking one billing period at a time is O(gap): a daily subscription running since 2015 is ~4000 steps from today, and callers ask for a whole month of payments, re-walking from the period start each time. Rendering the dashboard for 40 such subscriptions took 2.5s. Skip most of the cadence in one jump, then step the remainder. Day- and week-based cadences are plain timedeltas and always jump; month-family anchors on day 29-31 keep stepping, because month-end clamping makes that sequence non-arithmetic (Jan 31 -> Feb 28 -> Mar 28) and a single jump would land elsewhere. The month jump deliberately under-counts (31 days/month) so it can never overshoot the reference date. Same dashboard: 0.038s. Parametrised tests pin the jump to the step-by-step result across cadences, leap days and month-end anchors. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A price change is recorded by closing the running period and opening a new one the next day, but every period restarted the billing cycle on its own start date — so changing a price silently moved the billing day, and in the month of the change the subscription was billed twice (once by each period). Anchor each period at the start of the contiguous run it belongs to: back-to- back periods are one continuous subscription and keep their original day, while a gap (cancelled, then resubscribed) does start a new cycle on the new date. The period covering a billing date still supplies its price. Fixes both the doubled charge and the wrong billed/still-due split on the dashboard, and the same dates on the detail page's next-payment list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Charts were tall and mute: a 640x220 viewBox scaled to ~420px on a wide screen, and a value was only readable from the SVG title attribute. - Every mark (bar, point, breakdown row) carries data-tip-* and sits in a <g> with a transparent full-height hit area, so the whole column is hoverable. CHART_JS renders a floating card on hover and pins it on click or tap, which is the only way to read a value on a touch screen. Marks are focusable and labelled, so the keyboard reaches them too. - Default viewBox height 220 -> 150 (the height is really an aspect ratio), with tighter padding and one fewer gridline: ~30% shorter at the same width. - bar/line charts take tip_labels and notes, so a tooltip can say "January 2026 / EUR 141.56 / 4 subscriptions" while the axis stays at "Jan". - tab_nav() and disclosure(): shadcn-styled tabs (plain links) and a native <details> show/hide, both JS-free. - plural() moves into fmt so the routes stop redefining it. - badge_cls gained the success/warning kinds the dashboard was already asking for; they silently fell through to the solid default variant. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The dashboard answered "what did this year cost" but not "what do I owe now". Add a card that walks real billing dates rather than prorated cost, so it shows money as it lands on the card: this month's total, last month's, the delta, the payments still to come this month, and a toggle revealing those already billed. Reorder around it — "Right now" (month card + run-rate) now leads the page and the year selector sits below with everything it governs, including the two year-scoped tiles that used to sit in the run-rate row. The monthly chart gained tooltips: full month name, exact amount, and how many subscriptions were active that month. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seven cards stacked on one page meant scrolling past the price history to reach the audit log. Give it a summary header — name, status, category, current price, next payment, actions — over four tabs: Overview (details, cost per period, next payments), Spend (monthly chart and lifetime figures), Periods (price history and the add form), History (audit trail). Tabs are plain ?tab= links, so they deep-link, survive a reload, and let the period POSTs redirect back to the tab they came from. The History tab and the add-period form only render for roles that may use them, and an unknown or no-longer-permitted tab falls back to Overview. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ongs to Importing newer prices for a subscription whose current period is still open-ended creates a second subscription with the same name, and there was no way to fix that short of retyping the periods by hand. combine_subscriptions() folds one into the other: periods are re-pointed rather than copied, so who added each price and when survives, and an open-ended period is closed the day before the next one starts — add_period's price-change rule, applied across the merged timeline so it works whichever side is open. Genuine overlaps between bounded periods are refused and nothing is written; plan_combine() decides that before any change is made. Import no longer leaves the duplicate unexplained: it still creates the row (guessing would be worse) but the result page names the clash and offers Combine, spelling out what will move and which period gets closed. The detail page offers the same for any same-named leftovers. Combining needs subscriptions.edit + subscriptions.delete, is refused across teams (a super admin in cross-team view can see both rows), and audits both sides. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.