ENGINEERING CASE STUDY / OCTOBER 2026

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.

TrendRadar research desk showing product filters and source-backed cards
Actual production-build preview, October 19, 2026. Next.js · TypeScript · Cloudflare Pages.
01 / CollectHN, GitHub and TrustMRR signals
02 / IdentifyCanonical URLs + source history
03 / EnrichEvidence gates + cached AI
04 / PublishStatic JSON + browser notebook

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.

Code: engine.ts

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.

Code: evidence gates · Builder constraints

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.

Code: AI reservation · Failure handling

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.

Code: refresh workflow · Artifact check

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.

Code: browser notebook

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.

Code: browser checks · Logic and regression tests