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.17] — 2026-08-24
Go-live plan rewritten for the current build.
Changed
docs/go-live.mdrebuilt as a phased checklist (Phase 0 decisions & sign-off → deploy/config → test-mode drills → live switch → first-two-weeks watch), with explicit gates and references to the current setup guides.
[0.9.16] — 2026-08-24
Off-server image storage (Bunny) + automatic unused-image cleanup.
Added
- Bunny Storage support (
lib/uploads.ts): whenBUNNY_STORAGE_ZONEandBUNNY_STORAGE_ACCESS_KEYare set, new uploads go straight to Bunny Storage;BUNNY_PULL_ZONE_URLserves them via the Bunny CDN. Existing/api/uploads/...URLs keep working unchanged (the route serves local files first, then redirects to the CDN) — no database migration needed. - One-off backfill script (
scripts/backfill-uploads-to-bunny.mjs) to move existing files to Bunny. - Upload garbage collector (
lib/upload-gc.ts+/api/cron/upload-gc): scans every product, wholesale product, fundraiser, organisation and blog post for referenced images and deletes the rest after a grace period (UPLOAD_GC_GRACE_DAYS, default 7). Covers the cases you asked about — business removes an item, changes a photo, fundraiser does — plus anything else that becomes unreferenced. Runs against whichever backend is active (local or Bunny). - Setup guide:
docs/upload-storage.md.
Notes
- Everything is env-gated: with no Bunny keys, the site behaves exactly as before (local storage).
- Images are still optimised before storage (1600px, quality 80, metadata stripped), so what reaches Bunny is already small.
[0.9.15] — 2026-08-24
Auto-optimised image uploads — smaller files, originals never stored.
Changed
- Every uploaded image is now processed on the way in: resized to a max long edge of 1600px (never enlarged), re-encoded at quality 80 for JPEG/WebP/AVIF, losslessly compressed for PNG, EXIF/orientation metadata stripped, and the original bytes are never written to disk.
- The site fits images into each layout with CSS (
object-cover), so one lean file serves every space — campaign covers, product cards, storefront banners and blog covers. - Safety net: if optimisation ever produced a larger file (e.g. a tiny already-optimised image), the original is kept instead.
sharpis now a direct dependency (it was already in the tree via Next).
Notes
- Applies to new uploads. Existing uploaded images are untouched — a
one-off script can re-process the current
uploads/folder if you want to reclaim space now.
[0.9.14] — 2026-08-24
Finished the listing-expiry loop ("extend it anytime" is now real).
Added
- My listings dashboard page (
/dashboard/products): every fundraiser listing in one table — price, moderation status, expiry date and a quick extend/relist control (15/30/45/90 days). Expired listings show a "Relist for…" button; live ones "Extend by…". - Sidebar link to My listings, and a second CTA on the Getting Started page's "List products" step.
Confirmed already in place
- Getting Started page (six steps: sign up → connect payout account → fundraiser → list products → share your link → get paid).
- Every campaign, organisation storefront and P2P page has its own shareable link with a copy button on campaign pages.
- Auto-expiry (15/30/45/90 days) on the listing form, enforced everywhere (checkout, explore, catalogue), with the update API supporting extension.
[0.9.13] — 2026-08-24
Full-system audit: half-finished features, correctness fixes and old-idea remnants.
Fixed
- Physical wholesale orders now email the business with the buyer's delivery address, zone and delivery charge — previously only vouchers notified suppliers, so physical orders relied on the dashboard alone.
- Removed the leftover destination-charge transfer engine from the
codebase (
lib/wholesale-transfers.tsnow only runs the velocity check). The old webhook paths that would have attempted platform→seller transfers (double-paying the business under direct charges) are gone. - Admin dispute view and analytics export no longer show the obsolete "transfer ID / reversal" fields from the old model (the export now lists shipping zone and charge instead).
docs/architecture.mdupdated from the old application-fee/transfer model to the current direct-charge + invoiced-fee model.
Verified during the audit
- The webhook handles direct-charge checkouts, commission/platform-fee/ business-fee invoices, disputes, refunds and payouts with no transfer remnants.
- All 14 released versions are tagged; type-check and production build pass.
- The branch had been reset to an old commit externally (v0.8.0) while the correct code lived in the tags — the branch was restored to v0.9.12 and this release is committed on top.
Known "waiting on you" items (not code bugs)
- Live Stripe keys + webhook re-pointing (listen to connected-account events and invoice events).
- Server env keys:
RESEND_API_KEY(email),DEEPSEEK_API_KEY(AI),BLOG_API_TOKEN,CRON_SECRET,INDEXNOW_KEY(+ optionalINDEXNOW_ROTATE_DAYS),ORDER_FRAUD_ENABLED. - Fee numbers:
WHOLESALER_FEE_BPS(default 5%) and the free-first-$X threshold (default none). - Lawyer/accountant sign-off on the legal docs and the Option A money flow.
- The dormant BECS subscription-fee invoicing (Phase 3 item, fee default $0) is still available but not scheduled.
[0.9.12] — 2026-08-24
Geographical delivery + metro/rural shipping charges with AI zone checking.
Added
- Delivery coverage on wholesale products: businesses choose where they ship (all of NZ, North Island only, South Island only) and set simple metro and rural delivery charges for physical products.
- Delivery address at checkout: buyers of physical wholesale items enter their delivery details (name, street, city, region, 4-digit postcode). The zone is derived from the NZ postcode rule (rural codes start 7/8/9), the correct metro/rural charge is added to the order, and out-of-coverage orders are declined with a clear message.
- AI address verification: the AI cross-checks the address against the postcode and the supplier's coverage. Disagreements don't block the sale — the order is flagged in the moderation queue for a human to verify before fulfilment.
- Order & fulfilment visibility: shipping charge, zone and the full delivery address are stored on the order, shown to the business on their orders page, included in the buyer's receipt email, and sent to the supplier's fulfilment notification so they can ship without chasing the buyer.
- Business page + help centre updated to explain delivery coverage and metro/rural charges.
- New schema (migration
0024_shipping_zones):ShippingCoverageenum,WholesaleProduct.shippingCoverage/MetroCents/RuralCents, and order shipping fields.
Notes
- The platform fee and the fundraiser's commission apply to the item price only — the delivery charge is passed through to the seller.
- Vouchers are digital and never require a delivery address.
[0.9.11] — 2026-08-24
XML sitemap generator installed on the site.
Added
/sitemap.xml— a live sitemap generated by Next.js on every request. It lists the key static pages, all legal documents, published blog posts, live fundraisers, organisation storefronts and P2P pages, with last-updated dates and priorities. New content appears automatically.robots.txt— allows all crawlers and points them at the sitemap.
Notes
- A downloaded
2026-AdvertiseOnline-generator.zipcouldn't be located on this machine (checked Downloads, Desktop, Documents, OneDrive, attachments and phone folders) — if it's re-attached or its path shared, it can be inspected and installed alongside this.
[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.