Skip to content

Remove platform-processed donations; donation links on orgs, people and events - #20

Merged
theobong merged 8 commits into
mainfrom
feat/donation-links
Sep 16, 2026
Merged

theobong merged 8 commits into
mainfrom
feat/donation-links

Conversation

@theobong

Copy link
Copy Markdown
Member

What changed

civfix no longer takes donations. There is no checkout, no fee, no payout and no donation record anywhere in the product: the Stripe integration, the org payments console, the donor receipt pages and the whole payments half of the contract are gone.

In their place, an organization or a person adds a donation link — an ordinary https address they own — in their settings. That link shows up as a Donate card on the events they host, on the organization's public page and on their profile, and tapping it opens the page in the browser. An event can also carry its own link, which wins over the organization's and the organizer's.

Because the product changed, the Terms of Service, Privacy Policy, Cookies & Storage and Sub-processors pages were rewritten and re-versioned, so everyone is asked to accept them once more the next time they sign in.

The mobile app moves to version 1.2.1 (1.2.0 is already in App Store Connect).

Shows in web and mobile.

Before you start

Test on staging.

You need two citizen accounts, and one of them should be an owner or admin of an organization and host an event as that organization.

Related PRs, all part of the same release: civfix-backend #52, civfix-admin #21, civfix-infra #8, dev-env #5. Merge civfix-backend #52 first — the donation-link columns and the new legal document versions live there, and this app expects them.

Verify

[Web]

  1. Sign in, open the host console, pick your organization, then Settings. Under the About section there is a field labelled Donation link, hinted Must start with https://. Shown on your public page and your events; civfix never handles the money.
  2. Type example.org into it. The field shows Must start with https:// and the save button will not let it through.
  3. Replace it with a real https address (for example https://example.org/give) and save. A toast confirms the organization was saved.
  4. Go to the organization's Overview. The cell labelled Donation link now shows the address's hostname, with Edit link underneath it.
  5. Clear the field in Settings, save, and return to Overview. The cell reads No donation link and the link underneath reads Add a link. Set the link again before continuing.
  6. Open the organization's public page (/orgs/<handle>). A button reads Donate to <your organization's name> and opens the address in a new tab.
  7. Open an event that organization hosts, on its public page. There is a card titled Donate with the line Supports <the organization's name>, a button Open donation page, and the hostname of the address underneath. The button opens the address in a new tab.
  8. In the host console, open that event's Settings. The Donations section has its own Donation link field and, because the event is hosted by an organization with a link, the line Leave this blank to use 's donation link. Put a different https address in the event's own field, save, and reload the event page: the card now says Supports and points at the event's address instead.
  9. Open /legal/terms. The row of links reads exactly Terms of Service · Privacy Policy · Cookies & Storage · Sub-processors — there are no donation documents in it. The line under the title shows the new version and effective date.
  10. Sign out and sign back in. You are asked to accept the terms once, and not again on the next sign-in.

[Mobile]

  1. Open the app, go to Settings → Account. There is a Donation link section inviting you to Add a link people can donate through.
  2. Enter not-a-link — it refuses with the invalid-link message. Enter a real https address and tap Save.
  3. Open your own profile. A row reads Donate with Supports and the hostname next to it; tapping it leaves the app and opens the page in the browser.
  4. Go back to Settings → Account and tap Remove link. The profile row disappears.
  5. Open the host dashboard for an event you host personally. There is a row labelled Donation link reading Not set yet. Tap it: it takes you to Settings → Account. Set a link there, come back, and the row reads Live on your events and page: .
  6. Open the host dashboard for an event hosted by your organization. The Donation link row reads Set it in the organization settings on the web and the row is not tappable.
  7. Open any event hosted by an account that has a donation link. The Donate card appears with Supports and Open donation page, and the button opens the browser.
  8. Open Settings → the legal links. The four documents are Terms of Service, Privacy Policy, Cookies & Storage and Sub-processors, and nothing about donations, receipts or payouts.

Regression

  • Create an event and edit it: the event's own donation link saves, clears and survives a reload; an event with no link anywhere shows no Donate card at all.
  • The public sign-up page (/e/<slug>) still renders its donate block when the event carries its own link, and the page builder's donate block still accepts a URL.
  • The other settings editors on mobile (display name, bio, social links, privacy, notifications) still save — the donation link sits beside them and shares the same profile mutation.
  • All four legal pages render, their back link returns to the map, and the footer nav on each page lists the same four documents.
  • The host console still loads for an organization with no donation link, and for a member who is neither owner nor admin.
  • The organization overview, members, verification and events tabs all still load; the payments tab is gone from the nav entirely.
  • Visit an old donation URL such as /donate/some-org. It now returns the 404 page — the route and its SPA fallback rule were both removed, so Cloudflare serves the site's 404. No redirect to the organization page was added.
  • The map, feed, report and messaging flows are untouched and should behave exactly as before.

Not covered

  • The public sign-up page's donate block can only use the event's own link. The event page data does not carry the organization's donation link, so an event with no link of its own shows no donate block there even when its organization has one. Recorded as a follow-up in DECISIONS §46; it needs a contract change.
  • No device or simulator run was done for this branch, on either platform, and Android specifically was not exercised at all. What was verified locally is the whole monorepo's typecheck, lint, tests, locale-key check and the web static export.
  • The real re-consent flow cannot be walked on staging until civfix-backend Repo-wide helper consolidation and naming #52 is deployed — the new legal document rows have to exist before a consent can be written against them.
  • Nothing was run against a real payment processor, because there is no longer one to run against.

Deletes the /donate route and feature, the org payments tab and its console
route section, the Stripe.js loader and appearance, the three donation legal
documents, the Apple Pay merchant-domain file, the /donate/* edge headers and
redirect, the publishable-key and merchant-file build gates, the Stripe eslint
fences and the two @stripe deps.

deploy-web.yml loses the STRIPE_LIVE/STRIPE_TEST variables, the key emission
and the three key assertions; Turnstile and the API/site assertions stay.

The privacy, terms, cookies and subprocessors pages now describe donation
links as external addresses civfix never processes.
Organization settings gains an https Donation link field saved through the org
update mutation, and the overview shows the link's hostname with an edit link.
The public org page and the signup page's donate block now open the external
address in a new tab.
The four host-org overview keys, the three org form keys and the event settings
org-fallback line become real entries in en/es/de/ko, so their call sites drop
the inline defaults. The stale platform-donation org_note is removed with them.

The console's organization donation field now rejects an unsafe https address
the same way the shared components do, using SafeHttpsLinkSchema beside the
request schema instead of letting one through that nothing will render.
The terms, privacy, cookies and sub-processors pages were rewritten for the
donation-link change, so all four move to version 2026-09-16 with the sha256 of
the newly rendered text. Everyone is asked to accept once more.

DECISIONS 46 gains the sign-up page follow-up: PublicEventPageDTO.organization
carries no donationUrl, so that surface cannot fall back to the org link.
App Store Connect already holds 1.2.0, so the next production build needs its
own marketing version. app.config.js does not read package.json, so both move.
@theobong
theobong merged commit 50b4633 into main Sep 16, 2026
4 checks passed
@theobong
theobong deleted the feat/donation-links branch September 16, 2026 02:05
@2ndromanempire

Copy link
Copy Markdown

hang on I did not want this

@2ndromanempire

Copy link
Copy Markdown

We need integrated donations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants