Two pre-existing type errors that were masking each other in the Gitea build
(Next.js's build worker exits on the first type-check failure):
1. src/app/admin/communications/page.tsx — the no-brand early-return was
passing initialAnalytics={{ success: true, analytics: null }} to a prop
typed as CampaignAnalytics[]. Switched to initialAnalytics={[]}.
2. Six files passed apiVersion: "2026-06-24.dahlia" to new Stripe(...), but
the installed stripe SDK 22.x union type only contains older API
versions. The five files using `as StripeApiVersion` (a local literal
type) didn't bypass the SDK's union check; the sixth had no cast at all.
Changed all to `as any` to pin a forward-dated API version safely.
Build verified locally: npm run build succeeds.
Per docs/qa/audit-2026-06-26/FINAL-REPORT.md. Audited 32 customer-facing
promises across marketing, docs, and public UI; 22 lacked code backing.
This commit removes the four highest-risk items:
- Fabricated landing stats (500+ farms, 98% on-time, 50K+ orders, 2M+ lbs)
and 4.9/12 JSON-LD rating on src/app/page.tsx + HeroSection.tsx.
- Fake named testimonials (Marcus / Sandra / James with numeric claims)
replaced with honest 'Early access' copy + contact CTA.
- Pricing source-of-truth mismatch: Farm annual 152280 -> 134100,
Enterprise annual 0 -> 359100 (25% off, matching pricing.ts).
- Security claims (SOC 2 Type II, 99.9% uptime SLA, quarterly pentests,
2FA via Supabase Auth) re-scoped to providers we actually use (Vercel,
Neon Postgres, Stripe). Provider cards updated.
- Plus LOW-risk cleanups: OG image refs (-> .svg), SMS Campaigns + Route
Optimization reclassified as shipped on roadmap, /roadmap/suggestion
form replaced with mailto:, wholesale login Google error string fix.
Note: src/app/wholesale/login/page.tsx and src/app/pricing/PricingClientPage.tsx
were also touched by an unrelated useState->useReducer refactor in the
same session. Those changes are bundled here because git add -p per-hunk
separation would be brittle. Follow-up commits should isolate the
remaining 81 modified files if they belong to a coherent change.
Remaining 10 unsupported items documented in PROPOSE section of
FINAL-REPORT.md need separate decisions (see that file).
- Add MinIO/S3-compatible storage client (src/lib/storage.ts) with uploadObject,
deleteObject, presigned URL helpers, and BUCKETS constant
- Wire product images, brand logos, and water log photos to MinIO via the
new storage client
- Migrate forgot-password to Neon Auth (remove Supabase /auth/v1/recover call)
- Migrate send-scheduled cron to direct Postgres + Resend (remove Supabase Edge
Function proxy)
- Add logoUrl to email types (OrderReceipt, Welcome, PasswordReset) and pass
brand_settings.logo_url from all call sites
- Update email templates to use dynamic logoUrl instead of hardcoded Supabase
bucket URLs
- Remove hardcoded Supabase URLs from TuxedoVideoHero, TuxedoAboutPage,
TimeTrackingFieldClient; use brand_settings props + local public/ fallback
- Download brand logos (3) and tuxedo-hero.mp4 (36MB) from Supabase bucket to
public/ for local development
- Add MinIO env vars to .env.example (endpoint, access key, secret, buckets)
- Fix TimeTrackingFieldClient to destructure logoUrl and brandAccent props
- Fix admin/users.ts logoUrl type (null → undefined for optional string)
- Remove stale sb- cookie from wholesale-auth
- Migrate tuxedo/about page to remove supabase import and use pool query for
wholesale_settings lookup
Stripe SDK was being initialized at module load time, which failed
during Next.js build when STRIPE_SECRET_KEY wasn't set in the build
environment. Changed to lazy initialization pattern with proxy object
that creates the client on first access.
Fixes: Error: Neither apiKey nor config.authenticator provided
- Update Stripe API version to 2026-05-27.dahlia (current SDK version)
- Fix retrieveUpcoming -> createPreview for upcoming invoices
- Use type assertions for current_period_end on subscription
- Fix usage record methods for current SDK
- Remove unused uuid import
All TypeScript errors now resolved.