Skip to content

URL: https://mkdocs.justinsforge.com/memory/general/reference_sipnserve_site/

sipnservesociety.com Site (Cloudflare Pages)

Replaces Squarespace (subscription to be cancelled after DNS cutover). Built 2026-07-01.

  • Source: forge/sites/sipnservesociety.com/ (standalone git repo, NOT part of the forge repo) -> GitHub JustinWieb/sipnservesociety.com (private).
  • Stack: Astro 5, fully static, no backend. Copy/FAQ/products in src/data/*.json; photos in public/images/ (webp, max 1400px). Brand: original Squarespace palette per Justin (2026-07-01): vermilion #ed350e, bright orange #fe5d0e, warm cream #fffaeb, yellow accent #f4fc03, Poppins, lowercase voice. The Mautic sipnserve email theme was reskinned to the same orange 2026-07-01 (twigs on CT112 + forge/infra/mautic/themes/sipnserve/, both in sync).
  • Deploy: every push to GitHub auto-deploys via Actions (.github/workflows/deploy.yml, cloudflare/wrangler-action; repo secrets CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID). Pages project sipnservesociety, production branch main, URL https://sipnservesociety.pages.dev. Non-main branches get preview deploys. Manual: npm run deploy with CF env vars exported.
  • Calendar: /calendar embeds SweatPals (sweatpals.com/embed/sipnservesociety/events, recolored to brand). Events managed in SweatPals, never in the repo.
  • Newsletter: footer form on every page POSTs to Mautic form id 1 (mautic.justinsforge.com/form/submit?formId=1, formName thesipnewsletter). Form actions: (1) add contact to segment 1 "Sip N Serve Members", (2) send welcome email (Mautic email id 3, email.send.lead). Both tested end-to-end 2026-07-01 (segment row + delivered welcome verified; test contacts deleted). Mautic API was enabled temporarily to create form/email and is DISABLED again.
  • Welcome email auto-refresh: forge/scripts/forge_sipnserve_welcome_email.py (cron daily 05:00 CT, log logs/sipnserve-welcome-email.log) scrapes the next 3 events from sweatpals.com/sipnservesociety (the bare embed URL renders EMPTY outside an iframe; scrape the community page), renders MJML (template inline in the script), compiles with ~/.forge-tools/mjml/node_modules/.bin/mjml, and UPDATEs emails.custom_html + bundle_grapesjsbuilder.custom_mjml for email 3 over ssh. Event cover images: downloaded through the browser context, converted to jpg (Outlook has no webp), self-hosted as /opt/mautic/mautic/media/images/sns-welcome-event-{1..3}.jpg (fixed names, content-hash ?v= cache-buster because Cloudflare caches the media path). Fail-loud: 0 events or lost unsubscribe token aborts (old email stays live) + warning notify. Emails cannot embed live iframes, hence cards + calendar link instead of the website's SweatPals embed.
  • Store: intentionally minimal per Justin (static cards, order via Instagram DM or mailto). /get-involved 301s to /partnerships.
  • /connect page (2026-07-02): three sections. (1) join our community -> SweatPals main page (site.sweatpals = https://sweatpals.com/sipnservesociety), NOT the old Google Form. (2) next events -> SweatPals events embed (same iframe as /calendar). (3) contact us -> form (name, email, title, description). Nav "connect with us" button + home "let's chat" CTA both link to /connect.
  • Contact form backend: Cloudflare Pages Function functions/api/contact.js (runs alongside the static Astro build, no adapter). POST /api/contact -> Resend API, from [email protected] (domain DKIM-verified in Resend), to [email protected], reply_to = submitter (so Reply goes to the visitor). Honeypot field company + validation + fail-loud. Secret RESEND_API_KEY set as a Pages project env var (secret_text) on BOTH production + preview via CF API (~/.forge-secrets/resend.env). Set-secret helper pattern: GET project -> merge env_vars -> PATCH (don't clobber existing).
  • hello@ = Google Group on the sipnservesociety.com SECONDARY DOMAIN under the justinwieb.com Workspace (super-admin [email protected]). Settings: ANYONE_CAN_POST / MODERATE_NONE (verified 2026-07-02); it does NOT moderate/quarantine. Members: [email protected] + [email protected] (Krystal is the active responder, Justin observer). Group mail does NOT reach [email protected] (personal) - that account is not a member. Manage the group fully with the existing business admin token: forge_google_user.user_token("business") already has Directory + apps.groups.settings scopes (no new OAuth/scopes needed; sipnserve rides on the justinwieb.com Workspace app-trust). Groups Settings API groups/v1/groups/<email>, Directory admin/directory/v1/groups/<email>/members.
  • Meet-your-hosts (2026-07-02): rebuilt as 5 circular bobbing headshots (name + role, no bio) from site.hosts in site.json: Krystal (founder, smash-3), Liliana (ch-07143), Uyi (sipnserve-5-10-29), Anna (nov6-72), Rocky (sep-13-1). 13 orphaned photos deleted.
  • DNS cutover (NOT DONE, needs Justin's explicit approval): snapshot of all 25 pre-cutover records at forge/data/sipnservesociety-dns-snapshot-2026-07-01.json. Flip = add custom domains sipnservesociety.com + www to the Pages project via API, then repoint apex (4 Squarespace A records) and www CNAME (ext-cust.squarespace.com) to sipnservesociety.pages.dev. NEVER touch MX (Google inbound), SES/Mailchimp DKIM CNAMEs, or unsubscribe/send/mail records. After cutover Justin cancels Squarespace.
  • DNS cutover EXECUTED 2026-07-02: Squarespace apex (4 A records 198.185.159.144/145 + 198.49.23.144/145) deleted; apex + www now CNAME -> sipnservesociety.pages.dev. Custom domains added to Pages project. MX/DKIM/SPF/DMARC/site-verification ALL preserved (email untouched). Pre-cutover snapshot: forge/data/sipnservesociety-dns-snapshot-2026-07-02-precutover.json (25 records; one-command revert). Cutover script: scratchpad sipnserve_cutover.py (dry-run default, --execute).
  • GOTCHA: Cloudflare Pages custom-domain cert validation is HTTP-method and CANNOT complete while the DNS record is PROXIED (orange) before the domain is active = chicken-and-egg 522 (edge has proxied record but no Pages route yet, so the ACME HTTP challenge to /.well-known/... hits its own 522). Fix: set the apex + www CNAMEs to DNS-only (grey cloud) so the challenge resolves straight to the pages.dev IPs and validates; the domain flips pending->active, then you MAY re-proxy for CF caching (apex CNAME flattening serves either way). Also: do NOT keep poking (revalidate/delete-readd/proxy-toggle) - each change resets Cloudflare's validation retry cycle; set correct DNS-only records once and WAIT ~10-15 min. CF token in ~/.forge-secrets/cloudflare.env has DNS+Pages but NOT SSL scope (403 on ssl endpoints).
  • Migration story: sipnserve-site-migration handoff.

[Claude Code, sipnserve-site worker]