Multi-country Add Keyword picker + drop stale API token#1
Merged
Conversation
…rd modal Track one term across many App Store storefronts in a single click. The modal swaps the free-text 2-letter input for a searchable chip-based multi-select sourced from Apple's 175 official territories (Apple's "App Store Pricing and Availability" page is the source of truth). - new web/src/lib/countries.ts: complete storefront list + Intl.DisplayNames with Apple-preferred overrides for Türkiye, Republic of Korea, China mainland, both Congos, Eswatini, and Kosovo (XK is not in Intl.DisplayNames). - new CountryMultiCombobox.svelte: chip trigger with per-chip remove, search by name or ISO code, keyboard navigation, selected items pinned to the top of the popover. Esc is scoped to the popover so it no longer also closes the parent modal. - AddKeywordModal: countries[] persisted via localStorage so users don't reselect every time; defaults to ['us'] for first-time users and falls back to ['us'] on corrupt/invalid storage. Submit fans out to addKeyword() per country via Promise.allSettled, reports per-country failures with localized name + code, saves on any success. "Clear" button wipes selection.
The Vapor server stopped requiring bearer auth in Phase 5b (the server binds to 127.0.0.1 only — see Sources/App/routes.swift), but the dev tooling kept threading a `devtoken` through env vars and Authorization headers. Drop the dead config so the docs and the launcher match the actual auth surface. - Makefile: drop KEYWORDISTA_API_TOKEN default + the env-var prefix on `dev-backend`; update the help string. - keywordista launcher: drop the default/export block and the token suffix on the startup banner. - .env.example: drop the token line. - requests.http: drop @token, the two now-meaningless 401 cases (`### 1a` / `### 1b`), and every Authorization: Bearer line.
bootuz
added a commit
that referenced
this pull request
May 23, 2026
A picture beats four lines of architectural prose for 'what does this actually look like'. Sourced from a live local run with 30 tracked keywords spread across US/GB/DE/JP/IN/FR — shows ranks, top-result icon strips, difficulty + entry-barrier dots, and the country picker that landed in #1. Lives at docs/dashboard.png so we have a directory to drop more screenshots into later (charts page, history panel, etc.) without cluttering the repo root.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
localStorage(keywordista:lastCountries), with aClearbutton on the form and a defensive fallback to['us']on missing/corrupt/stale data.KEYWORDISTA_API_TOKENfrom Makefile / launcher /.env.example/requests.http. The server stopped requiring it in Phase 5b (routes.swift:8-12) — only the dev tooling was still passing it around.Why the picker, not a free-text input
A first-time user faced an empty datalist (the old
<input list>only suggested codes already tracked) and had to know ISO codes by heart. Backend validation only checks length, so typos likeusasilently created bad rows. The picker is now the de-facto allowlist.Naming corrections vs. common copies of the App Store country list
Cross-checked against Apple's official territories page. Notable diffs from older third-party copies and from a JSON list I was initially handed:
li≠ Liberia.liis Liechtenstein (not an App Store storefront). Liberia islr.cd(Democratic Republic) andcg(Republic).Intl.DisplayNamesdiverges.xk), Liberia, Libya, Maldives, Montenegro, Morocco, Myanmar, Nauru, Rwanda, Serbia, Tonga, Vanuatu, Zambia.Test plan
npm run check— 0 errors, 0 warningsverify-multi-…, submitted 5 countries → all 5 rows persisted viaPOST /api/v1/keywords; confirmed viaGET /api/v1/dashboard.constraintUniqueFailedfor the 3 dupes; DE landed; modal stayed open with the 3 failures listed per country.['us'].bash -n keywordistapasses;grep -r KEYWORDISTA_API_TOKENreturns 0 matches.Follow-ups (out of scope)
409 Conflictfor duplicate(term, country)instead of surfacing the SQLite constraint string. The modal's failure list would then say "already tracked" instead ofAPI 500: …constraintUniqueFailed….POST /api/v1/keywords/batch) would collapse N round-trips into one if heavy multi-country use becomes common.