Skip to content
All projects

Insurance platform · .NET · React

Apólice

Insurance end to end, from quote to claim payment: auditable premium calculation, events that are never lost and a documented API, in .NET 10 and React.

Client
Personal open-source project
Role
Software Engineer — independent project
Year
2026
Technologies
  • C#
  • .NET 10
  • ASP.NET Core
  • EF Core
  • React
  • TypeScript
  • PostgreSQL
  • Aurora DSQL
  • RabbitMQ
  • Amazon SQS
  • AWS Lambda
  • Terraform
  • xUnit
  • Testcontainers
  • Playwright
  • GitHub Actions

Context

Open-source insurance platform, built in October 2026, that covers the life cycle of an Auto, Home and Life policy: quote, issuance, endorsement, cancellation and claim. Broker, claims analyst and admin get resource-based authorization, and a broker only sees their own book. All data is fictitious, with a demo sign-in by persona. The project takes the insurance domain I worked with on the front-end of i4Pro's ERP, where I consumed .NET APIs, to a C# and .NET back-end, and was run with Spec-Driven Development: a versioned specification as the source of truth, a design guide, 8 ADRs and an independent review of each layer before merging.

Challenge

Insurance is a domain where every cent has to add up: the premium depends on per-product factors, an endorsement charges or refunds pro rata, cancellation has three refund rules and a claim goes through review, approval and payment with a record of who did what. The challenge was to deliver this whole cycle as a real production system: business rules that are testable and isolated from infrastructure, events that are never lost and never duplicate effects, protection against access to another broker's book, observability and automated deployment on AWS at close to zero cost.

Results

passing .NET tests: 548 domain, 398 application, 32 architecture and 165 integration tests with real PostgreSQL and RabbitMQ
1,143
line coverage in the domain, and about 99.9% in the application layer
~99%
front-end tests with Vitest, Testing Library and axe, plus a Playwright E2E test of the main flow against production
168
production cost on AWS, within the free tier, with a budget and an alert in place
~US$ 0

