Open-source readiness: license, CI, a demo that works, and a README that sells it - #1
Merged
Merged
Conversation
- support Google Maps locally with an OSM fallback - open the latest search by default - select map prospects on click instead of hover - document local-only map and address settings
The repository had 28 stars and 5 forks with no license at all, so nobody downstream had any legal right to use or redistribute it. AGPL-3.0 keeps it open while requiring anyone running a modified version as a network service to publish their changes — relevant for a tool that generates commercial leads and would be trivial to resell as a closed SaaS. Adds a CI workflow running lint, typecheck, tests, db:check and build on every pull request. It runs with MOCK_EXTERNAL=1 so it reads fixtures/ and never spends Google Places quota; places:smoke stays out for that reason. Issue templates include one specific to this project — proposing a scoring signal — since that is the natural way to contribute here: everyone who has sold a redesign knows a tell the analyzer does not check yet. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The demo dataset was geocoded to [0, 0] — Null Island, roughly 600 km off the coast of Ghana. OpenStreetMap has nothing to render there, so the mock mode that every new user meets first (and that both README screenshots showed) displayed plumbers and hair salons floating on a blank grey square. It read as a broken product. Coordinates now point at central Tours (47.3879 / 0.689, place Jean Jaurès) and street names are real, so the tiles show an actual city. Every business keeps its exact offset from the centre, so the demo geometry is unchanged: a 1 km radius still retains 10 prospects and excludes 2 (one out of range, one permanently closed), with the same scores. Business names, phone numbers, SIREN/SIRET, officers and ratings stay fictional — only the geography is real. fixtures/README.md says so explicitly. The postcode moves from 00000 to 37000, which renames files: gouv fixtures are resolved as <slug>-<postcode>.json and places_search as <sector>-<citySlug>.json, so both sets had to move with it. Note for future edits: the restaurant-ancien.fr fixtures are latin-1 on purpose (they exercise charset decoding). They must be read and written as latin1, not utf8, or every accent becomes U+FFFD. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous two screenshots shared the same frozen left half — a blank grey map, because the fixtures sat on Null Island. Half of each image was dead space, and the second one added almost nothing to the first. New set, all captured on the retargeted Tours fixtures with the default OpenStreetMap layer (what someone without a Google Maps key actually sees, so the images do not oversell the default experience): - demo.gif — the whole path in 13s: form, sweep, ranked list, prospect panel, diagnostic. 928 KB. - 01-workspace.png — the hero, with a map that has streets on it. - 02-diagnostic.png — cropped tight on the panel rather than full width, so it stops duplicating the hero. - social-preview.png — 1280x640 for the GitHub social card (upload is manual; the API does not expose that field). Also drops the five untouched create-next-app SVGs, and ignores the editor's local .nimbalyst/ scratch directory. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The old README was technically accurate but sold the project badly: no badges, no demo, and the Markdown brief — the artefact the whole tool exists to produce — appeared nowhere. It also never said the project is France-only, so a forker discovered the BAN dependency after npm install rather than before. Changes that matter: - The France-focused constraint is now a callout near the top, not a surprise. - A real generated brief is included in full, in a collapsed block. Text rather than a screenshot, so it is copyable and searchable. - Costs are stated concretely. Prospect details bill as Place Details Enterprise ($20/1000), not Pro, because the field mask requests rating, userRatingCount and regularOpeningHours; search stays on Text Search Pro ($32/1000). A 100-prospect sweep is around $2.50 and the monthly free allowance covers roughly 1000 prospects. Rates checked 2026-08-07 against Google's published pricing and dated in the text, since they change. - Opt-out handling is promoted from the eighth bullet of a list to its own Ethics section — it is a design commitment, not a feature detail. - Adds a roadmap and, more usefully, explicit non-goals: no SaaS, no LLM, no CRM, no automated outreach. Now that the project has visibility, this is what stops out-of-scope pull requests before they are written. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The v4 actions target Node 20, which GitHub runners now force onto Node 24 and flag as deprecated on every run. Clears the annotation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Four commits, each independently reviewable.
Why now
28 stars and 5 forks, and the repository had no license — downstream had no legal right to use any of it. While fixing that, two more problems surfaced that were doing real damage to first impressions.
What is in here
1.
feat:license, CI, contribution guidesAGPL-3.0 (usage stays free; running a modified version as a network service requires publishing changes — relevant for a lead-generation tool). CI runs lint, typecheck, tests,
db:checkand build on every PR, withMOCK_EXTERNAL=1so it never spends Google quota. Issue templates include one specific to this project: proposing a scoring signal.2.
fix:demo fixtures were on Null IslandThe mock dataset was geocoded to
[0, 0]— open ocean, ~600 km off Ghana. OpenStreetMap renders nothing there, which is why the demo (and both README screenshots) showed businesses floating on a blank grey square. Now centred on Tours, with every offset preserved: same 10 retained / 2 excluded, same scores. Business names, phones, SIRETs and ratings remain fictional; only the geography is real.3.
docs:new visualsA 13-second GIF of the full path, a hero with an actual map, a panel shot cropped tight so it stops duplicating the hero, and a social card. Captured on the default OpenStreetMap layer — what a user without a Google Maps key really sees.
4.
docs:README rewriteThe generated Markdown brief — the thing the tool exists to produce — was absent from the documentation; it is now included in full. The France-only constraint is a callout near the top instead of a post-
npm installsurprise. Costs are concrete, and correct a wrong assumption: details bill as Place Details Enterprise ($20/1000), not Pro, because the field mask asks forrating,userRatingCountandregularOpeningHours. Adds explicit non-goals.Verification
lint,typecheck, 72/72 tests,db:checkandbuildall pass locally. Every README link and image resolves. No billed Google call was made while producing any of this.This PR is also the first run of the new CI — that is deliberate, better it proves itself here than on
main.Not included
No deployed demo. Vercel is architecturally incompatible: the sweep is a fire-and-forget promise that a serverless function kills at response time, and
/tmpis not shared between invocations, so the poller could not see the database the POST wrote. That needs a host with a persistent process (Fly.io, Railway, Render) and is left for a separate decision.🤖 Generated with Claude Code