Root cause of 'syncs stop at 5/31': the nightly buildium-gl-sync writes journal
entries (so reports stay current) but never created the matching bank-register
transactions for import-mode companies (gl_auto_post=false). Those registers were
materialized once at import, so the reconciliation/register views froze ~5/31
while the GL kept advancing.
- Add accounting.transactions.journal_entry_line_id (FK + unique index) to link
register rows to their source GL line, making materialization idempotent
- buildium-gl-sync now materializes a register transaction for each bank line it
inserts, for import-mode companies only (bank debit -> deposit/credit,
bank credit -> withdrawal/debit; category/coa from the single offset account),
upserting on journal_entry_line_id so re-runs never double-insert
- One-time backfill (run against prod) filled the existing gap: 231 register
rows across Bridgewater/Casuarina/Village Grove/Bent Oak, skipping 3 near-miss
rows that share a day with an existing register row (incl. a Casuarina transfer)
for manual review
gl_managed companies are unaffected — their register drives the GL via
post_transaction_gl, not the other way around.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/v1/glaccounts omits some inactive accounts (e.g. prior-management bank
accounts) whose ledgers still hold one side of historical transactions,
making checks/deposits come back unbalanced on backfills (found during the
Casuarina Club GL import).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /v1/vendors 403s on keys without the Vendors scope; import bills without
vendor links instead of failing the pull, and surface it in results.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anything on/before buildium_gl.last_synced_date is already in the books as
buildium_gl entries; ap_cutover_date freezes that boundary so direct
buildium_bill/billpay postings never double-count history.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- public.bills.line_items + line-aware accounting mirror (one bill_item per
Buildium line with its mapped platform account)
- buildium-sync bills: strict per-line resolution through
buildium_gl_account_links (unmapped -> bill held + flagged); pulls
/bills/{id}/payments (check#, bank, date) and /bankaccounts/{id}/checks
(one-off checks become paid bill+payment pairs)
- import-mode companies get direct JEs (buildium_bill Dr expense/Cr AP,
buildium_billpay Dr AP/Cr mapped bank) + cleared register rows; sets
buildium_gl.exclude_ap so the nightly GL pull skips Bill/Bill Payment/Check
- buildium-gl-sync: exclude_ap transaction-type filter; preserve buildium_gl
config keys when advancing the watermark
- Settings: Pull Bills & Expenses card with held/unmapped reporting
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Buildium API exposes no ARC comment threads or member votes (verified live);
surface the final decision instead: vote row dated to the actual decision,
decision_notes 'Approved by X on date (via Buildium)'
- record_buildium_arc_vote RPC bypasses the finalized-ARC write lock that was
silently swallowing import votes; 69 existing imports backfilled
- Application Record PDF: paragraph break between comments and decision notes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add missing indexes on journal_entry_lines (journal_entry_id, account_id)
and journal_entries (company_id, date): Bridgewater's ledger query took
7.5s, blew the 8s statement timeout, and rendered the JE/GL pages empty
- Paginate JE/GL page fetches past the 1000-row PostgREST cap (shared
fetchJournalEntries helper) and surface query errors instead of
swallowing them into an empty list
- New buildium-gl-sync edge function (scheduled nightly via pg_cron):
incrementally pulls new Buildium GL activity into accounting journal
entries via GET /v1/generalledger, reconstructing double-entry JEs by
grouping per-account entries by transaction id; watermark + 14-day
overlap window, dedupe on (company_id, external_source, external_id),
account mapping by external_id/code/name with auto-create for new
Buildium accounts
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Group the multi-period Income Statement by account category (Operating Income,
Administration, Utilities, Reserves Budget, …) with "Total for <category>"
subtotals, matching the Buildium layout, in the on-screen table, PDF, and CSV.
- New accounting.accounts.category column (nullable; null = ungrouped), seeded
from the local chart_of_accounts parent hierarchy.
- Editable in Chart of Accounts: single-edit (with datalist autocomplete) and
bulk-edit (blank = no change, __clear__ to unset).
- buildium-account-categories edge function pulls each account's parent-GL
category from Buildium (matched by code, fallback name) and backfills
accounting.accounts.category; idempotent and re-runnable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 4. Mirror the vendor insurance request flow for RV/boat renters:
- Migration: insurance fields on rv_boat_lot_rentals + rv_renter_insurance_requests
table + token-scoped lookup/submit SECURITY DEFINER RPCs (granted to anon).
- Edge fn send-rv-renter-insurance-request emails the renter a secure link
(reuses the vendor-insurance-request email template).
- Public page /rv-insurance/:token to submit carrier/policy/expiration + COI upload.
- "Request Insurance" button on each active rental + insurance status display.
DB RPCs verified end-to-end (rolled-back txn): submit matches token, updates the
rental, marks the request submitted. Edge function deployed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename the bill_approvals approver column from vendor_name to approver_name
across UI, hooks, types, and buildium-sync. Add a Chart of Accounts import
dialog (XLSX upload + column mapping + type-alias normalization) and a
"denied" status color.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Buildium bill imports left expense_account_id null on all bills because the
importer only read firstLine.GLAccountId, but the bill-line payload exposes the
GL id under GLAccount.Id (nested). chart_of_accounts.account_number already
stores the Buildium GL Id, so resolve the line's GL id from either shape before
mapping it. Re-syncing backfills existing bills via the update path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The supabase-js .functions.invoke() call from one edge function to
another doesn't reliably attach the apikey as Authorization, so the
inner send-transactional-email call was failing verify_jwt and
returning 401. Pass the service-role bearer header explicitly.
This is what was actually preventing bill-approval-vote-invite emails
from going out — every Notify Board flow logged 401s on the per-bill
sends, with zero rows ever landing in email_send_log for that template.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
UI
- Dashboard BillApprovalsCard: render approver name chips (color-coded
by vote status) per pending bill instead of leaving the approver
identity invisible.
- BillDetailPage: collapse the duplicate "Requested Approvers" card
into the existing "Approvers" table. Approve/deny handler now stamps
approved_by = auth.uid() for audit trail.
- MasterBoardDashboardPage: the "pending approvals for me" count was
filtering on a non-existent bill_approvals.approver_user_id column.
Replaced with a board_members.member_name -> bill_approvals.approver_name
join (matches the RLS policy).
- BillApprovalRequestDialog + AIInvoiceParserPage: bill_approvals inserts
now set created_by.
Database
- Rename public.bill_approvals.vendor_name -> approver_name. RLS policies
auto-rewritten by ALTER TABLE RENAME COLUMN; the column was misnamed
(it stores the approver's board-member name, never a vendor).
- Restore the bill_approval_email_tokens table + lookup_/record_
bill_approval_by_token RPCs. The original 20260520153409 migration
was never applied successfully; rewrote it to use approver_name and
to populate approved_by/created_by from board_members.user_id on
token-driven votes. Added the v2 migration that matches the live DB
state.
- accounting trigger: void on accounting.bills cascades to
public.bills.status='cancelled' (existing forward sync then drops the
accounting row per accounting.bill_should_mirror).
Edge function
- send-transactional-email: add bill-approval-request and
bill-approval-vote-invite templates (caller paths in BillApprovalsPage
+ send-bill-approval-invites referenced templates that weren't in the
registry, so every email 404'd). Restored the local copies of
election-invite, board-vote-invite, and the missing registry.ts so the
repo matches what's deployed. Deployed to send-transactional-email v35.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- buildium-sync now ensures every active association has an accounting company
after syncing associations. Once it exists, the existing DB triggers flow
units -> customers, owner ledger -> A/R + income, and bills -> A/P + expense
into Accounting automatically (closing the gap where Buildium synced only the
main dashboard, not Accounting).
- New buildium-opening-balances function: fetches an association's Buildium GL
trial balance as of a cutoff (default 2025-12-31, Accrual), maps GL accounts
to accounting accounts (flagging bank accounts), rolls prior-year P&L into
Retained Earnings, writes accounting.opening_balances, and posts the opening
GL entry. Idempotent; service-role gated.
Applied to 6 Buildium associations (opening balances + 2026 activity); all
balance. New columns/data applied to the project directly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace Lovable-bound email transport and auth webhook so the platform
sends all automated email through its own infrastructure.
- process-email-queue: drop sendLovableEmail/LOVABLE_API_KEY; send via the
Hostinger Email API (primary) with automatic SMTP fallback. Shared
transports added in _shared/hostinger-mail.ts and _shared/smtp-send.ts.
- auth-email-hook: verify Supabase's native Send Email hook signature
(Standard Webhooks via SEND_EMAIL_HOOK_SECRET) instead of Lovable's libs;
build the GoTrue verify URL; keep enqueue → process-email-queue.
- Recreate the 6 auth email templates under _shared/email-templates/ that
previously only existed in the deployed function.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove the Zoho Books integration (edge functions, sync libs, settings,
reports/overview, banking links, fees tab, import dialog); preserve fee
rules as a standalone FeesTab and the COA accounting_system classification.
- Financial Overview/Reports (staff + board) render the Accounting dashboard
and reports; board reports mirror the rich Accounting Reports.
- New Reserve Fund Schedule report + an is_reserve flag on accounts.
- Unify all report exports to a branded format (logo + centered header +
footer): shared ReportSheet (on-screen) and reportHeader (PDF). Budget vs
Actuals and Bank Reconciliation PDFs now match the reference layout.
- Render financial reports inline (no preview pop-up).
- Budget Management mirrors Accounting Budgeting (staff-accessible) with SPA
navigation; editable bills in the Accounting Bills page.
- Negative opening balances flow through to the GL and reports (allow negative
input; keep non-zero on save; signed CSV import).
- Upload a per-account trial balance via CSV on Opening Balances.
- Board members: read-only RLS access to their association's accounting ledger;
editable board-members panel on the association page; share vendor contacts
with the board (toggle + directory section).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>