Key deliverables

  1. 01Architected the API in C# and .NET 10 with Clean Architecture (Domain, Application, Infrastructure, Api and Worker), tactical DDD with aggregates, value objects and domain events, and the Strategy pattern for each product's pricing, with 32 architecture tests (ArchUnitNET) covering the dependencies between layers and the conventions for handlers and aggregates.
  2. 02Developed 32 versioned REST operations under /api/v1 with ASP.NET Core Minimal APIs, OpenAPI 3.1 with Scalar and ProblemDetails errors (RFC 9457), using EF Core 10 for writes, under optimistic concurrency, and Dapper for reads, with keyset pagination (CQRS-lite).
  3. 03Implemented a transactional outbox with idempotent consumers: RabbitMQ locally and Amazon SQS with a dead-letter queue in production, where a scheduled relay republishes whatever is still pending.
  4. 04Secured the API following the OWASP API Top 10: 15-minute JWTs with a rotating refresh token in an HttpOnly cookie and reuse detection, another broker's resource answering 404 (anti-BOLA), rate limiting, Idempotency-Key, security headers and an audit trail of sensitive actions.
  5. 05Built the front-end in React 19 and strict TypeScript, with TanStack Query, React Hook Form + Zod, Tailwind CSS 4 and Radix UI, mobile first, with light and dark themes and a WCAG 2.1 AA accessibility target checked with axe in the tests.
  6. 06Automated delivery on AWS with Terraform and GitHub Actions through OIDC (.NET 10 arm64 Lambda, Aurora DSQL with IAM authentication, SQS, EventBridge and secrets in SSM), with 1,143 .NET tests, 165 of them integration tests with Testcontainers, and a Playwright E2E test of the main flow passing against production.
  1. Persona sign-in

    In the demo sign-in, four personas get in without a password: two brokers, a claims analyst and an admin, each with its own scope. Fictitious data.

    Apólice sign-in screen on a computer. On the left, the navy panel with a guilloché engraving, the line Da cotação ao sinistro, cada apólice com histórico completo (from quote to claim, every policy with a full history), the platform description for brokerages and an AUTO-2026-000042 policy card labeled as an illustrative example with fictitious data. On the right, Entrar (sign in), with four demo personas, Ana Ribeiro (broker), Bruno Lima (broker), Carla Souza (claims analyst) and Diego Martins (admin), each with its own scope, the email and password sign-in and links to the API documentation and to the code on GitHub.
    Apólice sign-in screen on a computer. On the left, the navy panel with a guilloché engraving, the line Da cotação ao sinistro, cada apólice com histórico completo (from quote to claim, every policy with a full history), the platform description for brokerages and an AUTO-2026-000042 policy card labeled as an illustrative example with fictitious data. On the right, Entrar (sign in), with four demo personas, Ana Ribeiro (broker), Bruno Lima (broker), Carla Souza (claims analyst) and Diego Martins (admin), each with its own scope, the email and password sign-in and links to the API documentation and to the code on GitHub.
  2. Portfolio overview

    The dashboard shows the book within the signed-in user's scope: active policies, premium written over the last 12 months, conversion, loss ratio and the split by product. Fictitious data.

    Portfolio overview dashboard for broker Ana Ribeiro, scoped to her own book: 12 active policies, R$ 27.5k of premium written in October, 2 open quotes, a 60.0% conversion rate over 90 days, 2 open claims and a 33.5% loss ratio over 12 months, against a target of up to 60%; the premium written chart for the last 12 months, with R$ 53.1k in the period, the current month in gold and a monthly average of R$ 2.3k; and the split by product, Auto with 7 active policies (90%), Home with 3 (7%) and Life with 2 (3%). In the navy sidebar, the fictitious brokerage Ribeiro & Associados, the menu and the saved queues.
    Portfolio overview dashboard for broker Ana Ribeiro, scoped to her own book: 12 active policies, R$ 27.5k of premium written in October, 2 open quotes, a 60.0% conversion rate over 90 days, 2 open claims and a 33.5% loss ratio over 12 months, against a target of up to 60%; the premium written chart for the last 12 months, with R$ 53.1k in the period, the current month in gold and a monthly average of R$ 2.3k; and the split by product, Auto with 7 active policies (90%), Home with 3 (7%) and Life with 2 (3%). In the navy sidebar, the fictitious brokerage Ribeiro & Associados, the menu and the saved queues.
  3. Quote with live pricing

    At the coverage step of the 5-step wizard, the premium is recalculated on every change, and the calculation breakdown shows every coverage, every factor and the IOF tax. Fictitious data.

    New quote · Auto insurance wizard at step 4 of 5, Coverages, with Product, Insured and Risk completed and a draft-saved notice. The coverage list shows collision, fire and theft and third-party property damage as mandatory, third-party bodily injury switched off with an Ative para calcular (turn on to price) hint and glass, headlights and mirrors switched on with a fixed R$ 3,000.00 limit. Next to it, the live Cálculo do prêmio (premium calculation) panel: the annual premium of each coverage, the BA/SE overnight-region factor of ×1.10, a net premium of R$ 5,051.20, 7.38% IOF tax (R$ 372.78) and the navy total premium block, R$ 5,423.98, or up to 10 interest-free payments of R$ 542.39, with the quote valid until 11/21/2026.
    New quote · Auto insurance wizard at step 4 of 5, Coverages, with Product, Insured and Risk completed and a draft-saved notice. The coverage list shows collision, fire and theft and third-party property damage as mandatory, third-party bodily injury switched off with an Ative para calcular (turn on to price) hint and glass, headlights and mirrors switched on with a fixed R$ 3,000.00 limit. Next to it, the live Cálculo do prêmio (premium calculation) panel: the annual premium of each coverage, the BA/SE overnight-region factor of ×1.10, a net premium of R$ 5,051.20, 7.38% IOF tax (R$ 372.78) and the navy total premium block, R$ 5,423.98, or up to 10 interest-free payments of R$ 542.39, with the quote valid until 11/21/2026.
  4. The policy as a certificate

    The policy is shown as a certificate, with coverage period, premium, installments, coverages, a timeline and the PDF, claim, endorsement and cancellation actions. Fictitious data.

    Detail of policy AUTO-2026-000001 presented as a certificate: a navy band with an engraving and a gold rule, Active status, insured Pedro Henrique Rocha with a masked CPF, a R$ 145,000.00 vehicle, model year 2023, and the Download PDF, Open claim, Endorse and Cancel actions; below, the coverage period from 02/22/2026 to 02/22/2027 with a 242-of-365-days bar, a total premium of R$ 7,885.57, 10 payments of R$ 788.55 and a main limit of R$ 145,000.00. Further down, the Coverages, Installments, Endorsements, Claims and Communications tabs, with the coverage table and each annual premium, and the policy timeline with the emails sent.
    Detail of policy AUTO-2026-000001 presented as a certificate: a navy band with an engraving and a gold rule, Active status, insured Pedro Henrique Rocha with a masked CPF, a R$ 145,000.00 vehicle, model year 2023, and the Download PDF, Open claim, Endorse and Cancel actions; below, the coverage period from 02/22/2026 to 02/22/2027 with a 242-of-365-days bar, a total premium of R$ 7,885.57, 10 payments of R$ 788.55 and a main limit of R$ 145,000.00. Further down, the Coverages, Installments, Endorsements, Claims and Communications tabs, with the coverage table and each annual premium, and the policy timeline with the emails sent.
  5. Simulated cancellation

    Before confirming, the cancellation simulates the refund under the rule of the reason: the short-rate table when the insured asks, pro rata otherwise. Fictitious data.

    Cancel policy RESID-2026-000001? dialog over the policy detail, warning that cancellation ends coverage today and cannot be undone. Three reasons: requested by the insured, selected, refunded by the short-rate table, and insurer's initiative and non-payment, refunded pro rata for the remaining days. The simulation shows the short-rate method, the date 10/22/2026, 226 of 365 days elapsed, 80% retained by the table, a current net premium of R$ 2,311.50 and a refund of R$ 462.30, with a note that the IOF tax is not refunded and the Back and Cancel policy buttons.
    Cancel policy RESID-2026-000001? dialog over the policy detail, warning that cancellation ends coverage today and cannot be undone. Three reasons: requested by the insured, selected, refunded by the short-rate table, and insurer's initiative and non-payment, refunded pro rata for the remaining days. The simulation shows the short-rate method, the date 10/22/2026, 226 of 365 days elapsed, 80% retained by the table, a current net premium of R$ 2,311.50 and a refund of R$ 462.30, with a note that the IOF tax is not refunded and the Back and Cancel policy buttons.
  6. Claim handling

    From the analyst's view, a claim under review brings together the automatic triage, the history and the approve or deny actions, here in dark theme. Fictitious data.

    Claim SIN-2026-000004 in dark theme, from analyst Carla Souza's view: Under review status, policy AUTO-2026-000003 for Beatriz Carvalho Mendes and the Deny and Approve buttons. The Occurrence card shows the glass, headlights and mirrors coverage, a claimed amount of R$ 1,850.00, a R$ 3,000.00 limit and the description of a cracked windshield; the History logs Claim opened by Ana Ribeiro and Review started by Carla Souza, with date and time; the automatic triage shows a score of 0 out of 100, low risk, with no alerts; and the policy card shows number, insured and broker.
    Claim SIN-2026-000004 in dark theme, from analyst Carla Souza's view: Under review status, policy AUTO-2026-000003 for Beatriz Carvalho Mendes and the Deny and Approve buttons. The Occurrence card shows the glass, headlights and mirrors coverage, a claimed amount of R$ 1,850.00, a R$ 3,000.00 limit and the description of a cracked windshield; the History logs Claim opened by Ana Ribeiro and Review started by Carla Souza, with date and time; the automatic triage shows a score of 0 out of 100, low risk, with no alerts; and the policy card shows number, insured and broker.
  7. On mobile

    On mobile, the dashboard becomes a two-column grid, the calculation breakdown opens in a bottom sheet, the policy keeps its certificate face and the claim history fits on one screen. Fictitious data.

    • Dashboard on mobile: a navy header with the Apólice brand, search, notifications and avatar; the portfolio overview for Thursday, October 22, 2026, scoped to the user's own book, the New quote button and the indicators in a two-column grid, 12 active policies, R$ 27.5k of premium this month, 2 open quotes, a 60.0% conversion rate over 90 days, 2 open claims and a 33.5% loss ratio over 12 months, against a target of up to 60%; the start of the premium written chart and the bottom navigation with Home, Quotes, Policies, Claims and More.
      Dashboard on mobile: a navy header with the Apólice brand, search, notifications and avatar; the portfolio overview for Thursday, October 22, 2026, scoped to the user's own book, the New quote button and the indicators in a two-column grid, 12 active policies, R$ 27.5k of premium this month, 2 open quotes, a 60.0% conversion rate over 90 days, 2 open claims and a 33.5% loss ratio over 12 months, against a target of up to 60%; the start of the premium written chart and the bottom navigation with Home, Quotes, Policies, Claims and More.
    • Calculation breakdown opened in a bottom sheet on mobile, over the quote wizard: the live premium calculation under the Auto insurance rate table as of 10/22/2026, with collision, fire and theft (R$ 4,171.20), third-party property damage (R$ 660.00) and glass, headlights and mirrors (fixed, R$ 220.00), the BA/SE overnight-region factor of ×1.10, a net premium of R$ 5,051.20 and R$ 372.78 of IOF tax; the navy total premium block, R$ 5,423.98, or up to 10 interest-free payments of R$ 542.39, valid until 11/21/2026; and the installment picker with 1×, 3×, 6×, 10× or another number.
      Calculation breakdown opened in a bottom sheet on mobile, over the quote wizard: the live premium calculation under the Auto insurance rate table as of 10/22/2026, with collision, fire and theft (R$ 4,171.20), third-party property damage (R$ 660.00) and glass, headlights and mirrors (fixed, R$ 220.00), the BA/SE overnight-region factor of ×1.10, a net premium of R$ 5,051.20 and R$ 372.78 of IOF tax; the navy total premium block, R$ 5,423.98, or up to 10 interest-free payments of R$ 542.39, valid until 11/21/2026; and the installment picker with 1×, 3×, 6×, 10× or another number.
    • Policy AUTO-2026-000001 on mobile: the navy certificate face with Auto insurance, Active status, insured Pedro Henrique Rocha, a masked CPF and the vehicle details; the Endorse button and a menu with the other actions; and, stacked, the coverage period from 02/22/2026 to 02/22/2027 with 242 of 365 days, the R$ 7,885.57 total premium and 10 payments of R$ 788.55, above the bottom navigation.
      Policy AUTO-2026-000001 on mobile: the navy certificate face with Auto insurance, Active status, insured Pedro Henrique Rocha, a masked CPF and the vehicle details; the Endorse button and a menu with the other actions; and, stacked, the coverage period from 02/22/2026 to 02/22/2027 with 242 of 365 days, the R$ 7,885.57 total premium and 10 payments of R$ 788.55, above the bottom navigation.
    • History of claim SIN-2026-000001 on mobile, from the analyst's view: four transitions with date, time and author, Payment recorded, Indemnity approved with the note that the partner repair shop's estimate was below the claimed amount, and Review started, all by Carla Souza, and Claim opened by Ana Ribeiro, each with its status badge, Paid, Approved, Under review and Open.
      History of claim SIN-2026-000001 on mobile, from the analyst's view: four transitions with date, time and author, Payment recorded, Indemnity approved with the note that the partner repair shop's estimate was below the claimed amount, and Review started, all by Carla Souza, and Claim opened by Ana Ribeiro, each with its status badge, Paid, Approved, Under review and Open.
  8. Design system foundations

    Primitive colors become semantic tokens through light-dark(), and the same token serves both themes. The serif marks policy numbers and amounts, while spacing, radii, motion and buttons by variant and state round out the foundation.

    Apólice design system sheet, foundations and primitives, with the brand's navy and gold seal beside the title and chips for tokens.css with light-dark(), Tailwind 4 with @theme inline, Radix UI with lucide and 1 token for 2 themes. Color: the Navy, Gold and Night primitive scales with hex values and the semantic tokens as light and dark pairs (canvas, surface, ink, ink-2, line, primary-bg, brand-surface, gold-text, link and focus, ok, warn and bad), with the rule that components only use the semantic ones. Type in three families: Source Serif 4 for the policy number, headings and premium amount, Public Sans for interface text and Geist Mono for identifiers. Spacing on a 4 px base, radii from 5 px to a full circle, shadows only on what floats and motion timings from 120 to 280 ms with reduced motion. Primary, secondary, ghost and danger buttons in default, hover and disabled states, plus the buttons on navy with a gold focus ring; fields in focus, error and disabled states; tone badges; toggle, segmented control and tabs.
    Apólice design system sheet, foundations and primitives, with the brand's navy and gold seal beside the title and chips for tokens.css with light-dark(), Tailwind 4 with @theme inline, Radix UI with lucide and 1 token for 2 themes. Color: the Navy, Gold and Night primitive scales with hex values and the semantic tokens as light and dark pairs (canvas, surface, ink, ink-2, line, primary-bg, brand-surface, gold-text, link and focus, ok, warn and bad), with the rule that components only use the semantic ones. Type in three families: Source Serif 4 for the policy number, headings and premium amount, Public Sans for interface text and Geist Mono for identifiers. Spacing on a 4 px base, radii from 5 px to a full circle, shadows only on what floats and motion timings from 120 to 280 ms with reduced motion. Primary, secondary, ghost and danger buttons in default, hover and disabled states, plus the buttons on navy with a gold focus ring; fields in focus, error and disabled states; tone badges; toggle, segmented control and tabs.
  9. Domain components

    The domain components, in React and strict TypeScript, turn insurance into interface: the policy as a certificate, the premium calculation with every factor, the statuses, the claim history, the installments and the KPIs. Fictitious data.

    Apólice domain components sheet, with fictitious data. At the top, captures from the app: the face of policy AUTO-2026-000043 as a navy certificate with gold foil, Scheduled status, the insured with a masked CPF, coverage period, total premium, 10 installments and main coverage limit, with the Download PDF, Endorse and Cancel actions; and the live Premium calculation panel, with the annual premium of each coverage, the applied factors (driver aged 18 to 25, region, garage and class 3 bonus) with each effect in reais, net premium, 7.38% IOF tax and total premium. Below, quote, policy and claim statuses mapped to tones, including the expiry deadline; the claim history with the low-risk automatic triage and the review, approved indemnity and payment events; the 10-installment schedule with the next one highlighted; and KPI cards for the month's premium, the 12-month loss ratio against the target of up to 60% and the 90-day conversion rate.
    Apólice domain components sheet, with fictitious data. At the top, captures from the app: the face of policy AUTO-2026-000043 as a navy certificate with gold foil, Scheduled status, the insured with a masked CPF, coverage period, total premium, 10 installments and main coverage limit, with the Download PDF, Endorse and Cancel actions; and the live Premium calculation panel, with the annual premium of each coverage, the applied factors (driver aged 18 to 25, region, garage and class 3 bonus) with each effect in reais, net premium, 7.38% IOF tax and total premium. Below, quote, policy and claim statuses mapped to tones, including the expiry deadline; the claim history with the low-risk automatic triage and the review, approved indemnity and payment events; the 10-installment schedule with the next one highlighted; and KPI cards for the month's premium, the 12-month loss ratio against the target of up to 60% and the 90-day conversion rate.
  10. States and accessibility

    The screens handle empty, error with a correlation ID, loading and missing permission, and the same token changes value in dark theme. Contrast follows WCAG 2.1 AA, and axe runs in the tests. Fictitious data.

    Apólice states and accessibility sheet, with chips for WCAG 2.1 AA, prefers-reduced-motion, 200% zoom with reflow at 320 px and axe in the tests. States captured from the app: empty on first use, Nenhuma cotação ainda (no quotes yet), with the New quote button; an error in dark theme, Não foi possível carregar as apólices (the policies could not be loaded), with a copyable correlation ID and a Try again button; a skeleton that only appears after 200 ms and does not pulse with reduced motion; and no permission, Disponível para o perfil Admin (available to the Admin profile). Below, the dashboard in dark theme on a computer, with the same token and a different value, two 390 pt phones with the portfolio overview in light theme and the policy list in dark, and the accessibility panel with contrast ratios of 17.5:1 for text, 7.9:1 for secondary text, 5.4:1 or more for states and 7.3:1 for focus, and the rules of always-visible focus, never color alone, 40 px targets on desktop and 44 px on mobile, and the 168 frontend tests with Vitest, Testing Library and axe.
    Apólice states and accessibility sheet, with chips for WCAG 2.1 AA, prefers-reduced-motion, 200% zoom with reflow at 320 px and axe in the tests. States captured from the app: empty on first use, Nenhuma cotação ainda (no quotes yet), with the New quote button; an error in dark theme, Não foi possível carregar as apólices (the policies could not be loaded), with a copyable correlation ID and a Try again button; a skeleton that only appears after 200 ms and does not pulse with reduced motion; and no permission, Disponível para o perfil Admin (available to the Admin profile). Below, the dashboard in dark theme on a computer, with the same token and a different value, two 390 pt phones with the portfolio overview in light theme and the policy list in dark, and the accessibility panel with contrast ratios of 17.5:1 for text, 7.9:1 for secondary text, 5.4:1 or more for states and 7.3:1 for focus, and the rules of always-visible focus, never color alone, 40 px targets on desktop and 44 px on mobile, and the 168 frontend tests with Vitest, Testing Library and axe.
  11. Documented API

    The API documents its 32 operations in OpenAPI 3.1 with Scalar, including the endorsement and cancellation simulations and the Idempotency-Key header on issuance.

    API documentation in Scalar, in dark theme, at the Apólices (policies) section: the list of operations, POST and GET /api/v1/apolices, GET /api/v1/apolices/{id} and /documento, endorsement simulation and creation, and cancellation simulation and creation; below, Emitir uma apólice (issue a policy), with the Idempotency-Key header and a curl request example. In the sidebar, the groups for authentication, system, dashboard, products, quotes, policies, claims, administration and models.
    API documentation in Scalar, in dark theme, at the Apólices (policies) section: the list of operations, POST and GET /api/v1/apolices, GET /api/v1/apolices/{id} and /documento, endorsement simulation and creation, and cancellation simulation and creation; below, Emitir uma apólice (issue a policy), with the Idempotency-Key header and a curl request example. In the sidebar, the groups for authentication, system, dashboard, products, quotes, policies, claims, administration and models.
  12. Architecture

    The board follows the request from 1 to 10, from the SPA on Vercel to the .NET Lambda and Aurora DSQL, and the event through the outbox to SQS, the worker and, on failure, the DLQ with an email alarm. Delivery runs from A to G through OIDC and Terraform, and the notes carry the decisions from the ADRs.

    Apólice architecture board in the style of a Miro board, From request to event, in production, with the figures 32 REST operations under /api/v1, 5 projects from Domain to Worker, 1,143 .NET tests, 168 frontend and E2E tests and a cost close to US$ 0 a month on the free tier. Zones: Client, with the React 19, TypeScript and Vite SPA, TanStack Query, React Router, React Hook Form, Zod, Tailwind 4 and Radix UI, the access token kept only in memory and the demo personas; Edge on Vercel, with CDN, the /api rewrite to the Function URL, security headers and OpenAPI 3.1 with Scalar; and AWS Cloud in the us-east-1 region, with the apolice-api Lambda on .NET 10 and arm64 (a pipeline with correlation id, JWT, rate limiting, validation, Idempotency-Key and the domain emitting the event, with the Api, Infra, Application and Domain layers checked by architecture tests), Aurora DSQL with an IAM token and no database password, SSM Parameter Store with KMS, EventBridge every 5 min triggering the outbox-relay, the SQS queue with batches of 10 and partial failure feeding the apolice-worker Lambda, the DLQ after 5 receives, the alarm and the email notice through SNS, plus CloudWatch, Budgets and least-privilege IAM. The flow numbered 1 to 10 goes from the request to the event written with the inbox in the same transaction and, on failure, to the DLQ; steps A to G show delivery through GitHub Actions, from push to the backend and frontend CIs, the OIDC deploy, terraform apply, migration with seed and smoke test and the frontend on Vercel. Alongside, the Security strip (OWASP API Top 10: 15-minute JWT with rotating refresh, anti-BOLA, rate limiting, Idempotency-Key and FluentValidation with ProblemDetails), Observability (Serilog, OpenTelemetry, health checks and email alarms) and Local and tests (PostgreSQL 17, RabbitMQ 4, Aspire dashboard, Valkey and Testcontainers), sticky notes with the decisions and trade-offs from the ADRs and a legend for synchronous, event path, asynchronous, failure and configuration lines.
    Apólice architecture board in the style of a Miro board, From request to event, in production, with the figures 32 REST operations under /api/v1, 5 projects from Domain to Worker, 1,143 .NET tests, 168 frontend and E2E tests and a cost close to US$ 0 a month on the free tier. Zones: Client, with the React 19, TypeScript and Vite SPA, TanStack Query, React Router, React Hook Form, Zod, Tailwind 4 and Radix UI, the access token kept only in memory and the demo personas; Edge on Vercel, with CDN, the /api rewrite to the Function URL, security headers and OpenAPI 3.1 with Scalar; and AWS Cloud in the us-east-1 region, with the apolice-api Lambda on .NET 10 and arm64 (a pipeline with correlation id, JWT, rate limiting, validation, Idempotency-Key and the domain emitting the event, with the Api, Infra, Application and Domain layers checked by architecture tests), Aurora DSQL with an IAM token and no database password, SSM Parameter Store with KMS, EventBridge every 5 min triggering the outbox-relay, the SQS queue with batches of 10 and partial failure feeding the apolice-worker Lambda, the DLQ after 5 receives, the alarm and the email notice through SNS, plus CloudWatch, Budgets and least-privilege IAM. The flow numbered 1 to 10 goes from the request to the event written with the inbox in the same transaction and, on failure, to the DLQ; steps A to G show delivery through GitHub Actions, from push to the backend and frontend CIs, the OIDC deploy, terraform apply, migration with seed and smoke test and the frontend on Vercel. Alongside, the Security strip (OWASP API Top 10: 15-minute JWT with rotating refresh, anti-BOLA, rate limiting, Idempotency-Key and FluentValidation with ProblemDetails), Observability (Serilog, OpenTelemetry, health checks and email alarms) and Local and tests (PostgreSQL 17, RabbitMQ 4, Aspire dashboard, Valkey and Testcontainers), sticky notes with the decisions and trade-offs from the ADRs and a legend for synchronous, event path, asynchronous, failure and configuration lines.

