Commit Graph
9 Commits
Author SHA1 Message Date
Leon SerfatyandClaude Opus 4.8 595a5e3e04 feat(auth): hide Google sign-in until OAuth is configured
Google social login has no credentials in production, so the "Continue with
Google" button (and its divider) errored on click. Gate the button + divider on
a new isGoogleConfigured() helper (requires GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET)
on both the login and signup pages, and guard the signInWithGoogle action as
defense in depth. The button reappears automatically once both env vars are set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 08:26:08 -04:00
Leon SerfatyandClaude Opus 4.8 e5e987eb4c fix(csp): whitelist Umami analytics origin so tracking works
The CSP script-src/connect-src didn't include the Umami host
(fickanalytics.phluit.net), so the browser blocked both loading script.js and
the event beacons (POST /api/send) — analytics recorded 0 visits despite the
site being live. Add a umamiOrigin() helper (derived from NEXT_PUBLIC_UMAMI_SRC,
defaulting to the shared phluit instance) and include it in script-src and
connect-src.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 07:37:35 -04:00
Leon SerfatyandClaude Fable 5 5a555c715e Build GDPR compliance system: data export, account deletion, consent
- Data export (Art. 15/20): GET /api/gdpr/export serves a full JSON export
  of the user's data (credentials/tokens excluded, exclusions declared)
- Right to erasure (Art. 17): self-service deletion with 30-day grace
  period (Settings -> Privacy & Data), cancellable; daily /api/cron/gdpr
  drain cancels Stripe billing, purges Spaces files, cascade-deletes the
  account, anonymizes consent rows, and writes audit evidence
- Migration 0011: account_deletion_requests (partial unique index = one
  pending per user) + FK-less consent_log (survives erasure)
- Consent: terms/privacy acceptance logged at signup (email + Google);
  cookie banner with analytics opt-out (umami.disabled), choices logged
  server-side for signed-in users via POST /api/gdpr/consent
- Admin deleteUser upgraded to the same full purge (was leaving Spaces
  files and Stripe subscriptions orphaned)
- /gdpr legal page now points at the self-service tools
- scripts/verify-gdpr.ts: end-to-end verification vs live dev DB (22/22)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 06:03:27 -04:00
Leon SerfatyandClaude Opus 4.8 0d11018019 fix(csp): allow inline scripts so the app hydrates on Turbopack builds
Next.js 16 builds with Turbopack, which does NOT stamp the middleware CSP
nonce onto its inline hydration scripts (self.__next_f.push). The nonce-based
`script-src 'self' 'nonce-…'` therefore blocked those inline scripts, React
never hydrated, and the marketing/app pages rendered as a blank/black shell
(header + framer-motion sections stuck at opacity:0).

Switch `script-src` to 'self' 'unsafe-inline' (Turbopack-compatible) and drop
the now-unused nonce plumbing. All other CSP directives stay strict
(object-src 'none', frame-ancestors 'none', locked connect-src/frame-src).
Verified in a local production container: served script-src is correct and
the page hydrates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 05:30:39 -04:00
Leon SerfatyandClaude Opus 4.8 5495b94924 Deploy on DigitalOcean App Platform (GitHub-source build) + consolidate audit-fixes
Deploy config:
- .do/app.yaml: build the Dockerfile directly from GitHub (deploy_on_push) instead
  of a pre-built DOCR image; NEXT_PUBLIC_* set RUN_AND_BUILD_TIME with the
  propertymanagement.network domain so they bake into the client bundle; add
  custom domains block (apex + www); wire Sentry DSN (server + browser).

Included pending work from the audit-fixes branch:
- AI provider abstraction (OpenAI/Anthropic, admin-selectable; Anthropic default)
- Per-landlord e-signature (DocuSign OAuth + Dropbox Sign) + migration 0010
- Outbound webhooks / Zapier integration
- PayPal removal (Stripe-only billing)
- Storage hardening (fail-loud when Spaces unconfigured), security fixes

Verified: full production Docker build (same build-args as DO) passes clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 04:45:24 -04:00
Leon SerfatyandClaude Opus 4.8 917a06ee85 docs: overhaul README and mark project proprietary
- Rewrite README: accurate current feature set (public API, webhooks/Zapier,
  PayPal, accounting sync, e-sign, team, branding, inspections, maps, ~30 tables,
  4 cron jobs), emoji section headers, clearer setup and security sections.
- Remove the inline env-variable example block; point to .env.example / DIGITALOCEAN.md.
- Fix stale "local disk" storage references to DigitalOcean Spaces.
- License: change MIT -> Proprietary; add LICENSE file and package.json "UNLICENSED".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 13:51:59 -04:00
Leon SerfatyandClaude Opus 4.8 c9968531e4 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>
2026-07-02 13:42:34 -04:00
Leon SerfatyandClaude Opus 4.8 969d5d4c8a Security hardening from 2026-07-01 audit
- Exclude supabase/ from Docker build context (leaked service_role key file)
- /api/files: exact per-user namespace match + reject path traversal;
  storage resolveKey rejects ".."/"." segments (fixes cross-user file read)
- Add ownsProperty/Unit/Tenant checks to tenants, maintenance (landlord path),
  and documents (JSON branch, now field-whitelisted) create handlers
- Escape user data in follow-up + payment-link emails (reuse escapeHtml)
- Neutralize CSV formula injection in toCsv + export routes
- Tighter sign-in rate limit (10/min); env-gated email verification + sender
- Per-request nonce CSP; drop script-src 'unsafe-inline' (styles unchanged)
- Add input length bounds; validate follow-ups POST body

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:56:34 -04:00
Leon SerfatyandClaude Opus 4.8 857b9a7811 Initial import: property management SaaS + security hardening + admin dashboard
Property Management Network — Next.js 16 (App Router), Better Auth,
Drizzle ORM over PostgreSQL, Stripe, OpenAI, Resend.

Includes:
- Security hardening: access-control/IDOR fixes, TLS-by-default DB layer,
  constant-time cron auth, strict security headers, atomic AI quota gating,
  HTML/email output encoding, demo-backdoor disabled in production.
- Superadmin dashboard at /admin (overview/MRR, server-paginated users with
  ban/impersonate/plan/delete, billing, platform activity + admin audit log,
  AI usage, system health) via the Better Auth admin plugin.
- Seed/migration utility scripts under scripts/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 20:36:07 -04:00