8 Commits

Author SHA1 Message Date
Ben Senescu
0bfdc56c45
feat: add tabs for keyword research (#185) 2026-05-12 19:30:19 -04:00
Ben Senescu
0c356fac19 fix: change google sheets export copy 2026-05-06 15:43:26 -04:00
Ben Senescu
b9ad31704f
Clarify keyword intent badges (#157) 2026-05-06 12:30:33 -04:00
Ben Senescu
9e5afc9d48
feat: Add shared table component (#154)
* fix rank tracking unranked filters

* improve modal dismissal and range selection

* refactor: create shared table component
2026-05-06 11:23:07 -04:00
Ben Senescu
a42fe4d350
keywords: consolidate export buttons into dropdown (#147) 2026-05-04 14:04:44 -04:00
Ben Senescu
ab50e59ff8
feat: add 'Export to Google Sheets' to every data table (#144) 2026-05-03 15:25:25 -04:00
Ben Senescu
b3d543d206 feat: add top-level persistent filters for keyword research (#93)
* feat: add top-level persistent filters for keyword research

Add a collapsible filter bar below the search bar so users can set
default filters (volume, CPC, difficulty, include/exclude terms) that
persist across searches and sessions via localStorage.

* simplify: remove top-level filter UI, keep only localStorage persistence

Revert the search bar to its original state. The existing in-table
filters already provide good UX — all we needed was persistence.
Auto-expand the filter panel when persisted filters are active on load.

* feat: show filtered keyword count as "Showing X of Y keywords"

When filters are active, display "Showing 14 of 150 keywords" instead
of just "14 keywords". When no filters are active, show "Showing X
keywords". Applied to both desktop and mobile views.

* style: fix prettier formatting
2026-04-08 14:09:02 -04:00
Ben Senescu
75f9868500
fix: Refactor folder structure & services (#17)
* refactor: simplify keyword source selection flow

* fix: improve stacked keyword page layout

* fix: keep SERP tied to searched keyword

Stop silently falling back SERP lookups to related keywords and show a keyword-specific empty message so missing coverage is explicit to users.

* refactor: extract keyword controller and switch SERP to live

Move keyword research orchestration out of the route, call DataForSEO organic live SERP, and harden response normalization with runtime validation for safer typed handling.

* refactor: split keyword research page state into focused hooks

* fix: aggregate auto keyword fallback and reuse cached results

* scope keyword metrics to projectId

* refactor: modularize SEO routes and harden parsing for CI checks

* refactor: adopt zod json codecs at parse boundaries

* refactor: adopt papaparse, tldts, and zod error enums

* refactor: reorganize client and server feature layout

Group keyword UI/controller files and server repositories/services by feature while keeping serverFunctions as the stable API surface. This improves navigation and maintainability without changing runtime behavior.

* refactor: move PSI business logic into service layer

Keep serverFunctions/psi as thin transport handlers by delegating orchestration, export shaping, and source resolution to PsiAuditService. This aligns PSI with the existing service-first backend pattern without changing endpoint behavior.

* refactor: enforce 350/120 size limits across modules

* move self host

* fix: show dynamic range for search trends

Replace the static 'Past 12 months' subtitle with a computed range from the actual plotted trend points so the UI reflects data lag correctly.

* fix: bind audit workflow writes to workflow instance

* chore: make ci checks pass
2026-03-11 23:01:52 -04:00