Changelog
All notable changes to Generous.nz are recorded here, grouped by version. Every deployed build has a version number, a git tag, and an entry below.
Versioning scheme
Versions follow MAJOR.MINOR.PATCH:
- 0.x — pre-launch. Minor bumps mark a completed build phase or major feature set; patches are bug fixes on the current build.
- 1.0.0 — first public launch.
- 1.x+ — post-launch: minor = new features, patch = fixes, major = breaking changes or significant re-architecture.
Each version is tagged in git (v0.2.0) and the current version is kept in
package.json. See docs/version-control.md for how to cut a release.
[0.9.10] — 2026-08-24
Security hardening pass — full audit + fixes.
Fixed
- Login brute force: credential sign-in is now rate-limited (10 attempts per email per 15 minutes), returning the same error as a wrong password so attackers can't detect locked accounts.
- AI cost abuse: the AI content generation endpoint is now rate-limited (40 calls per IP per 10 minutes) so a logged-in user can't burn through your DeepSeek/OpenAI tokens.
- IP-spoofable rate limits: the rate limiter trusted the first
X-Forwarded-Forvalue, which an attacker could spoof through the proxy. It now prefersX-Real-IPand otherwise uses the last (proxy-appended) forwarded address. - Upload validation: uploads now verify the file's magic bytes (not just
the client-declared type), so a renamed HTML/script file can't be stored
or served as an image. Uploaded files also get
X-Content-Type-Options: nosniff. - Blog sanitizer hardened: rendered markdown now also strips iframes,
objects, embeds, forms, SVG/MathML, links, metas and bases, plus
data:andvbscript:URIs on top of the existing script/event-handler stripping. - Security headers on every response:
X-Content-Type-Options,X-Frame-Options: DENY,Referrer-Policy,Permissions-Policy, and a Content Security Policy (frame-ancestors none, base-uri/form-action self, remote images allowed for cover photos). - Blog publishing API rate limit on the token-based update/delete endpoints (30 per 10 minutes).
Dependencies (npm audit)
- postcss upgraded to a patched 8.5.x (resolves 4 high advisories, including the source-map disclosure issues).
- sharp overridden to patched 0.35.x (resolves the libvips CVE cluster).
- Remaining:
deepmerge-tsinside the Prisma CLI tooling (dev-only, not shipped to the runtime). The full remediation for the bundled sharp/postcss chain is a Next.js 16 upgrade, which is a separate breaking-change task.
Verified by review
- Authorization (ownership) checks confirmed on fundraiser/product/wholesale product & order/update/review/export/admin routes.
- Webhook signature verification, server-side price/fee computation, Stripe direct-charge account routing, and the no-open-redirect login flow all confirmed.
[0.9.9] — 2026-08-24
AI token efficiency pass — every AI call tightened.
Changed
- Tighter prompts everywhere: moderation/review prompts, order fraud screening, campaign risk scoring and the fundraiser-reasons check were rewritten to be short and specific (JSON-only replies, no filler).
- Per-task output caps (
max_tokens):- Content generation: now capped per type (80–400) instead of a flat 700.
- Moderation/AI review: 120 (was default 300).
- Order fraud screening: 120 (was 250).
- Fundraiser-reasons verification: 200 (was 500).
- Campaign risk scoring: 120 (was 200).
- Long inputs truncated before they're sent (stories capped at ~3–4k characters, generation context at 2.5k) so prompt cost stays low.
- Provider consistency fix: content generation and campaign risk scoring now use the configured review provider (DeepSeek preferred, OpenAI fallback) instead of only checking for an OpenAI key — so the AI tools actually run with a DeepSeek key instead of silently using template fallbacks.
[0.9.8] — 2026-08-24
Site-wide content audit for the new payment system.
Changed (non-legal pages & copy)
- Landing page: "Get paid safely" now explains the 5% + GST fee is invoiced to the fundraiser, never taken from donations.
- Getting started: step 6 clarified — payments go straight to your bank; wholesale commissions are paid automatically by the business; the platform fee is invoiced weekly to the card you add.
- Business page: the example breakdown now reflects the direct-charge model (buyer pays the business $100 → $10 commission → $5.75 fee invoiced → business keeps $84.25), instead of the old "fee from the sale" wording.
- Campaign page "Where the money goes": explains donations/sales go straight to the seller's own Stripe account and the fee is invoiced to the fundraiser.
- Dashboard sales page: updated the split explanation and column labels — buyers pay sellers directly; wholesale suppliers are paid directly (not "from the sale"); fees shown as invoiced.
- Connect payout account button: no longer says money is "held securely" — it's paid out by Stripe directly, and notes the fee card step.
- Help centre: "Covering platform fees" and "Campaign settings" updated to match the invoiced-fee model and the new reasons editor.
- Fee references aligned: the stored subscription fee reference and the
PLATFORM_FEE_PERCENTconstant now use 5.0 (not the old 5.75 application fee), with migration0023_subscription_fee_percent. - Stripe onboarding comment/URL cleanup (Standard accounts only).
Verified
- Fundraiser Stripe setup end to end: Standard account via hosted onboarding,
account.updatedsync, dashboard payout-account + fee-card steps, and the help guide all match the current flow.
[0.9.7] — 2026-08-24
Legal pages fully aligned to the SaaS/direct-charge model.
Changed
- Audited all legal pages for leftover marketplace wording and removed
it:
- Terms of Service: platform reframed as software/tools/administration; "marketplace platform" wording removed.
- Privacy Policy: same reframe + typo fix ("an agency"); version 2.0 with a direct-charge change note.
- Seller Agreement: no longer describes the Platform as a "marketplace and payment facilitator"; chargebacks clarified as taken from the seller's own Stripe balance. Version corrected to 2.0.
- Fundraiser Agreement: "marketplace items" → "catalogue items"; "hold or reverse payouts" → "pause payouts or commission invoicing".
- Refund, Dispute and AML/CFT policies: bumped to 2.0 with change notes describing the direct-charge model (seller is merchant of record; the Platform never holds or routes money).
- Verified the whole site (all pages and components) has no remaining "marketplace" phrasing.
[0.9.6] — 2026-08-24
Edit fundraising reasons on existing campaigns.
Added
- Each fundraiser card on the dashboard now shows its reason tags (or "No reasons selected") with an Edit reasons / Add reasons button. Owners can change what they're fundraising for at any time, not just at creation.
- Saving re-runs the AI verification against the story (unsupported tags removed, clearly-described tags added, flagged for review if something was removed), so edits stay honest.
[0.9.5] — 2026-08-24
Automatic IndexNow key rotation.
Added
- Rotatable IndexNow key: the active key now lives in the database
(falling back to
INDEXNOW_KEY), so it can change at runtime without a deploy or restart. The verification file at/<key>.txtfollows automatically. - Rotation cron (
/api/cron/indexnow?key=…): generates a fresh 32-char key whenINDEXNOW_ROTATE_DAYShas elapsed (default off; 30 is recommended). Safe to run hourly — it self-throttles to the interval. Each rotation is audited (indexnow.key_rotated).
Notes
- Rotation is hygiene, not security: the key file is public by design. A 30-day cadence invalidates leaked copies without churning the file.
[0.9.4] — 2026-08-24
Fundraising reasons — "what are you fundraising for" tags with AI verification and business opt-outs.
Added
- Fundraiser setup checkboxes: campaigns can tick what they're raising for (medical, education, sport, community, animals, environment, arts & culture, faith, emergency, event, other). Tags show as badges on the public campaign page.
- AI verification in the background: the configured AI reads the story against the selected tags and removes tags the story doesn't support and adds tags it clearly describes. Changes are audited; a campaign that has a tag removed (a likely misrepresentation) is flagged in the moderation queue for human review.
- Business opt-outs: approved businesses can tick "causes you won't fundraise for" in their wholesale dashboard. Fundraisers raising for an excluded cause can't add that business's offers — the catalogue shows "Not available for your fundraiser" and the add-to-store API rejects the add with a clear message.
- New schema (migration
0022_fundraising_reasons):FundraisingReasonenum,Fundraiser.reasons,WholesalerProfile.excludedReasons.
[0.9.3] — 2026-08-24
IndexNow — instant search-engine submission.
Added
- IndexNow integration (
lib/indexnow.ts): new and changed pages are submitted to Bing and other participating search engines the moment they go live. - Key file endpoint —
https://generous.nz/<key>.txtis served automatically whenINDEXNOW_KEYis set (any other key returns 404). - Automatic submissions:
- Blog posts on publish (both
/blog/<slug>and/blog), from the admin area or the external AI publishing API; - Fundraisers when approved and when updated (
/f/<slug>); - Organisation storefronts on creation (
/orgs/<slug>); - P2P supporter pages on creation (
/p2p/<slug>).
- Blog posts on publish (both
- Setup guide:
docs/indexnow.md; env entry added to.env.example.
Notes
- Submissions are best-effort and never block publishing. Batches of 25
URLs per request. Disabled entirely when
INDEXNOW_KEYis unset.