A local-first SAP Fiori-style insurance cockpit built for a portfolio targeting an SAP Fiori Developer role.
The app demonstrates how a broker can manage policies, overdue premium items, claims, commissions, reminders, and follow-up tasks in one workflow-driven UI built with OpenUI5 and SAP CAP.
It is intentionally scoped as a polished MVP:
- free to run locally
- no SAP BTP account required
- no Docker required
- realistic insurance terminology and sample data
- OData V4 backend + freestyle UI5 frontend
Insurance brokers often work across disconnected spreadsheets, insurer portals, and back-office systems. That makes it hard to answer practical questions quickly:
- Which premium items are overdue today?
- Which customers need follow-up?
- Which claims are waiting on documents or insurer action?
- How much commission is expected from paid premium?
This project packages those daily broker tasks into one Fiori-style cockpit with a clean UI, clear semantic statuses, and realistic actions.
This repository focuses on a realistic insurance operations scenario implemented with SAP-style full-stack patterns:
- UI5 MVC application structure
- multi-page routing and shell navigation
- OData V4 integration
- CDS-based domain modeling
- business actions for collections and claims workflows
- testing and documentation
The core demo flow is:
- The broker opens the dashboard and sees overdue open items and claims needing attention.
- The broker navigates to Open Items and filters for overdue receivables.
- The broker opens the related policy context and registers a payment.
- The open item status updates from Open or Overdue to Partially Paid or Paid.
- The backend recalculates commission based on premium collected.
- The broker creates a reminder or a follow-up task from the same process.
That flow is intentionally close to real insurance collections work, while still being small enough to run locally as a portfolio project.
- KPI cards for:
- Active Policies
- Overdue Open Items
- Total Outstanding Amount
- Open Claims
- Expected Commission
- recent overdue open items table
- claims requiring attention table
- analytics tiles for portfolio distribution and operational status
- searchable list/report-style page
- filters by policy type and status
- broker/customer context
- navigation to a dedicated detail page
- object-page style detail view
- general policy information
- related open items
- related claims
- related commissions
- related tasks and reminders
- the main collections workspace
- receivables list with status and overdue visibility
- actions:
- Mark as Paid
- Register Partial Payment
- Create Reminder
- Create Follow-up Task
- claim tracking table
- staged workflow progression
- close/reject action
- expected vs paid commission visibility
- broker-oriented earnings overview
| Layer | Technology | Why it was chosen |
|---|---|---|
| Backend | Node.js | Simple, common JavaScript runtime |
| Service layer | SAP CAP | Fast way to model domain entities, expose OData, and add business actions |
| Data model | CDS (schema.cds, service projections) |
Clean SAP-style modeling and readable domain structure |
| Database | SQLite | Free, lightweight, easy to seed locally |
| Frontend | OpenUI5 freestyle app | Demonstrates SAPUI5-style frontend skills without requiring paid SAP setup |
| UI architecture | MVC with XML Views | Standard UI5 project structure recruiters expect to see |
| Data access | OData V4 model | Strong SAP relevance; clean list/detail/action integration |
| Testing | Jest, QUnit | Backend logic coverage + formatter coverage |
| Styling | Standard UI5 controls + custom CSS | Fiori-like look while keeping the app realistic and lightweight |
flowchart LR
U["Browser"] --> UI["OpenUI5 Freestyle App<br/>app/webapp"]
UI --> ROUTER["UI5 Router<br/>manifest.json"]
ROUTER --> VIEWS["XML Views + Controllers"]
VIEWS --> ODATA["OData V4 Model"]
ODATA --> CAP["SAP CAP Service<br/>srv/broker-service.cds<br/>srv/broker-service.js"]
CAP --> CDS["CDS Domain Model<br/>db/schema.cds"]
CAP --> DB["SQLite<br/>db.sqlite"]
DB --> CSV["CSV Seed Data<br/>db/data/*.csv"]
The application is split into two clear parts:
The frontend lives under app/webapp and is a freestyle OpenUI5 application.
It uses:
Component.jsto bootstrap the app and initialize routingmanifest.jsonto define models, routes, and dependencies- XML Views for page layout
- Controllers for page behavior and user actions
- a formatter module for UI-specific logic such as value-state mapping and overdue calculation
The backend lives in:
db/schema.cdssrv/broker-service.cdssrv/broker-service.js
CAP handles:
- entity exposure as OData V4
- projections for frontend-friendly fields like
customerName - action endpoints for business workflows
- SQLite integration
- CSV seeding
broker-cockpit/
├─ app/
│ ├─ index.html
│ └─ webapp/
│ ├─ Component.js
│ ├─ manifest.json
│ ├─ controller/
│ ├─ view/
│ ├─ model/
│ ├─ fragment/
│ ├─ i18n/
│ ├─ css/
│ └─ test/
├─ db/
│ ├─ schema.cds
│ └─ data/
├─ srv/
│ ├─ broker-service.cds
│ ├─ broker-service.js
│ └─ broker-service.test.js
├─ package.json
└─ README.md
The domain model is intentionally business-readable. Policies sit at the center, with operational entities around them.
- Customers
- Brokers
- Policies
- Installments
- OpenItems
- Payments
- Claims
- Commissions
- Reminders
- Tasks
erDiagram
CUSTOMERS ||--o{ POLICIES : owns
BROKERS ||--o{ POLICIES : manages
POLICIES ||--o{ INSTALLMENTS : has
POLICIES ||--o{ OPENITEMS : has
OPENITEMS ||--o{ PAYMENTS : receives
OPENITEMS ||--o{ REMINDERS : triggers
POLICIES ||--o{ CLAIMS : has
POLICIES ||--o{ COMMISSIONS : generates
POLICIES ||--o{ TASKS : creates
OPENITEMS ||--o{ TASKS : relates_to
CUSTOMERS {
UUID ID PK
String firstName
String lastName
String email
String city
String country
}
BROKERS {
UUID ID PK
String name
String licenseNo
Decimal commRate
String email
}
POLICIES {
UUID ID PK
String policyNumber
String policyType
String status
Date startDate
Date endDate
Decimal annualPremium
String currency
}
OPENITEMS {
UUID ID PK
Date dueDate
Decimal amount
Decimal paidAmount
String status
String currency
String description
}
PAYMENTS {
UUID ID PK
Date paymentDate
Decimal amount
String method
String reference
}
CLAIMS {
UUID ID PK
String claimNumber
String claimType
String status
Date reportedDate
Decimal estimatedAmount
Decimal paidAmount
}
COMMISSIONS {
UUID ID PK
Decimal premiumPaid
Decimal commRate
Decimal expectedAmount
Decimal paidAmount
String status
}
REMINDERS {
UUID ID PK
DateTime reminderDate
String note
Boolean sent
}
TASKS {
UUID ID PK
String title
String description
Date dueDate
Boolean done
String priority
}
INSTALLMENTS {
UUID ID PK
Integer installmentNo
Date dueDate
Decimal amount
Boolean paid
}
The app is preloaded with demo data to make the UI feel like a real working portfolio, not an empty skeleton.
The dataset includes:
- 8 customers
- 2 brokers
- 15 policies
- multiple policy types:
- Motor
- Property
- Life
- Travel
- Health
- open items in different states:
- Open
- Partially Paid
- Paid
- Overdue
- In Dispute
- claims in different stages
- commission records
- reminders and tasks
Default currency is EUR.
This project uses CAP to expose a clean OData V4 service at:
OData V4 is relevant for SAP frontend work because it gives the UI a standard way to:
- read lists and details
- expand related entities
- filter and sort on the server
- trigger business actions through defined endpoints
- stay close to enterprise SAP app patterns
That makes this project much more SAP-relevant than a generic REST-only demo.
The service exposes frontend-facing projections for:
- Customers
- Brokers
- Policies
- Installments
- OpenItems
- Payments
- Claims
- Commissions
- Reminders
- Tasks
Several projections also include convenience fields for UI consumption, for example:
customerNamepolicyNumberpolicyTypebrokerName
This keeps the UI simpler while still preserving a proper normalized backend model.
The UI relies on standard OData query options such as:
$selectto limit payload fields$expandto load related customer, policy, or broker context$orderbyto sort lists like overdue items and claims$filterfor page filters such as policy status or open item status
Examples used in practice:
/Policies?$orderby=policyNumber asc&$expand=customer($select=firstName,lastName),broker($select=name)
/OpenItems?$orderby=dueDate asc&$expand=policy($select=policyNumber,policyType),customer($select=firstName,lastName)
/Claims?$orderby=reportedDate desc
The backend also exposes business operations beyond plain reads.
markAsPaid(openItemId)registerPartialPayment(openItemId, amount, paymentDate)createReminder(openItemId, note, reminderDate)createFollowUpTask(openItemId, title, dueDate)moveClaimToNextStatus(claimId)closeClaim(claimId, note)calculateCommission(policyId)
These actions are called from the UI when a broker performs operational work from tables or dialogs.
getDashboardKPIs()
This function returns aggregated dashboard values:
- active policies
- overdue open items
- total outstanding amount
- open claims
- expected commission
The logic in srv/broker-service.js is the operational core of the project.
For each open item:
outstandingAmount = amount - paidAmount- if outstanding becomes
0, status becomesPaid - if some money is paid but balance remains, status becomes
PartiallyPaid - if the due date is in the past and the item is not fully settled, it is operationally treated as overdue
When a payment is registered:
- a Payment record is created
- the OpenItem
paidAmountis updated - the OpenItem status is recalculated
- commission is recalculated for the related policy
Commission is derived from collected premium, not just nominal premium.
The service:
- sums paid amounts from paid/partially paid open items for a policy
- applies the broker commission rate
- updates the commission record
Claims move through a simple controlled sequence:
New → WaitingDocuments → SentToInsurer → Approved → Paid
The closeClaim action marks a claim as rejected/closed with a note.
The app is structured around a UI5 shell with route-driven navigation. Main building blocks include:
Component.jsmanifest.jsonApp.view.xml- per-page controllers and views
- MVC architecture
- XML Views
- controller-based event handling
- reusable fragments for dialogs
- i18n resource bundle
- semantic
ObjectStatus ObjectNumberfor financial values- message toasts and message boxes for user feedback
- busy indicators during backend operations
app/webapp/Component.jsapp/webapp/manifest.jsonapp/webapp/controller/app/webapp/view/app/webapp/model/formatter.js
The CDS model defines:
- domain entities
- associations and compositions
- enum-like status types for insurance objects
This gives the project a very SAP-style, readable backend foundation.
The service layer has two files:
srv/broker-service.cdsfor the OData contractsrv/broker-service.jsfor behavior
That split is useful in a portfolio because it clearly shows:
- data model
- exposed API
- business logic
- Node.js 18 or newer
- npm 9 or newer
cd "C:\Users\DELL\SAP Fioneer\broker-cockpit"
npm installnpx cds deploy --to sqliteOr reset and reseed in one command:
npm run reset-dbnpm run watch| URL | Purpose |
|---|---|
| http://localhost:4004/ | CAP launch page |
| http://localhost:4004/webapp/index.html | Main UI5 application |
| http://localhost:4004/odata/v4/broker/ | OData V4 service root |
| http://localhost:4004/odata/v4/broker/$metadata | OData metadata |
| http://localhost:4004/webapp/test/unit/unitTests.qunit.html | QUnit test page |
| Command | What it does |
|---|---|
npm install |
installs project dependencies |
npm run watch |
starts CAP with live reload for development |
npm start |
starts the service without watch mode |
npm test |
runs backend Jest tests |
npm run reset-db |
deletes and recreates the SQLite database from CSV seed data |
This project is designed first as a local-first portfolio application.
The current Vercel deployment is fully working for demo use:
- https://broker-cockpit.vercel.app/webapp/index.html
- frontend assets load correctly
- the CAP OData V4 service responds successfully
- demo CSV data is seeded into an in-memory SQLite database at startup
Hosted limitation:
- the deployed environment uses in-memory SQLite
- data can reset between cold starts
- the local setup remains the primary persistent development environment
The note below reflects an earlier stage of the deployment work before the Vercel runtime fixes were completed.
A Vercel deployment was created during development at:
The Vercel deployment currently serves the frontend successfully, but the full CAP + SQLite backend is not working correctly in Vercel’s serverless runtime for this setup.
That means:
- the UI can be opened
- static frontend assets are served
- the OData V4 backend is not fully operational in that environment
- the Vercel link should be treated as a frontend preview, not as the final full-stack production deployment
The app uses:
- SAP CAP
- SQLite
- OData V4
- runtime-loaded CAP service infrastructure
That combination works well locally, but it is not an ideal fit for Vercel’s serverless function packaging model in this project shape. During deployment, CAP’s SQLite runtime resolution and related backend packaging behavior cause the OData service startup to fail even though the same code works locally.
For a real full-stack public deployment of this repository, a better fit would be a host that runs a normal long-lived Node.js server process, for example:
- Render
- Railway
- Fly.io
Those platforms are a better match for:
- CAP service bootstrapping
- SQLite or alternative attached databases
- stateful backend actions
- a complete end-to-end portfolio demo link
The project includes both frontend-oriented and backend-oriented tests so the repo demonstrates more than just UI implementation.
QUnit is used for lightweight frontend unit testing in the UI5 app.
In this project, QUnit is used to validate presentation and helper logic from the formatter layer, which is a common place for UI-specific business rules in UI5 applications.
The QUnit tests cover logic such as:
- semantic status-to-state mapping for
ObjectStatus - outstanding amount calculation
- overdue day calculation
- visibility logic for paid vs unpaid records
Why that matters:
- it shows how UI behavior can be tested without relying on manual browser checks
- it keeps small but important business-display rules from silently breaking
- it reflects a realistic UI5 testing entry point for a portfolio project
The QUnit entry page is:
http://localhost:4004/webapp/test/unit/unitTests.qunit.html
OPA5 is UI5’s browser-based integration testing approach for end-to-end user journeys.
In this repository, an OPA5 smoke-test scaffold is included as a starting point. It is not yet a full regression suite, but it demonstrates the intended testing direction for UI interactions such as:
- launching the application
- navigating between pages
- selecting list items
- executing business actions
- verifying UI state changes after backend calls
Why OPA5 is relevant here:
- it is SAP-native UI test tooling
- it maps naturally to business workflows rather than isolated functions
- it is especially useful for validating routing, dialogs, and table-driven interactions in UI5 apps
This project currently includes the scaffold so the repository stays practical in scope while still showing awareness of the right UI5 integration-test pattern.
Jest tests cover the CAP service contract and core business actions, including:
- entity-set reads
- dashboard KPI function
- payment action logic
- claim workflow progression
If you want to present the project quickly, this is the best walkthrough:
- Open the dashboard and explain the broker use case.
- Point out overdue open items and claims requiring attention.
- Navigate to Open Items.
- Filter by
Overdue. - Select one item and register a partial payment.
- Show the status update and explain the payment/business logic.
- Create a reminder or a follow-up task.
- Navigate to Claims and move one claim to the next status.
- Open Policies and drill into a policy detail page.
- Close with the commission overview and the CAP/OData architecture.
Add screenshots here once you are happy with the final UI.
- Dashboard
- Policies
- Policy Detail
- Open Items
- Claims
- Commissions
- no authentication or authorization layer yet
- no SAP BTP deployment target configured in this repo
- no real email or reminder delivery
- dashboard KPI aggregation is intentionally lightweight for local SQLite use
- OPA5 coverage is scaffold-level, not full journey coverage
- add full OPA5 journeys for the main broker workflow
- improve dashboard charts and analytical interactions
- add date-range filters on open items and claims
- introduce role-based broker views
- add export options for operational reporting
- add Fiori Launchpad sandbox configuration
- migrate demo persistence to SAP HANA Cloud for a cloud-hosted version
This project is strong as a portfolio piece because it shows both sides of the typical SAP full-stack workflow:
- a UI5 frontend organized the way SAP teams expect
- a CAP backend with CDS and OData V4
- business-focused enterprise UX rather than a generic CRUD toy
- local reproducibility for reviewers
- enough domain complexity to talk through real implementation choices
It is especially useful for a candidate with insurance-domain experience because it connects that domain knowledge to SAP-style technical delivery.