FL 718.111(12)(g) association website and Xero PDF attachments

2026-04-03

Florida condominiums with 150+ units have a statutory obligation to maintain a website containing specific categories of official records, under §718.111(12)(g) of the Florida Condominium Act. Bamboo House is over that threshold, so honest-cam needs to ship that website. This PR is it — plus a Xero integration improvement that's been bugging me since PR #4 shipped.

The association website

  • Public pages at /website/* — homepage, about, contact, meeting notices. These are visible without login, which is the statutory requirement for a few specific items (notices of meetings, for example).
  • Auth-gated records at /website/records — 17 statutory document categories behind the magic-link session auth the owner portal already uses. This is where the sensitive stuff lives: contracts, financial reports, budgets, insurance certificates, director certifications.
  • website-populate CLI — reads the OCR sidecars from the earlier pipeline stages and symlinks 940 documents into four categories (financial reports, contracts, budgets, director certs) under the website's records tree. Symlinks, not copies, so the canonical file stays in the ingest pipeline's directory and the website just points at it. Re-running the command is idempotent (dedupes by source path) and category classification comes from the OCR sidecar, not a separate hand-labeled file.
  • Competitor reference doc covering 20+ providers — CONDUU, CondoSites, BuildingLink, and others. Not because I want to be them, but because I want to be explicit about what honest-cam does that they don't (native Xero integration, OCR-driven document organization, real compliance tracking) and what they do that I haven't bothered with (branded domains, custom-designed public pages).

Dev mode auto-login

Testing the association website kept requiring me to request a magic link, copy it out of stdout, paste it into the browser, hit login, and then click through. Dozens of times a day. New env var: PORTAL_DEV_MODE=1.

When set:

  • Login skips the magic-link dance.
  • Portal auto-creates a session for the first unit owner in the property registry.
  • Guarded against running anywhere that isn't localhost (the middleware rejects any request where request.client.host isn't in 127.0.0.1 / ::1).
  • Unguarded in production: the env var simply isn't set on the Mac mini, so the dev-mode branch never even compiles into the active code path.

Four tests specifically cover the dev-mode guard because I want the "oh god this shipped to prod by accident" failure to be impossible, not just unlikely.

Xero PDF attachments

This is the part I've wanted since PR #4. When honest-cam syncs a bill or an invoice to Xero, it now also attaches the source PDF to the Xero transaction via Xero's attachment API. So when a board member logs into Xero and clicks on a $6,000 waste management invoice, they see the actual waste management invoice, not just a line item saying "Waste Management, $6,000, 2026-04-01."

This closes the loop between the OCR pipeline and the ledger. Every Xero transaction is now traceable to its source document in one click.

A backfill command, honestcam xero-attach <slug>, walks historical synced transactions and attaches PDFs retroactively. Idempotent — it won't attach the same file twice because Xero's API returns the existing attachment ID on a duplicate.

Xero reauth script

Xero refresh tokens expire after 60 days of non-use. scripts/xero-reauth.sh runs the full OAuth dance from the command line so I can re-authorize without touching the web UI. Scheduled to run weekly, well inside the 60-day window.

Verification

  • 21 website route tests — public pages render, auth gating works on the records route, file downloads stream correctly, path traversal is blocked on record downloads.
  • 4 dev-mode login tests — auto-redirect works, session cookie sets correctly, the env-var guard is respected, non-localhost requests are rejected.
  • 23 populate tests — category mapping, symlink creation, idempotency, dedup, and error handling (missing source file, invalid category, permission errors).
  • Full suite: 575+ tests passing, ruff clean.
  • Preview verified end to end: homepage, about, records page showing all 940 indexed documents.

PR: https://github.com/StevieIsmagic/honest-cam/pull/8