Proporio — Angular & Google Cloud SaaS

AI-assisted rental management for Belgian landlords: leases, receipts, maintenance requests, contractors and yield calculators.

Proporio — Angular & Google Cloud SaaS
Role
CTO
Stack
Angular 22 · Firebase · Cloud Functions
Market
Belgium, three regions
Status
Live

Context

A Belgian landlord gets work from everywhere: tenant e-mails, WhatsApp messages, bank transactions, lease deadlines, rent indexations and legal duties that differ by region. Finding out what needs doing is up to them. Proporio starts from the opposite principle: a landlord should never have to go looking for work.

Business challenge

Give landlords a single cockpit where spreadsheets, e-mails and paper letters used to coexist.

Solution

Every input — an e-mail, a message, a payment, a deadline — becomes an action card in a single feed, the Cockpit. A language model classifies the message, finds the property and lease involved and drafts the action; the landlord reviews, edits if needed and approves. The product is multi-workspace: landlords, tenants, contractors, building managers and agencies each have their own, and data moves between workspaces through projections, never through cross-workspace permissions.

Outcome

Live since June 2026, in four languages, with 96 card scenarios, 17 effect executors, open banking reconciliation and an assistant with 63 tools. Belgian law is modelled: 14 lease types, regional rules and health-index rent indexation.

My role

CTO

Architecture

Users

  • Angular SPA / PWA
  • Inbound e-mail
  • WhatsApp
  • Banks (open banking)

Application

  • Firebase Hosting · Auth · App Check
  • Cloud Firestore
  • Cloud Functions Gen2 · europe-west1
  • Cloud Scheduler: 38 jobs
  • Cloud Storage · KMS · Secret Manager
  • BigQuery

External services

  • OpenRouter (Claude, GPT, Gemini, Mistral…)
  • SendGrid · MJML
  • WhatsApp Cloud API
  • Bridge · Exthand (open banking)
  • Stripe · Stripe Tax
  • Sentry · PostHog

The flow, step by step

  1. Inbound

    An e-mail reaches the workspace address. SendGrid Inbound Parse forwards it to an HTTP function protected by a path secret and an address allowlist.

  2. Classification

    The message is stored; a Firestore trigger runs a two-level classification — domain, then subtype — through the OpenRouter gateway.

  3. Matching

    The sender is identified, the property and lease are found, and the scenario registry picks the best handling.

  4. Action card

    The summary is translated into four languages, a reply is drafted, and the card joins the Cockpit, pending or scheduled.

  5. Approval

    The landlord edits and approves. The executor registry applies each effect: reply, work order, payment reminder…

  6. Sending and audit

    Every five minutes, scheduled drafts go out through SendGrid; every action leaves an audit trail.

Data model

The main entities, their key fields and their relations.

Workspace

  • type (8 workspace types)
  • members{uid: role}
  • subscription
  • onboarding
  • 1—n Property
  • 1—n Tenant
  • 1—n ActionCard

Property

  • buildingUID
  • keys (subcollection)
  • meters (subcollection)
  • 1—n Contract
  • 1—n Intervention
  • 1—n Loan · Expense

Contract

  • propertyUID
  • tenantIds[]
  • Belgian lease type
  • rent · deposit
  • n—n Tenant
  • 1—n PlannedPayment
  • 1—n PlannedIndexation

Tenant

  • identity
  • contact details
  • language
  • n—n Contract

InboundMessage

  • source (e-mail, WhatsApp)
  • sender
  • content
  • 1—n ActionCard

ActionCard

  • source · intent · domain
  • priority · status
  • trustTier
  • summary in 4 languages
  • 1—0..1 MailDraft

BankTransaction

  • bank connection
  • amount · reference
  • reconciliation status
  • n—0..1 PlannedPayment

Full technical sheet

