feat(community): restore public signup form on /community - #26
Merged
Conversation
Reverts the form removal from 8d2ee6d. The community-tier Stripe checkout is the only path to the community tier (14.99/mo) - the admin UI only invites to inference - so removing the public form left no way for new members to join community. Restores the CommunitySignupForm Preact island, the cclose__form section and CSS on _community.astro, the 17 community.formStrings i18n keys (en + es), the styles/global.css import, and the waitlistClient.ts comment about the third copy of isValidEmail/REGIONS being back. Both /community and /es/community render the form again. This is how the 22 existing community members originally signed up (before 2026-07-30). 670 tests pass - astro check 0/0/0 - npm run build OK.
…rtal The nan_community pricing card linked to https://cloud.nan.builders/ (the member portal login), which has no signup form. Now that the public community signup form is restored on /community, the CTA must send visitors there so they can actually sign up. Region-aware: /community (en) or /es/community (es).
QA blockers: - Add CommunitySignupForm logic tests (resolveSignupResponse + errorMessageFor) in src/tests/lib/communitySignup.test.ts (18 cases) - Extract response classification into lib/communitySignup.ts as pure functions so the component's error mapping is testable in node - Extend i18nParity.test.ts to cover root-level community + hackaton subtrees, not just nan.* (catches en-only keys rendering as raw paths) - Assert the community pricing card CTA href in pricing.test.ts UX blockers: - Button now uses the .btn .btn-primary system classes instead of raw Tailwind utilities (the un-layered button reset in tokens.css was cancelling bg-violet-600, leaving the submit button unstyled) - Break the /community <-> #pricing loop: hero CTA scrolls to #signup (the form) on the same page, pricing card routes to /community#signup - Remove the client-side honeypot short-circuit: it hung real users (password manager / autofill) on a spinner with no recovery, and did not stop bots that POST directly. The server is authoritative - already_subscribed no longer destroys the form: it renders an inline banner above the still-mounted form so the user can retry with another email - Add alreadyMemberLabel i18n key (was a hardcoded English literal) 688 tests pass - astro check 0/0/0 - npm run build OK.
QA re-review (3 blockers):
- Fix tautological CTA href regex in pricing.test.ts: assert the full
ternary so the EN branch regression is caught, not masked by the ES
substring also containing '/community#signup'
- Add communityPage.test.ts: assert id="signup" exists on .cclose,
CommunitySignupForm mounted with client:load, and every t('community.*')
call resolves to a real string (not the raw key path) in both locales
— closes the gap that let '// already a member' slip through as a
hardcoded literal
UX re-review (2 blockers):
- Show the price on /community: render community.priceLabel (14,99€),
priceTaxNote and footer next to the form. The price was only visible
on the home pricing card; the /community form sent users to Stripe
Checkout without ever showing the amount. The strings already existed
but were orphaned.
- Remove the client-side honeypot field entirely: removing only the
short-circuit left a honeypot-filled response redirecting real users
(password manager / autofill) to the home with a fake-success query
param. The field is gone from the island; the server rate-limiter and
server-side honeypot (when _hp is sent) are the real bot defence.
691 tests pass - astro check 0/0/0 - npm run build OK.
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.
What
Restores the public community-tier signup form on
/communityand/es/community, which was removed in8d2ee6d(2026-07-30).Why
The community tier ($14.99/mo) is the only paid tier without an admin-invite path — the admin UI only invites to inference (€70/$75). The sole way to become a community member is the public Stripe Checkout for the community price. When the
CommunitySignupFormisland was removed, the/api/community-signupendpoint andlib/communitySignup.tswere kept alive but left with no UI caller, so there was no way for new members to sign up to community anymore.This is how the 22 existing community members originally joined (before 2026-07-30). After the removal, the only workaround was generating a Stripe Checkout link by hand via the API — which is what surfaced the gap.
Changes
src/components/landing/CommunitySignupForm.tsx(Preact island,client:load) — callsPOST /api/community-signupwhich forwards to cloud-apiPOST /api/community/signup.cclose__formsection +.cclose__formCSS rule insrc/pages/_community.astro(covers both/communityand/es/communityvia the_-prefixed body).community.formStringsi18n keys ini18n/en.jsonandi18n/es.json(email, region, submit, errors, etc.).import '../styles/global.css'the island needs (Tailwind utilities mapped to project tokens).waitlistClient.tscomment — the third copy ofisValidEmail/REGIONSis back (known tech debt, acceptable).Verification
npm test→ 670 passed (45 files)astro check→ 0 errors / 0 warnings / 0 hintsnpm run build→ OK (Cloudflare Workers server build)/communitychunk referencesCommunitySignupForm+community-signupendpoint confirmed indist/Deploy notes
No VERSION file on this repo — deploy is GitHub Actions on push to
main(deploy.yml:npm ci→npm test→npm run build→npx wrangler deploy). Merging this PR to main triggers the prod deploy to Cloudflare.After deploy, the public community signup works again at
https://nan.builders/communityandhttps://nan.builders/es/community.