33 Commits

Author SHA1 Message Date
admin b15ed4bff8 Avria Sign: add SHA-256 document hash to certificate of completion
The Certificate of Validation claimed "cryptographic proof ... and integrity"
but showed no hash. Add a real SHA-256 of the original document to the
certificate page so the integrity claim is backed by a verifiable digest.
(Deploy via MCP alongside the base-flow fix.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:58:27 -04:00
admin 71cc71f89f Inbound invoices: recipient-alias routing + parser hardening
parse-invoice: guard oversized PDFs (>18MB → clear "too large, saved for manual
entry" message) and surface the AI gateway's actual error instead of a bare
status code.

inbound-bill-email: route to an association by the recipient alias
(<alias>@bills.avriamail.com, via associations.inbound_alias) in addition to the
sender's vendor mapping; fix extractEmail (bare addresses were mis-split, e.g.
invoices@x → s@x); surface parse-invoice's real error in the inbox. Deployed via
MCP; migration associations_inbound_alias adds + populates the aliases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:13:49 -04:00
admin a65c135122 Accounting: auto-create record-only bills for no-bill vendor payments (import mode)
Buildium often records vendor payments as direct checks (Dr Expense/Cr Bank)
with no bill. For import-mode companies post_bill_gl no-ops, so a bill is a
record only. New fn accounting.autocreate_nobill_vendor_bills() creates a paid
record-only bill for each such buildium_gl payment (vendor resolved by payee,
idempotent by external_id); buildium-gl-sync calls it per import-mode company
after each pull. No GL impact, no double-count.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 12:57:28 -04:00
admin 393268dd04 Vendor profile email: add where-to-send-invoices block
Below the Submit vendor profile button, instruct vendors to email bills to
ap@avriacam.com or mail them to the association's mailing address, c/o Avria
Community Management, LLC. The address is resolved from the vendor's
association (association_id, falling back to association_ids[0]).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 12:20:12 -04:00
admin 2c50e96fbd Email: default automated sender to notifications@avriamail.com
The retired no-reply@avriamail.com had no email_senders row, so the
queue dispatcher 500'd on every run. Point DEFAULT_AUTOMATED_FROM at
notifications@avriamail.com (the sole remaining sender). The
AUTOMATED_EMAIL_FROM secret was set to match and the function deployed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 12:03:18 -04:00
admin 9aa1f94eb4 Accounting: categorize register transactions from Buildium GL lines
partymap mode now also resolves each Buildium transaction's dominant
income/expense account (from its Journal lines) to a local category, staged
alongside the party. Used to backfill accounting.transactions.category on the
materialized bank register. Applied to Village Woods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:16:00 -04:00
admin 0faee9994d Accounting: partymap mode + register payee backfill
Adds "partymap" mode to buildium-payee-backfill: resolves each Buildium GL
transaction to a local vendor (by name) / customer (by unit_number) and stages
it in accounting.buildium_party_map. The materialized bank register
(accounting.transactions) is then backfilled in SQL by bridging each register
row to its journal-entry bank line (bijective row-number pairing within
date/amount/side groups, so same-amount/same-day payments each get a distinct
owner) and pulling the resolved vendor/customer + name from staging.

Applied to all five Buildium-imported associations (Village Woods, Bent Oak,
Village Grove, Bridgewater, Casuarina).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 19:44:42 -04:00
admin 12e551f578 Accounting: add account/txn detail modes to buildium-payee-backfill
account mode lists a single account's ledger entries; txn mode reconstructs
one transaction's full double-entry across accounts. Used to trace the VW
5098 discrepancy to a missing 2025-12-31 reserve-funded reclass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:27:00 -04:00
admin e999890ee5 Accounting: add report mode to buildium-payee-backfill
report mode pulls /v1/generalledger signed balances per account for the
window so imported books can be diffed against Buildium's authoritative GL
to verify completeness.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:18:34 -04:00
admin 3a7e08fb78 Accounting: buildium-payee-backfill edge function
Re-pulls Buildium GL transactions and backfills payor/payee names onto
imported journal_entries.description (matched by external_id). Vendor for
Bill/Check/EFT via PaymentDetail.Payee; owner for Charge/Payment/ApplyDeposit
resolved from UnitId via /v1/associations/owners. Idempotent; modes
sample/dry/apply. Used to backfill Village Woods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:12:00 -04:00
admin 10cd24e738 Bank feeds: replace Plaid with Stripe Financial Connections
Swap the bank-linking + transaction-download integration from Plaid to
Stripe Financial Connections (you're already on Stripe for payments).

- accounting.stripe_bank_connections table (mirrors plaid_connections)
- stripe-financial-connections edge function: create_session / save_account
  / sync / disconnect, using per-association keys from stripe_account_mappings
  (handles connected accounts via Stripe-Account + stripeAccount on the client)
- lib/stripeBank.ts: client wrappers + the Stripe.js collectFinancialConnections
  Accounts flow
- AccountingBankingPage: Connect/Sync/Disconnect now drive Stripe FC; removed
  react-plaid-link usage and the PlaidLinkButton
- Integrations page wording updated
- Imported transactions land uncategorised in the bank feed (credit/debit by
  amount sign) for matching, same as before

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:27:05 -04:00
admin 5aef967b74 Buildium GL sync: keep import-mode bank registers current
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>
2026-06-13 10:10:25 -04:00
admin df8623ff9f buildium-gl-sync: include inactive bank-account GL ids from /v1/bankaccounts
/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>
2026-06-12 19:52:21 -04:00
admin 28c3c7bd0a Bills import: degrade gracefully when Buildium API key lacks Vendors permission
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>
2026-06-12 18:58:13 -04:00
admin cc5f70bc5b Bills import: A/P cutover guard — only post JEs dated after the GL watermark
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>
2026-06-12 18:46:24 -04:00
admin 25064d8418 Direct Buildium A/P import: bills, payments, one-off checks via GL Account Map
- 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>
2026-06-12 18:43:58 -04:00
admin c1fad194f7 ARC imports: record Buildium decision votes + richer decision notes; PDF spacing
- 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>
2026-06-12 14:26:48 -04:00
admin ff65c8a656 Buildium GL account map: strict account links, separate pull/push charges
- buildium_gl_account_links + buildium_unmapped_gl_accounts tables (strict, hold-and-flag)
- buildium-sync: pull charges syncType, account-first push resolution, no fuzzy matching, push dryRun
- buildium-gl-sync: links-only resolution, watermark held while unmapped accounts exist
- GL Account Map settings tab + Pull Charges card + unmapped results panel

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 14:07:18 -04:00
admin abd46bcb2b Hostinger Reach integration UI + ARC Buildium matching, drop Mailchimp
- HostingerReachPage (replaces MailchimpPage): connect Reach via
  reach-connection, per-association segment sync via reach-sync
- ARC Applications: Buildium import review/matching updates
- buildium-import-stage/apply: latest staging + apply changes (already
  deployed to Supabase)
- migrations: hostinger_reach_integration + arc_finalized_lock service
  role (already applied to live DB)
- CI: note that deployment is VPS-side polling (auto-deploy.sh cron)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 23:07:30 -04:00
admin f5f6285bbd Accounting: fix empty JE/GL pages + nightly Buildium GL pull sync
- 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>
2026-06-11 22:12:38 -04:00
admin 4f0ac97e83 Income Statement: Buildium-style category subgroups
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>
2026-06-10 22:34:58 -04:00
admin 308af20aa1 RV/Boat Lots: request renter insurance (vendor-style flow)
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>
2026-06-07 20:16:31 -04:00
admin ea8cf6efb6 Merge remote-tracking branch 'origin/main' into accounting-sales-receipts-coa-sync-expenses
# Conflicts:
#	src/integrations/supabase/types.ts
#	src/pages/BillDetailPage.tsx
2026-06-06 23:24:45 -04:00
admin af67e2fb9a Accounting: rename bill_approvals.vendor_name→approver_name + COA import dialog
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>
2026-06-06 23:04:29 -04:00
admin 096cac6b0b Merge pull request #6 from renee-png/accounting-sales-receipts-coa-sync-expenses
Accounting: sales receipts, COA dashboard sync, accrual A/P, manual deposits, per-association COA, bill-approval sync fix
2026-06-05 20:52:43 -04:00
admin 756ebce121 buildium-sync: robustly resolve bill line GL account into expense_account_id
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>
2026-06-04 20:17:07 -04:00
admin 6376d5cc7e send-bill-approval-invites: forward Authorization on inner invoke
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>
2026-06-04 17:37:11 -04:00
admin 2c723410a4 Bill approvals: surface approvers, fix email path, schema cleanup
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>
2026-06-04 17:17:05 -04:00
admin bd5caf5415 Merge pull request #3 from renee-png/email-cutover-and-accrual
Migrate email pipeline off Lovable + branded auth emails
2026-06-03 02:40:35 -04:00
admin f7dc5d8177 Buildium -> Accounting: auto-provision companies + opening-balance migration
- 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>
2026-06-03 02:31:21 -04:00
admin b1486a0b2a Migrate email pipeline off Lovable + branded auth emails
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>
2026-06-02 23:07:26 -04:00
admin e302fb91f0 Accounting platform: remove Zoho, unify reports, board access, vendor sharing
- 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>
2026-06-02 18:29:31 -04:00
admin 183fe0a93c Add ACMCC app source, Supabase backend, and project config
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 20:19:26 -04:00