A trade-data product grows through search. Every HS-code page, every trade-directory entry, every analytics view needs to be crawlable — which rules out the client-rendered dashboard pattern the rest of the fleet uses.
What I did about it
Inverted the usual split: 24 of 31 pages are server components, the best server-rendering ratio in the portfolio.
Each route is a server component owning its metadata and static shell, with a separate client component handling interactivity only where it's genuinely needed.
A shared Flask backend serves both this and the cut-down directory sibling, with per-site session isolation via an X-Client header so the two products share accounts without sharing state.
What I rejected, and why
Server rendering costs latency on every request that a cached SPA shell would avoid. For a product whose growth depends on trade-data pages appearing in search, that trade is not close.
The longest-running project here has almost no audit logging, so "who changed this customer's plan and when" is unanswerable. I would add an append-only audit table early rather than reconstructing intent from application logs.