Features and the pains they solve

Every feature was born from a real operational problem.

  1. 01

    Quote with live pricing

    Pain
    The broker builds the quote without knowing what each choice costs, and a premium nobody can explain makes the insured suspicious.
    Solution
    The 5-step wizard recalculates the premium on every change, with a simulation that saves nothing, and shows the calculation breakdown: each coverage's premium, the factors applied (driver age, region by postal code, commercial use, bonus class, property type, smoker), IOF tax and the maximum number of installments. Each product has its own pricing strategy.

    Impact: Auto, Home and Life; a saved quote is valid for 30 days

  2. 02

    Issuance without duplicates

    Pain
    Issuing from an expired quote, or twice because of a repeated click, creates a duplicate policy and a wrong charge.
    Solution
    A policy can only come from an accepted, valid quote, with coverage starting within 30 days, a number in the AUTO-2026-000042 format and up to 10 installments. Issuance accepts an Idempotency-Key: repeating the key returns the original response, and the policy PDF is generated with QuestPDF.
  3. 03

    Pro rata endorsement

    Pain
    Changing the limit or adding a coverage mid-term means charging or refunding only for the remaining days, math that usually ends up in a spreadsheet.
    Solution
    The system simulates before confirming and charges or refunds the difference pro rata for the remaining days. Every aggregate has a version, and a concurrent change becomes a 409 instead of overwriting the other one.
  4. 04

    Cancellation with simulation

    Pain
    Each cancellation reason has its own refund rule, and applying the wrong one refunds too much or too little.
    Solution
    Before confirming, the dialog shows the method, days elapsed, percentage retained and the amount to refund: in full before coverage starts, by the short-rate table when the insured asks and pro rata per day for the other reasons.

    Impact: The IOF tax is not refunded, and the screen says so before confirmation

  5. 05

    Claims with triage and handling

    Pain
    Without triage, a late notice with an amount close to the limit gets the same treatment as a simple case; without a history, nobody knows who approved what.
    Solution
    Every new claim gets an automatic, asynchronous triage, with a 0–100 score and alerts (recent coverage start, amount near or above the limit, late notice). The analyst starts the review, approves up to the lower of the claimed amount and the limit, denies with a reason or records the payment, and every transition goes into the history with author and date.
  6. 06

    Book isolated by role

    Pain
    In a system with several brokers, changing the id in the URL must never open a policy from another book (BOLA, the top risk in the OWASP API Top 10).
    Solution
    Authorization is resource-based: a broker only sees their own book, and someone else's resource answers 404, as if it did not exist. The analyst sees everything but cannot operate quotes or policies; the admin changes catalog rates and checks the audit trail.
  7. 07

    Secure session

    Pain
    A long-lived token stored in the browser can be stolen through XSS and cannot be revoked.
    Solution
    A 15-minute JWT access token kept only in memory and a 7-day rotating refresh token in an HttpOnly, SameSite=Strict cookie, stored in the database only as a hash. Reusing an already rotated token revokes the whole family, and sign-in locks after 5 wrong passwords, even with parallel attempts.
  8. 08

    Events that are never lost

    Pain
    Writing to the database and publishing to the queue in separate steps loses the event when either one fails, and redelivery duplicates emails or triage.
    Solution
    The event becomes an outbox row in the same SaveChanges as the aggregate; the API publishes right after commit and a scheduled relay covers failures. The consumer records the message in the same transaction as its effect, so a redelivery repeats nothing.

    Impact: RabbitMQ locally; SQS with a DLQ and an alarm in production

  9. 09

    Portfolio dashboard

    Pain
    To know how much they wrote, how well they convert and where the loss ratio stands, brokers have to stitch reports together.
    Solution
    The dashboard shows active policies, premium written this month and over the last 12 months, quote conversion, open claims, loss ratio and the book by product, within the signed-in user's scope: their own book or the whole portfolio. Reads use Dapper with parameterized SQL, separate from the EF Core writes.
  10. 10

    API with a drift-free contract

    Pain
    Integrating with an API without an up-to-date contract is trial and error, and the front-end breaks silently when the back-end changes.
    Solution
    The 32 operations under /api/v1 are documented in OpenAPI 3.1 with Scalar, with ProblemDetails errors (RFC 9457). CI regenerates the contract and fails if the committed one is out of date, and the front-end's TypeScript types are generated from the same OpenAPI.
  11. 11

    Serverless, observable production

    Pain
    An always-on server for a demo is expensive, and without correlated logs and traces there is no way to follow a request into the worker.
    Solution
    The API runs on AWS Lambda (.NET 10, arm64) behind a Vercel rewrite, on the same origin as the front-end, with Aurora DSQL authenticated through IAM, SQS and EventBridge, all in Terraform with OIDC deploys. Serilog writes JSON logs with a correlation id and no personal data, and OpenTelemetry carries the request's trace into the worker.

    Impact: Production cost close to US$ 0 (free tier)