No spec document lives in the repo; reconciled against the recorded MVP decisions and preferences (project context). Live code audited 2026-10-12. Stripe account audited the same date.
1. Delivered and verified in code
DeliveredMulti-tenant row-level security
Every customer entity carries a tenant_id with org-scoped read/write rules and an admin fallback. Evidence: base44/entities/Property.jsonc, Tenancy.jsonc, RentInvoice.jsonc (rls blocks).
Full data model
All planned entities present (Property, Tenant, Tenancy, Contract, Reference, Guarantor, RentInvoice, Payment, MaintenanceIssue, Jurisdiction) plus Branch, Team, Staff, Role, AuditEvent, CalendarEvent, Notification, ComplianceCertificate, ContractTemplate, PropertyExpense, HubspotSync, GuarantorAgreement.
Jurisdiction-aware core
Jurisdiction entity with UK/Europe/USA phases, linked from Organisation, Property, Tenancy and Contract.
Enterprise Settings control plane
Settings sections: OrganisationSettings, UsersRoles, RolesManager, BranchesManager, PermissionsMatrix, PlanBilling (src/pages/Settings.jsx).
RBAC server-side gating
checkPermission enforced across privileged functions: saveOrganisation, removeOrganisationMember, assignOrganisationRole, enforceEntitlement, logInvoiceToSheets, syncSubscriptionToHubspot (base44/shared/permissions.ts).
Entitlement enforcement
enforceEntitlement + confirmSubscription apply plan limits and activation server-side.
Stripe checkout replay guard
confirmSubscription records consumed_checkout_sessions on the Organisation entity, preventing replay of a paid session.
Contract signature centralised
signContract verifies auth + tenant email, then flips status to fully_signed server-side; no client-gated status change (base44/functions/signContract/entry.ts).
Gmail header sanitisation
sanitizeHeader strips CRLF and Unicode line separators; sendRentReminders routes through sendGmail (base44/shared/gmailSend.ts).
Sheets formula-injection guard
logInvoiceToSheets prefixes = + - @ with an apostrophe under USER_ENTERED (FORMULA_PREFIX).
Safe invoice numbers
generateMonthlyInvoices builds INV-YYYYMM-NNNN from fixed templates; no user-supplied invoice_number.
Finance page property-only
src/pages/Finance.jsx contains no MRR, subscription or HubSpot deal references.
HubSpot revenue sync
syncSubscriptionToHubspot + workflows/SubscriptionToHubspotDeal.jsonc.
Help and Settings relocated to header
Removed from the sidebar and added as header icon buttons in src/components/app/AppShell.jsx.
2. Resolved this session — GBP pricing mismatch
DeliveredRoot cause
The marketing Pricing page displayed GBP 10 / 35 / 250 / 350 per month, but Stripe held GBP prices at 29 / 79 / 199 / 399, and the in-app PlanBilling panel showed a third set (10 / 29 / 249 / 499). createSubscriptionCheckout resolves the price by the active lookup key sa_<plan>_monthly, so the charged amount followed Stripe, not the display.
Fix applied
Created new active GBP recurring prices at the displayed amounts (GBP 10 / 35 / 250 / 350) with the canonical lookup keys, moved each product default_price to the new price, and archived the previous 29 / 79 / 199 / 399 prices. Aligned src/components/settings/PlanBilling.jsx PLANS to GBP 10 / 35 / 250 / 350. Checkout now charges the displayed GBP amounts.
Evidence
src/components/marketing/PlanComparisonTable.jsx (display), base44/functions/createSubscriptionCheckout/entry.ts (lookup-key resolution), src/components/settings/PlanBilling.jsx (PLANS aligned), Stripe price records sa_solo_monthly / sa_professional_monthly / sa_agency_monthly / sa_business_monthly (GBP, active).
3. Gaps still open
Open gapBranch / team settings inheritance
Branch and Team entities have no inheritance field or logic; settings do not cascade from Organisation to Branch to Team.
Security Centre and LegalAcceptanceRecord
No entities, files or UI for a Security Centre or legal acceptance records exist in the codebase.
Solo advanced-features entitlement
Spec wants Solo to include AI assistants, integrations and the full finance/compliance suite; entitlement gating for Solo was not audited and should be verified so Solo is not wrongly restricted.
4. Implemented but not yet test-run
Not test-runSubscription payment to HubSpot deal sync
syncSubscriptionToHubspot + workflows/SubscriptionToHubspotDeal.jsonc present; end-to-end flow not test-run.
Rent invoice to Google Sheets logging
logInvoiceToSheets present with the formula-injection guard; not test-run against a live sheet.
Security scan re-run
Remediations (replay guard, signContract, header sanitisation, RBAC gating) landed; the security scan has not been re-run to confirm clean.