Consolidate audit-fixes branch: webhooks, integrations, and deploy hardening

Batch commit of the pending working tree on security/audit-fixes-2026-07.
Major areas:
- Outbound webhooks / Zapier: schema + signed delivery with retries, public
  v1 API (REST-hook subscribe/unsubscribe), settings UI, cron drain.
- Deploy hardening: email via SMTP2GO (Resend fully removed), verified DB TLS
  (DATABASE_SSL=require + DATABASE_CA), storage fails loud in production when
  Spaces is unconfigured instead of silently using ephemeral disk.
- Integrations & features (concurrent work): accounting (QuickBooks/Xero),
  e-signature (DocuSign/Dropbox Sign), PayPal, geocoding/maps, onboarding,
  expanded legal pages.
- DB migrations 0006–0009.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leon Serfaty
2026-07-02 13:42:34 -04:00
co-authored by Claude Opus 4.8
parent 969d5d4c8a
commit c9968531e4
282 changed files with 41530 additions and 4013 deletions
+34 -29
View File
@@ -5,12 +5,13 @@ import Link from "next/link"
import { motion } from "framer-motion"
import { Check, X, Zap, ShieldCheck } from "lucide-react"
import { cn } from "@/lib/utils"
import { PLAN_AMOUNTS } from "@/lib/stripe/plans"
const PLANS = [
{
key: "starter",
name: "Starter",
monthlyPrice: 0,
monthlyPrice: PLAN_AMOUNTS.starter,
description: "For landlords just getting started.",
highlight: false,
cta: "Get started free",
@@ -20,7 +21,7 @@ const PLANS = [
{
key: "pro",
name: "Pro",
monthlyPrice: 29,
monthlyPrice: PLAN_AMOUNTS.pro,
description: "For active landlords growing their portfolio.",
highlight: true,
badge: "Most popular",
@@ -31,7 +32,7 @@ const PLANS = [
{
key: "landlord",
name: "Landlord",
monthlyPrice: 59,
monthlyPrice: PLAN_AMOUNTS.landlord,
description: "For serious portfolios at scale.",
highlight: false,
cta: "Start Landlord",
@@ -42,7 +43,7 @@ const PLANS = [
key: "lifetime",
name: "Lifetime",
monthlyPrice: null,
fixedPrice: 199,
fixedPrice: PLAN_AMOUNTS.lifetime,
description: "Pay once, own it forever.",
highlight: false,
badge: "Best value",
@@ -71,7 +72,7 @@ function Cell({ val }: { val: string | boolean }) {
return <span className="text-sm font-medium text-white/80">{val}</span>
}
export function PricingSection() {
export function PricingSection({ annualEnabled = false }: { annualEnabled?: boolean }) {
const [annual, setAnnual] = useState(false)
const DISCOUNT = 0.8
@@ -95,30 +96,34 @@ export function PricingSection() {
<h2 className="text-3xl font-bold text-white sm:text-4xl">Simple, honest pricing</h2>
<p className="mt-3 text-white/50">Start free, upgrade when you grow. No per-unit fees, ever.</p>
{/* Toggle */}
<div className="mt-8 inline-flex items-center rounded-full border border-white/10 bg-white/[0.04] p-1.5">
<button
onClick={() => setAnnual(false)}
className={cn(
"rounded-full px-4 sm:px-5 py-1.5 sm:py-2 text-xs sm:text-sm font-medium transition-all duration-200",
!annual ? "bg-indigo-600 text-white shadow-lg shadow-indigo-500/30" : "text-white/50 hover:text-white"
)}
>
Monthly
</button>
<button
onClick={() => setAnnual(true)}
className={cn(
"flex items-center gap-1.5 sm:gap-2 rounded-full px-4 sm:px-5 py-1.5 sm:py-2 text-xs sm:text-sm font-medium transition-all duration-200",
annual ? "bg-indigo-600 text-white shadow-lg shadow-indigo-500/30" : "text-white/50 hover:text-white"
)}
>
Annual
<span className="rounded-full bg-emerald-500/20 px-2 py-0.5 text-[10px] font-bold text-emerald-400 border border-emerald-500/30">
20%
</span>
</button>
</div>
{/* Toggle — only shown when annual billing is actually purchasable.
When annual isn't configured we stay monthly-only rather than
advertising a plan that can't be bought. */}
{annualEnabled && (
<div className="mt-8 inline-flex items-center rounded-full border border-white/10 bg-white/[0.04] p-1.5">
<button
onClick={() => setAnnual(false)}
className={cn(
"rounded-full px-4 sm:px-5 py-1.5 sm:py-2 text-xs sm:text-sm font-medium transition-all duration-200",
!annual ? "bg-indigo-600 text-white shadow-lg shadow-indigo-500/30" : "text-white/50 hover:text-white"
)}
>
Monthly
</button>
<button
onClick={() => setAnnual(true)}
className={cn(
"flex items-center gap-1.5 sm:gap-2 rounded-full px-4 sm:px-5 py-1.5 sm:py-2 text-xs sm:text-sm font-medium transition-all duration-200",
annual ? "bg-indigo-600 text-white shadow-lg shadow-indigo-500/30" : "text-white/50 hover:text-white"
)}
>
Annual
<span className="rounded-full bg-emerald-500/20 px-2 py-0.5 text-[10px] font-bold text-emerald-400 border border-emerald-500/30">
20%
</span>
</button>
</div>
)}
</motion.div>
{/* Plan cards */}