133 Commits

Author SHA1 Message Date
Ben Senescu
01ecf11415
Make default project creation race-safe (#206) 2026-05-20 17:34:57 -04:00
Ben Senescu
2484f93ce6
Refactor pages to improve performance and consistency (#205) 2026-05-20 17:23:09 -04:00
Ben Senescu
74ba0c4fc8
Prevent duplicate Default projects and add D1 cleanup tooling (#203) 2026-05-19 20:53:13 -04:00
Ben Senescu
efef3894cb
Add shared search tabs to domain overview and backlinks (#192)
* Add shared search tabs to domain and backlinks

* refactor: share search tab framework with keywords

* fix: normalize backlinks tab validation target
2026-05-18 14:51:43 -04:00
Ben Senescu
7fa4d5cade
Simplify Loops signup contact sync (#202) 2026-05-18 14:24:06 -04:00
Ben Senescu
7a0ab0de2c
Add more mcp tool metadara + ChatGPT domain verification route (#197) 2026-05-14 13:02:08 -04:00
Ben Senescu
0ce787889a
Redirect signups to the homepage (#196) 2026-05-14 08:17:44 -04:00
Ben Senescu
f926a0f78c
add users to loops post google sign in (#194) 2026-05-13 21:44:34 -04:00
Ben Senescu
701ace3dff
Add Google sign in and two-step auth flow (#193) 2026-05-13 20:55:20 -04:00
Ben Senescu
a98407176b
Remove unused Better Auth OAuth and JWKS tables (#188) 2026-05-13 15:22:10 -04:00
Ben Senescu
49a2d7f732
Set MCP access token TTL to 24 hours (#191) 2026-05-13 15:01:32 -04:00
Ben Senescu
fa20de2126
Send Loops contacts after email verification (#189) 2026-05-13 13:21:57 -04:00
Ben Senescu
8773662b16
feat: unify multi select behavior across the app 2026-05-12 20:38:31 -04:00
Ben Senescu
0bfdc56c45
feat: add tabs for keyword research (#185) 2026-05-12 19:30:19 -04:00
Ben Senescu
ae2031bfad
Harden domain and backlinks validation before external calls (#183)
* Validate backlinks targets before calling DataForSEO

* Validate backlinks targets before provider calls
2026-05-12 19:15:51 -04:00
Ben Senescu
570fe2aa62
Add keyword tags, server-side saved filtering, and filtered exports (#179) 2026-05-12 00:02:43 -04:00
Ben Senescu
740c899764
Create Loops profiles on user signup (#180) 2026-05-11 21:24:23 -04:00
Ben Senescu
b9b85a6d48
Support Cloudflare Access and local no-auth MCP modes (#166) 2026-05-10 17:31:30 -04:00
Ben Senescu
b633da8844
Mark Claude Desktop connector approval optional (#175) 2026-05-10 16:36:53 -04:00
Ben Senescu
0dd818e114
Replace better-auth with Cloudflare for oauth (#174) 2026-05-08 22:19:55 -04:00
Ben Senescu
db10ffa250
Fix Claude Desktop MCP OAuth registration and resume flows (#173) 2026-05-08 18:07:05 -04:00
Ben Senescu
f58efea164
Improve MCP structured result visibility (#167) 2026-05-08 16:17:28 -04:00
Ben Senescu
2234cb54fc
Show project nav on app pages (#171) 2026-05-08 16:00:04 -04:00
Ben Senescu
103b6fe91c
fix: add additional well known for claude.ai + Claude Desktop (#170)
* Simplify MCP discovery metadata and lazy auth flow

* Fix ci check for MCP discovery branch
2026-05-08 15:59:43 -04:00
Ben Senescu
36b60f240f
Merge pull request #165 from bensenescu/codex/update-ai-tab
Update the AI tab for MCP setup and usage guidance
2026-05-08 15:30:18 -04:00
Ben Senescu
38fbac159f ci: run prettier on AI page 2026-05-08 15:27:12 -04:00
Ben Senescu
239a5a9e2b Add Claude and Codex desktop setup guides with brand logos
- Drop redundant codex mcp login step from the CLI flow
- Add Claude Desktop and Codex Desktop accordion entries
- Lead each setup-guide row with its product logo
2026-05-08 15:20:42 -04:00
Ben Senescu
93ee343c63 Polish AI & MCP page and move out of project scope
- Move /p/$projectId/ai to /ai so the page can be linked directly
- Lead with a copyable MCP server URL and trim the surrounding copy
- Make Claude Code and Codex setup guides collapsible accordions
- Add an Available tools section grouped into Keywords and Domain
2026-05-08 14:56:26 -04:00
Ben Senescu
02fcfb9834 Update AI page for MCP setup guidance 2026-05-08 13:40:51 -04:00
Ben Senescu
4cd02e36f4 Advertise offline_access in MCP scope metadata 2026-05-08 13:40:26 -04:00
Ben Senescu
57790b930f
feat: add OpenSEO MCP tools (#161) 2026-05-08 00:34:29 -04:00
Ben Senescu
0ff7bc96b2
Add stateless MCP server (#162) 2026-05-07 23:38:00 -04:00
Ben Senescu
6231424e88
feat: add personal access tokens (#159)
* feat: add personal access tokens

* feat: replace MCP tokens with OAuth foundation

* fix: keep OAuth constants private in auth foundation

* fix: clean up mcp oauth branch scope

* fix: expose oauth metadata endpoints

* fix: trim mcp oauth config to non-default options

Drop OIDC scopes, the org-id JWT claim, and the openid-configuration
metadata endpoint since the MCP integration is OAuth-only and the org
gets resolved server-side. Also remove options that just duplicated
better-auth defaults.

* fix: drop redundant oauth metadata helpers

Remove `session.storeSessionInDatabase: true` since better-auth only
enforces it when secondaryStorage is configured. Inline the
`getHostedBaseUrlForOAuthMetadata` alias and skip the async
`getOAuthServerConfig()` call in the protected-resource metadata handler
— the issuer is just `baseURL` without a custom jwt.issuer override.

* docs: explain cache headers on mcp metadata response

* Use escaped file routes for OAuth metadata

* save
2026-05-06 22:41:02 -04:00
Ben Senescu
fb265e3a3a ci: run prettier 2026-05-06 15:45:09 -04:00
Ben Senescu
0c356fac19 fix: change google sheets export copy 2026-05-06 15:43:26 -04:00
Ben Senescu
ca260f544b
feat: improve mobile UX (#155) 2026-05-06 12:52:05 -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
7f892ca433
Merge pull request #19 from every-app/split-modal-dismissal
fix: exit closes modal + accessible labels
2026-05-06 10:46:45 -04:00
Ben Senescu
6f50850b5a
fix rank tracking unranked filters (#18)
Co-authored-by: Granata005 <granata005@gmail.com>
2026-05-06 10:46:33 -04:00
Ben Senescu
6b7d0464f7
feat: add shift range table selection (#20)
* add shift range table selection

* format keyword suggestion selection

* credit original draft author

Co-authored-by: Granata005 <granata005@gmail.com>

---------

Co-authored-by: Granata005 <granata005@gmail.com>
2026-05-06 10:46:21 -04:00
Ben Senescu
89091ca9d5
refactor: simplify rank tracking backend (#125) 2026-05-05 22:18:35 -04:00
Ben Senescu
db1a1d723f
fix: use Tanstack Query for Keyword Research (#150)
* keywords: use query cache for research requests

* keywords: simplify research request dedupe
2026-05-05 14:11:28 -04:00
Ben Senescu
def9390cea
feat: Implement server-side pagination and filtering for domain keywords (#143) 2026-05-04 15:26:36 -04:00
Ben Senescu
a42fe4d350
keywords: consolidate export buttons into dropdown (#147) 2026-05-04 14:04:44 -04:00
Ben Senescu
c1a9c1f57d
Replace mutation-based search with URL-driven state management (#145)
* fix: preserve cmd+click on tracked domain rows

Tracked-domain rows used <div role="button" onClick={navigate(...)}>,
which prevented standard browser open-in-new-tab behavior (cmd+click,
middle-click, right-click → open). Use TanStack Router's <Link> as a
stretched overlay so the row is a real <a href> while the archive
button stays interactive.

* fix: use <Link> for tab toggles and history navigation

Replace onClick={() => navigate(...)} / setSearchParams patterns with
TanStack Router's <Link> across surfaces that change the URL on click.
<Link> renders a real <a href> and only intercepts plain left-clicks,
so cmd/ctrl+click, middle-click, and right-click → open-in-new-tab
all work natively.

- Audit: history "View" button + Pages/Performance tab toggles.
- Domain overview: Top Keywords / Top Pages tab toggles. The keyword-
  only sort fallback now happens in the Link's search updater.
- Backlinks: history items, Backlinks/Domains/Pages tab toggles, and
  "Recent searches" back-link. Removes now-unused
  navigateToBacklinksHistory / navigateToBacklinksTab helpers.

Keyword research and domain history items, and AI search histories,
are not converted: those pages don't trigger their data fetch from
URL params alone, so a plain link target wouldn't reproduce the
current click behavior without a deeper refactor.

* refactor: unify search-page state around URL-driven fetching

Drive Keyword Research, Brand Lookup, and Prompt Explorer from URL
search params so a search is reproducible from a link alone. With
that, all three history surfaces become <Link>s and cmd+click /
right-click → "open in new tab" work natively.

- Shared SearchHistorySection now takes a renderItemLink slot so
  callers wrap history items in a <Link> with the right destination.
- Prompt Explorer: added URL search params (q, models, web, cc, hb)
  via promptExplorerSearchSchema; switched the explore mutation to
  useQuery keyed on the URL params; addSearch now fires from a
  success effect; "Recent searches" back-button is a <Link>.
- Brand Lookup: history items + "Recent searches" back-button are
  <Link>s; local form state stays in sync with URL via an effect.
- Keyword Research: form submit still navigates+kicks off a search
  for the same-URL re-submit case, but the controller also runs an
  URL-driven search trigger (with a dedup ref against the form path).
  Direct URLs, cmd+click on history, and browser back/forward all
  reproduce the same fetch. "Recent searches" back-button and the
  history items are <Link>s; the bespoke resetView path is gone.

Also drops now-unused clearKeywordSearchParams,
navigateToBacklinksHistory/Tab helpers' last consumers, and the
PromptExplorerPage's onQueryChange/onSelectHistoryItem callbacks.

* format

* refactor: replace useMutation with manual state in keyword research

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-04 13:00:37 -04:00
Ben Senescu
11252f8088
fix: improve spreadsheet exports (#146) 2026-05-04 12:49:42 -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
2130dccc81 hosted: add posthog opt out + session replay 2026-04-28 20:56:06 -04:00
Ben Senescu
17298da7ee
fix: capture DataForSEO errors with context (#138) 2026-04-24 00:16:20 -04:00