Repository navigation
feat(analytics): analytics page, and dashboard money from the API - #8
Merged
Merged
Conversation
The dashboard summed revenue and average order value client-side from the last 100 orders. Its own comment admitted it. The headline numbers therefore stopped being the shop's numbers at order 101, and there was no trend, no product view and no sight of where orders stop converting. Adds an Analytics page — revenue over time, orders and units, the order funnel, per-SKU performance and active-but-unsold stock — reading /v1/admin/analytics/*, which computes everything in SQL over the whole order history. The dashboard's money tiles now come from the same summary endpoint over a 30-day window. Its work queues still read the orders list, which is the right source for them: "what needs doing now" is exactly the newest orders. Money is shown per currency and never summed across them. The API returns a list keyed by currency because a cross-currency total is meaningless; adding them up here would put the bug straight back. Charts use Chart.js directly behind a thin standalone wrapper rather than an Angular wrapper library. The app is zoneless and tracks the newest Angular, and a wrapper's peer range would gate every future Angular upgrade — ng2-charts would also pull in @angular/cdk, which this app does not otherwise need. Only the controllers actually drawn are registered, so the rest of Chart.js is tree-shaken, and the whole library sits in a lazy chunk: nothing but /analytics pays for it. isoDate and rangeEndingToday live in core/date-range rather than beside the page, because the dashboard needs them and importing from a page component would drag Chart.js into a screen that draws no charts. Percentage change from a zero baseline renders as "no prior data", not 0% and not an arrow. It is undefined, and a direction would assert what the data cannot support. Closes #7 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YY1ekLLeFLkAU2kvdQ8Ey4
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.
Closes #7 · consumes OpenTaberna/fastapi#44
The dashboard summed revenue and AOV client-side from the last 100 orders — its own comment
said so. Those figures now come from
/v1/admin/analytics/*, computed in SQL over the wholeorder history, and a new Analytics page adds the trend, product and funnel views that
did not exist.
What's here
Analytics page — net revenue over time, orders and units, the order funnel with drop-off
per step, per-SKU performance with return rate, and active-but-unsold stock. Period selector
of 7 / 30 / 90 days / 12 months, switching to weekly buckets past 120 days because daily
buckets over a year are unreadable.
Dashboard — money tiles read the summary endpoint over 30 days. Work queues still read
the orders list, which is correct for them: "what needs doing now" is the newest orders.
Decisions worth reviewing
No Angular chart wrapper. Chart.js is used directly behind a thin standalone component.
The app is zoneless and on Angular 22, and a wrapper's peer range gates every future Angular
upgrade —
ng2-charts@10would also pull in@angular/cdk, which this app does nototherwise use. Only the controllers actually drawn are registered, so the rest of Chart.js
tree-shakes away.
Chart.js is not in the initial bundle. It sits in a lazy chunk (187 kB raw / 57 kB
transfer) loaded only by
/analytics. Initial total is unchanged at 345.94 kB / 93.41 kB.While wiring this I caught a real problem: the dashboard imported
rangeEndingTodayfromanalytics.page.ts, which drags the analytics page — and through it Chart.js — into thedependency graph of a screen that draws no charts. The helpers moved to
core/date-range.grep -rln "from 'chart.js'"now returns only the two chart components and the analyticspage.
Currencies are never summed. The API returns a list keyed by currency; the page renders
one block each and charts the highest-earning one, saying so when there is more than one.
No baseline renders as "no prior data". Change from zero is undefined — not 0%, and not
an arrow.
Verification
The dashboard specs catch the actual regression. Restoring the client-side sum — with an
orders stub carrying a 999999 order that would dominate any such sum:
The analytics page spec is a render test with teeth: it compiles the template, runs every
computed and builds real Chart.js configurations, so a mistyped field fails in CI rather
than on an operator's screen.
nav.model.spec.tswas updated from six navigation entries to seven — an intentional changeto an existing assertion, not a loosened one.
Verified against the live dev stack: all four endpoints answer, and
403without a token.