TrendRadar
Engineering Teardown
A product research desk for Turkish solo builders. I moved collection and optional AI enrichment off the reader's request path, published a static snapshot, and kept commercial evidence separate from popularity signals.

01 / Stable identity across collection runs
Canonicalization removes URL fragments and tracking parameters, normalizes hostnames and sorts query parameters. SHA-256 identities retain 24 hex characters. A signal is keyed by source plus canonical URL; a product usually groups by its outbound hostname. Publishing platforms retain the full URL, so unrelated GitHub or Hacker News posts do not collapse into one product.
Repeat observations preserve first-seen time and update engagement history. Samples are at least 15 minutes apart; the latest 96 are retained. A source-content fingerprint invalidates cached analysis when content changes, without spending another model call merely because engagement increased.
Trade-off: hostname grouping can conflate independent products sharing a business domain. It is explicit identity resolution, with no claim of semantic deduplication.
02 / Popularity is separate from evidence
Momentum compares signals within the same source and a seven-day age neighborhood. Velocity needs observations at least one hour apart; otherwise an age-adjusted engagement fallback applies. GitHub stars and HN votes are not treated as interchangeable units.
A validated opportunity requires reviewed paying-customer and Turkey-demand evidence. Opportunity scoring additionally requires reviewed distribution and competitor evidence, plus complete editorial scores. Evidence expires after 30 days. Missing evidence stays unknown; SDKs and frameworks are separated from product candidates.
Trade-off: revenue observations are attributed evidence, not proof of profit or local demand. MVP time and cost remain hypotheses. Unknown costs do not pass explicit budget filters.
03 / Reserve the AI budget before calling
Only free-model identifiers are accepted, with zero-priced provider routing. Each attempt is saved to a UTC-day ledger before the network request. The application ceiling is 40 attempts/day; the scheduled workflow requests at most five/run. Failures consume reservations, and provider quotas can be lower.
Responses have a 45-second deadline, Zod validation and unsupported-claims checks. An enrichment failure preserves existing analysis or leaves a pending card. Failed analyses wait six hours before retry; authentication, payment and rate-limit responses stop that run's AI loop.
Trade-off: a local run lock coordinates one state directory. Actions cache restoration is not a distributed transaction; cache loss or independent collectors can create separate ledgers. Readers receive cached text, never API credentials.
04 / Static delivery, honest failure states
GitHub Actions schedules collection every six hours. Source calls run concurrently with per-source status; JSON writes use a temporary file and rename. After collection, Next.js exports the site, an artifact check scans for configured credentials/private files, and only free/out is uploaded to Cloudflare Pages.
All-source failure stops publication and leaves the previous deployment serving readers. Partial success retains older observations alongside new ones. The UI shows source failures and warns when the last successful collection is over 48 hours old.
Trade-off: scheduled time is not a freshness SLA. There is no request-time server or database in the public product; the legacy Prisma application remains separate. Pages deployment rollback supplies the recovery path.
05 / Browser-local notes and domain migration
Saved ideas, progress and notes live in localStorage. JSON export/import provides a portable backup; no account or cross-device sync is required. Storage errors are visible to the user.
The existing storage key stays compatible after the rename, but pages.dev and trendradar.shepardai.pro are different browser origins. Existing users export at the old address and import at the new one. DNS cannot transfer browser storage.
06 / What the checks establish
The rename passed a production static build, the credential/private-file export scan and five existing browser checks. These exercise mobile rendering, saved notes and progress, filters, plan downloads, unit economics, failed-snapshot recovery, builder constraints and revenue provenance.
Tests establish behavior on the tested snapshot. They do not establish market demand, customer traction, model accuracy or a load-test SLA. HTTPS and domain activation are separate release checks.