About this project
What GrowthOS is, which operating problem it models, how the modules connect, and where the model stops.
Why this project exists
Running a direct-to-consumer store means answering the same question every week with evidence from tools that do not talk to each other: search console says one thing, the analytics suite another, the ad platform a third, and the product catalogue sits somewhere else entirely. Each tool is internally consistent and none of them agree, so the weekly decision usually gets made on whichever number was easiest to find.
GrowthOS is an attempt at the opposite. It is a decision workbench for a fictional outdoor brand, NorthTrail Outdoor (North America, USD), built so that every number on every screen comes from one definition and one calculation, and so that every recommendation can be traced back to the rule and the evidence that produced it.
It was built as a portfolio piece: the interesting part is not that it renders charts, but that it is opinionated about metric definitions, honest about what a heuristic can and cannot know, and willing to show a finding it cannot explain rather than round it away.
The problem it is modelled on
Four failure modes that this project is deliberately built against.
- The same word means two things
- “Conversion rate” can be per session, per user or per visit; “revenue” can include tax and shipping or not. Two dashboards disagree and nobody can say which is wrong. Here every ratio is defined once, in one module, and every screen imports it.
- A score with no argument behind it
- A tool says a page scores 62 and offers no way to disagree. Every score here decomposes into named checks with a pass, a warning or a failure, the evidence that decided it, and a rule version.
- Findings that go nowhere
- Audits produce lists; lists produce nothing. Every finding in this project becomes a task with a priority, an estimate and a link back to the page it is about — and a completion that survives a reload.
- Correlation dressed as cause
- The funnel can say where sessions are lost. It cannot say why, and this project never pretends otherwise: its advice is phrased as a hypothesis with a suggested way to test it.
How the modules fit together
Each module answers one question. Recommendations is where they converge.
| Module | Reports on | The question it answers |
|---|---|---|
| Dashboard | Both | Is the business healthy this window, and where should I look first? |
| Products | Both | Which SKUs exist, and is each one's on-page metadata fit to publish? |
| SEO Audit | Storefront | Is this page technically fit for classic search? |
| GEO Audit | Storefront | Can a generative engine extract a trustworthy answer from this page? |
| Content | Storefront | What should we write next, and why that rather than something else? |
| Analytics | Storefront | Where does traffic come from, and what does each channel cost and return? |
| Funnel | Storefront | Where in the journey are sessions lost? |
| Amazon | Amazon | Are our Amazon listings fit to sell, and which one is worst? |
| Amazon Ads | Amazon | Which search terms are worth bidding on, and which are burning money? |
| Recommendations | Both | Given everything above, what should I do on Monday morning? |
The chain, end to end
On the storefront: SEO, GEO and Content decide what exists and how findable it is → Analytics says which channels brought sessions and what they cost → the Funnel says where those sessions were lost. On Amazon, a separate chain: listing quality decides whether an ASIN is fit to sell at all. Both ends feed Recommendations, which turns everything into one ordered list of things to do.
The direction matters. Recommendations recalculates nothing: it calls each engine and merges the output. If the SEO audit changes its mind about a page, the task list changes with it on the next load. That is why only the “done” decision is stored — the findings themselves are always regenerated, so they cannot drift away from what the engines currently say.
Guided walkthrough
About 7 minutes end to end. The same path is in the README.
| Step | What to show |
|---|---|
| Dashboard | Open with the headline numbers and the metric definitions table. Point out that every ratio has one definition, shared by every module. |
| Products → one SKU | Edit a title or meta description. Save, reload, show the edit survived. Note the audit for that page is now marked stale. |
| SEO Audit → re-run | Re-run the audit for that page. Walk through one failing check and its evidence — not a score, a reason. |
| GEO Audit | Show the readiness bands and say plainly that this measures page structure, not any real AI ranking. |
| Analytics → Funnel | Channel table with CAC and ROAS, then the funnel. Show the largest drop-off and why it is not automatically the biggest problem. |
| Amazon | Run the listing audit. Open the suppressed ASIN and show why its non-compliant main image outranks every copy improvement on it. Say plainly that Amazon numbers are never added to the storefront’s. |
| Amazon Ads | Show the search term table: what a shopper typed versus what we bid on are two columns, not one. Then a harvest candidate and a negation candidate, and say that both are suggestions the project will never act on itself. |
| Recommendations | The whole project lands here: one prioritised list with evidence and a deep link back to each finding. Mark one done, reload, show it stuck. |
What this model cannot do
Stated here rather than buried, because a portfolio piece that overclaims is worse than one that does less.
- The data is generated, and says so
- Every session, order and unit of ad spend comes from a seeded generator with a fixed end date. Reloading gives the same numbers. Nothing here is a real business result, and no claim in this project should be read as one.
- The scores are this project’s rules, not anyone’s algorithm
- SEO (seo-1.0.0) and GEO (geo-1.0.0) are rule sets written for this project: each check, weight and rounding step is in the repository and can be argued with. They are not Google’s ranking algorithm, and a high score is not a ranking promise. The Amazon listing rules (amazon-listing-1.0.0) work the same way and are not Amazon’s published requirements — real category rules vary by browse node.
- GEO does not measure AI behaviour
- No AI API is called anywhere in this project. The GEO audit checks whether a page is structured so an answer could be extracted from it — direct answers, facts, sources, schema. It cannot observe whether any assistant actually cites the page, and it never claims to.
- Attribution is last-touch and single-channel
- Each session carries exactly one channel. Real multi-touch attribution would distribute the same revenue differently, so channel ROAS here is the simplest possible reading, not the fairest one.
- Revenue is narrow, and refunds are not modelled
- Revenue is paid item value minus discounts. Tax, shipping and refunds are excluded, and the MVP has no refund concept at all, so anything downstream of revenue is optimistic by an unmodelled amount.
- Impact and effort are estimates
- Recommendation priorities (recommendations-1.0.0) come from per-rule 1–5 estimates with written reasons, nudged one step up or down by how busy the page is relative to the rest of the catalogue. One step, not a multiplier: traffic decides which of two comparable findings to do first, it does not decide whether a finding is serious. They order the work; they are not forecasts, and no figure in this project should be quoted as expected revenue.
- Organic acquisition looks free because its cost is not modelled
- Organic Search shows a CAC of $0.00 because no spend is attributed to it. That is arithmetic, not a finding — content, SEO and brand labour are real costs this demo does not carry.
- The two channels are never added together
- The storefront and Amazon share this catalogue, but an Amazon session and a storefront session are counted differently and mean different things. Nothing in this project adds them, and ACOS is never silently converted into ROAS for a side-by-side comparison — the attribution windows do not match, and ACOS covers only advertising-attributed sales. Conversion rate is the sharpest case: on Amazon it is orders ÷ clicks, on the storefront it is purchasing sessions ÷ sessions. Two honest numbers side by side beat one misleading total.
- The target ACOS is a choice, not a benchmark
- A brand buying market share runs a deliberately high ACOS; one funding itself from cashflow runs a low one. This project picks a figure so the rules have something to compare against and says so on screen. Harvest and negation candidates are suggestions to test — nothing here changes a bid, a budget or a negative keyword list.
- An ignored finding is set aside, not deleted
- Ignoring a finding needs a reason from a fixed list, because an ignore nobody can explain later has to be raised again — which defeats the point. Ignored findings stay in the list, counted and filterable, and the evidence at the time of the decision is kept: if that evidence changes, the ignore is flagged as worth another look. Nothing re-checks it otherwise, and the page says so.
- Accessibility is checked, not certified
- Every route is scanned with axe-core against WCAG 2.1 A and AA on three browser engines, and the accessibility tree is asserted directly: one main landmark and one h1 per page, named navigation regions, captioned tables, charts that are never the only route to a number, and keyboard operation throughout. What has not happened is a person using this with VoiceOver or NVDA. Automated rules catch roughly a third of real barriers, so this project claims those specific properties hold — not that the experience is good.
- It is a workbench, not a store
- There is no storefront, no checkout, no login, no multi-tenancy and no background job. Nothing connects to Shopify, Amazon, GA4 or an ad platform — in particular this project never calls SP-API, which would need a real seller account — and no page is ever crawled.
Data window and determinism
All modules read the same fixed window: 2026-06-03 — 2026-08-31 — 90 days, inclusive of both ends, in UTC. The end date is a constant, not today, so the demo never pretends a seeded dataset is live.
Nothing is randomised at render time. The generator is seeded, so the same session counts, orders and scores appear on every machine and in every test run. Money is held as integer cents throughout and formatted only for display.
Demo data
Everything you change in this workbench is stored in this browser only. Nothing is sent anywhere.
Product SEO edits, content ideas, audit results and completed recommendations are kept under a namespaced key in this browser's local storage. Traffic, orders and spend are not stored — they are generated from a fixed seed and are identical on every load. Resetting clears only this project's key and returns the catalogue and content plan to their original state.
Checking what is stored…