← All work

Pulse CRM

The eligibility and pricing engine behind a reverse-mortgage call center.

Next.jsReactTypeScriptTailwind CSSSupabasePostgreSQLRow-Level SecurityEdge Functions (Deno)TanStack Queryreact-hook-formZodshadcn/uiRadix UIPlaywrightVitestSentryPostHog
Role
Sole primary engineer
Period
Mar 2025 – Apr 2026
Status
Production
Stack
Next.js 16, Supabase Postgres, Deno Edge Functions.

323,695

Lines in src/

429

SQL migrations

143

RLS-protected tables

17m17s

10k-property eligibility benchmark

1,642

Commits

5

Custom ESLint rules

The problem

Ennkar's loan officers manage reverse-mortgage (HECM) refinance pipelines: qualifying borrowers against FHA program rules, valuing properties, importing large third-party dial lists, and calling under telemarketing compliance constraints. Before Pulse, this was spreadsheet-and-phone work — no shared source of truth for pricing, no audit trail for who could call whom, and no way to run eligibility across a dial list faster than an agent could dial it by hand.

Constraints

  • Loan math has to be exactly right — there is no acceptable rounding error in a regulated financial calculation.
  • Dial lists arrive as inconsistent third-party CSVs that need fuzzy field mapping, not a fixed schema.
  • Telemarketing compliance (TCPA) constrains when and how a borrower can be contacted, and that has to be enforced by the system, not by agent discipline.
  • The team is small enough that there is no dedicated QA function — correctness has to be enforced by tooling, not by process.

What I built

A Next.js 16 application on Supabase Postgres with no application-server API tier: pages call Postgres directly through typed queries, Postgres RPCs, and Deno Edge Functions, with Row-Level Security enforced on every public table. Two route groups — protected and public — cover 53 page routes. There are zero 'use server' files in the codebase, a documented architectural rule rather than an oversight: the database, not a Next.js API layer, is the authority.

  • A unified loan derivation engine (loan-field-engine.ts) that produces rates, PLF matches, principal limits, and balances consistently across the client form, CSV import, and nightly pipelines — replacing three implementations that used to drift.
  • A batch eligibility pipeline benchmarked at 10,000 properties in 17m17s across 130 parallel windows with zero defects, with window claim caps, continuation dedup, and same-run idempotency so a rerun cannot double-process a property.
  • A jurisdiction fee engine covering all 50 states with per-county research.
  • TCPA-aware call-window scheduling and a reminder-delivery ledger that dedupes minute-accurate notifications.
  • Integrations with FRED for interest rates, DataTree (with RentCast fallback) for property valuation, Gmail and RingCentral for communications, and a RingCentral speech-to-text webhook — the only shipped AI-adjacent surface in the system.

Architecture

The system deliberately has no general-purpose API tier. Client code queries Supabase directly under RLS, calls Postgres RPCs for anything that needs to run as one transaction, and calls Deno Edge Functions for anything that needs a runtime outside Postgres — webhook receivers, third-party API calls, and long-running batch work. As of the 2026-08-24 snapshot the database exposes 143 public tables, all under RLS, roughly 339 callable functions and procedures, and 40 Edge Functions, coordinated by 20 pg_cron jobs. An earlier internal audit tracked reducing SECURITY DEFINER functions exposed to the authenticated role from 238 to 91 across ten labelled phases — authorization hardening treated as a measured program, not a one-time review.

Decisions and tradeoffs

Decision

Write a custom ESLint plugin (eslint-plugin-internal) with five project-specific rules, two of which stop the loan engine from overwriting factual source inputs or basis fields without an explicit canEngineWrite() gate.

Because

A real production defect — Number.isFinite(Number(x)) evaluating a malformed value as finite — let a 0% ARM cap freeze rates. Code review had already missed it once.

Trade-off

Every engineer touching the loan engine now works inside a stricter set of rules than the rest of the codebase, which adds friction to changes in that area by design.

Decision

Route all data access through Supabase RPCs and Edge Functions instead of a Next.js API layer.

Because

It keeps authorization logic in one place (Postgres RLS and grants) instead of duplicated across an app-server API and the database.

Trade-off

Business logic that would be trivial in a typed server function has to be written in PL/pgSQL or Deno, which is a smaller hiring pool and a steeper local-development curve.

Note

A multi-tenancy isolation harness (Storage, Realtime, and cache isolation, tested in vitest.isolation.config.ts) exists in the codebase. It is designed and test-harnessed, not shipped — Pulse currently serves one tenant.

Outcome

RLS-protected public tables
143
Callable functions / procedures
~339
Edge Functions
40
SQL migrations
429
10k-property benchmark
17m17s, 130 windows, 0 defects
Legacy API routes removed
~89 → 20
Eligibility-report storage after retention pruning
~21GB → ~3.5GB

As of 2026-08-24

Pulse CRM is the deepest system in this portfolio: the largest codebase, the most tables, and the only project with static analysis purpose-built to prevent a specific class of financial defect. It has no public source and no publishable screenshot — every local capture contains real borrower data — so this case study leans on measured system figures rather than imagery.

Want the full picture, or open to talking about your own project?