Neonvil Logo
Budget Calculator
Neonvil Logo

contact@neonvil.com

© 2026 Neonvil Inc.


Budget Calculator
Back to Case Studies
FEATURED INSIGHT
One click by an underwriter creates the applicant in our identity provider, adds them to the portal group, and updates the case record — and we stopped worrying about what happens when any one of those three services hiccups. The backend absorbs the partial failures we used to chase manually.

NEONVIL & Confidential Insurance Wholesaler

A Case Study: An Invite-Only Underwriting Portal with an AI-Assisted Review Console
Underwriting Portal Platform

Business Outcome

A production underwriting platform with two faces — an invite-only applicant wizard and an internal review console with AI-assisted risk summaries — delivered on one Postgres, two authentication planes, and a keyless deployment pipeline.

Two Audiences, One Platform

An applicant portal for invite-only guests and an underwriter console for internal staff, sharing one database and one schema pipeline — no duplicated product logic.

Underwriters Own the Forms

Schema-driven questionnaires mean new product lines, new steps, and new financial-table columns ship as configuration — no frontend deploy required.

Tunable AI, Audited

Risk summaries run through per-agent prompt and model configs the review team can edit live, with every call tracked against a token-usage audit row.

Context & Challenges

A property-and-casualty insurance wholesaler needed to replace a manual underwriting intake with a self-serve applicant portal plus an internal review console. Same product, two distinct user populations — invite-only guests and internal underwriters — three parallel underwriting product lines running through one shell, and AI-assisted risk summaries the reviewers can tune without a deploy.

Four critical engineering challenges:

01

Idempotent cross-service invites: approving an applicant chains an identity-provider invite, a portal-group add, and a database status update — a 409 on re-run looks up the existing user and continues, a 403 still persists status so the database never drifts past the IdP.

02

Two identity planes in one repo: the applicant API validates JWTs with JWKS rotation and 5-second clock-skew tolerance; the admin API trusts a platform-injected principal plus a double-submit CSRF cookie with SameSite=Strict — one IdP, two trust models, no shared bearer tokens.

03

Schema-driven forms where the underwriting team owns the UI: a custom columns uiSchema extension reorders financial-table columns server-side, and step-scoped renderers handle comma-grouped currency — new product lines ship as configuration, not a frontend deploy.

04

Direct-to-blob uploads with live progress: fetch has no upload-progress API, so a SAS-URL handshake followed by a raw XMLHttpRequest PUT with per-row progress listeners carries 100 MB files without ever touching the Function.

Project Goals

Applicant Portal

A schema-driven multi-step application wizard with direct-to-blob uploads, pre-population from prior applications, and invite-only guest authentication.

Underwriter Console

An internal review UI with grouped application views, reviewer comment threads, AI risk summaries, and per-agent prompt and model configuration.

Dual-Plane Backend

Two Azure Functions apps on one Postgres — one JWT-gated for applicants, one CSRF-hardened for underwriters — with identity-provider invites, transactional email, and Azure OpenAI wired end-to-end.

Our Solution

Three layers, one Postgres. The applicant portal carries the guest-facing wizard. The underwriter console drives triage, review, and AI-assisted decisioning. The dual-plane backend mediates both — with two separate authentication models over one system of record.

APPLICANT UX
Applicant Portal

Schema-driven wizard with direct-to-blob uploads

Four-phase stepper (Start → Questionnaire → Uploads → Status) with URL-synced application ID for reload-safe resume

JsonForms questionnaire with a custom columns uiSchema extension, step-scoped renderers, and comma-grouped currency in array tables

Direct-to-Azure-Blob uploads via SAS handshake + raw XMLHttpRequest PUT — 100 MB files with per-row live progress

Pre-population from prior applications with a dismissible banner showing exactly which fields were carried over

REVIEW
Underwriter Console

Triage, grouped applications, AI-assisted summaries

Onboarding triage inbox with a one-click Approve that invites the guest into the IdP and adds them to the portal group

Grouped-by-user applications with reviewer comment logs and eight distinct application states driving status transitions

AI risk summaries with per-agent system prompt, user prompt template, model, temperature, and token-usage audit

PDF export of the full application record for offline review and archival

ORCHESTRATION
Dual-Plane Backend

Two auth planes, one system of record

Microsoft Graph
Azure OpenAI
ACS Email
Azure Blob

Applicant-facing Azure Functions: JWT verification with JWKS rotation and 5-second clock-skew tolerance

Admin-facing Azure Functions: platform-injected principal plus double-submit CSRF cookie with SameSite=Strict

Idempotent cross-service invites: a Graph 409 resolves via mail-filter lookup; a 403 still persists status so the DB never drifts past the IdP

One Postgres with JSONB questionnaire payloads, Prisma migrations gated in CI, keyless deploys via GitHub OIDC federation

Effort Allocation

100%

Applicant Portal UX (22%)

Underwriter Console UX (20%)

Backend Business Logic (18%)

Security, Auth & Data Modelling (16%)

Integrations (14%)

Infrastructure & CI/CD (10%)

Infrastructure & Technologies

FRONTEND

Next.js + Static Export

Chosen because Entra ID popup auth needs a stable client origin — static export on Azure Static Web Apps removes the SSR runtime and a long list of MSAL redirect race conditions in one move.

FORMS
📐

JsonForms + Ajv

Chosen so the underwriting team owns the questionnaires — schema-driven rendering ships new product lines as config, and the same Ajv schemas validate on the client and in Azure Functions.

AUTH
🔐

MSAL + Microsoft Entra ID

Chosen because the client mandated Entra ID for invite-only applicant access — sessionStorage caching, a dedicated auth-redirect page, and auth-code-aware storage flushing were all required to survive popup login on static hosting.

COMPUTE
🟧

Azure Functions v4 (Gen 2)

Chosen for scale-to-zero on two low-to-moderate-traffic surfaces, with first-party bindings for Blob Storage, Communication Services, and Entra ID — one platform covers the applicant API and the admin API as separate function apps.

DATA
🐘

PostgreSQL + Prisma

Chosen for native JSONB on dynamic questionnaire payloads without going NoSQL, plus relational integrity between applications, schemas, uploads, and AI notes — and a singleton client that survives Function cold starts without exhausting connections.

IDENTITY
🌐

Microsoft Graph API

Chosen as the single source of truth for guest invitations, directory lookups, and portal-group membership — avoids rolling a custom invite email plus account-provisioning flow on top of the IdP.

AI

Azure OpenAI (agents in DB)

Chosen so reviewers can tune AI — system prompt, user prompt template, model, temperature, and max-tokens live in a Postgres agents table; every call records token usage against an audit row.

Back to Case Studies