Languages
TypeScript 6 (front end), TypeScript 5.7 (functions)
Front end
Angular 22, Angular Material and CDK, Tailwind 3
Back end
Cloud Functions Gen2 on Node 24, europe-west1, zod 4 validation
Database
Cloud Firestore, data stored per workspace (workspaces/{id}/…)
Authentication
Firebase Auth (e-mail, Google), custom claims, App Check reCAPTCHA v3
Payments
Stripe: per-property, per-seat and per-unit subscriptions, Stripe Tax
Scheduled jobs
38 Cloud Scheduler jobs, Europe/Brussels time zone
Real time
Firestore onSnapshot listeners
AI
Single OpenRouter gateway: classification, drafting, translation, contract import, 63-tool assistant
Messaging
SendGrid and MJML, WhatsApp Cloud API, FCM push notifications
Banking
Open banking through Bridge and Exthand, sessions sealed with Cloud KMS
CI/CD
21 GitHub Actions workflows, automatic deployment of the development environment
Tests
Karma and Jasmine (820 specs), Jest 30 (506 tests), tested Firestore rules, Playwright
Quality
ESLint 10, Prettier, quality ratchets, CodeQL, Gitleaks
Observability
Sentry (front end and functions), PostHog, BigQuery export, system health events
Languages (UI)
French, Dutch, German and English (ngx-translate)
Security and GDPR
Deny-by-default Firestore rules, HMAC-signed webhooks, DAST scan, consent log, cascading deletion, scheduled retention

Key features

  • Cockpit

    96 scenarios and 17 effect executors; a daily sweep surfaces upcoming deadlines.

  • Lease lifecycle

    Guided creation or AI import, health-index indexation, check-in inspection, termination.

  • Bank reconciliation

    Automatic match above 0.9 confidence; below that, a review card.

  • Work orders

    Repairs, maintenance, quotes and contractors.

  • Dedicated portals

    Tenant (PWA), contractor, building manager with general meetings, agency with CRM and mandates.

  • Assistant

    63 tools; the ones that change data ask for explicit confirmation.

Problems solved

  1. Cold-start memory

    ProblemEvery function loaded the whole bundle, about 243 MiB of memory: more than 500 requests were killed by the 256 MiB limit.

    FixA global 512 MiB memory floor, documented where the functions are exported.

  2. Replayed trigger

    ProblemGen2 triggers are delivered at least once: a repair request sometimes created two work orders.

    FixCard ID derived from the event ID, and create() instead of set(): the second run fails cleanly.

  3. UTC day versus Brussels day

    ProblemIdempotency keys used the UTC day while the cron jobs run on Brussels time.

    FixDates computed in Europe/Brussels with Intl.DateTimeFormat, tested across daylight-saving changes.

  4. Front-end state race

    ProblemReloading a list overwrote a local change Firestore had not confirmed yet.

    FixPending writes are tracked with a 30-second lifetime.

  5. Hardened inbound webhook

    ProblemThe SendGrid address allowlist only logged unknown callers.

    FixAfter six months of logs with no false positive, unknown callers are rejected (403).

Technical choices

Choice Why
One LLM gateway Switch models per task without redeploying, track costs in a registry and type the errors.
Projections, not cross-workspace permissions A third party never reads another workspace’s documents; revoking the link cuts the projection.
Bank secrets apart, sealed with KMS Firestore rules apply to whole documents: secrets live in a separate collection.
Proof of WhatsApp number ownership A typo must never send a tenant’s arrears to a stranger.

Timeline

  1. August 2024 First commit
  2. October 2025 Multi-workspace model and Stripe
  3. April 2026 Cockpit, first version
  4. June 2026 Stable production release
  5. July 2026 WhatsApp Cloud API
  6. August 2026 Open banking for all four profiles

In numbers

2,821
commits, 1,835 of them mine
659
Cloud Functions
1,326
test files
4
languages

Taken from the project’s source code and Git history on 8 October 2026. No usage or revenue figures are published.

Related projects

SaaS
Jan 2024 — present
StreamCrea — Creator dashboard
Twitch, YouTube and Kick sync, multi-network publishing and a subscriber blog.
PHP, Laravel, Livewire, Stripe
View project
SaaS
Sep 2023 — present
Egonix Cards — NFC business cards
NFC business cards: tap the card, the contact lands in a space where it can be exported, segmented and followed up.
Laravel, Livewire, Filament, Stripe, TailwindCSS
View project
SaaS
Jan 2024 — present
Finnexus — Laravel Finance project
Enterprise finance SaaS with analytics, cash-flow forecasts and treasury insights.
Laravel, Livewire, TailwindCSS, Stripe
View project
SaaS
Jan 2024 — present
Discobot — Discord bot platform
One Discord bot, six plugins configured per server from a web dashboard.
Laravel, Node.js, Discord.js, Stripe
View project

Available for PHP / Laravel / WordPress / Silverstripe missions in Belgium and remote EU.