Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

Corporate Expense Audit Dashboard

A Power BI fraud-flagging dashboard built on a synthetic 25,155-row corporate expense ledger with deliberately planted anomalies — duplicate charges, over-limit spend, self-approvals, round-number patterns, and spending spikes. Rule-based risk scoring surfaces the ~20% of transactions worth a second look, ranks employees by risk, and exposes segregation-of-duties gaps.

Live interactive showcase → (add your Netlify/portfolio link here)


Overview

Dataset 25,155 synthetic expense transactions, Jan 2025 – Jun 2026
Tool Power BI Desktop (DAX, Power Query / M)
Report pages Overview · Investigation List · Employee Risk
Total expenses ₱4.67M
Flagged transactions 5,018 (19.95%)
High-risk transactions (Score 3+) 74
Employees with Score 3+ 31
Employees with self-approved expenses 34

The dashboard scores every transaction against seven independent fraud rules (duplicate, over-limit, self-approved, round-number, round-number pattern, weekend submission, spending spike, rapid cluster) and rolls them into a single Risk Score, filterable live via a disconnected threshold table.


Dashboard Preview

Add screenshots here: screenshots/overview.png, screenshots/investigation-list.png, screenshots/employee-risk.png

Overview — KPI cards, monthly expense trend, flags by department, expenses by category Investigation List — full flagged-transaction table with a Score 1+/2+/3+ button slicer Employee Risk — company-wide risk ranking + self-approval (segregation-of-duties) table


Data Model

Star schema: one fact table, one disconnected parameter table, and four measure-only tables kept separate by purpose rather than dumped into one bucket.

Validated_Expense (fact)
├── Expense ID, Amount, Risk_Score
├── Flag_Duplicate, Flag_OverLimit, Flag_SelfApproved
├── Flag_RoundNumber, Flag_RoundNumberPattern
├── Flag_Weekend, Flag_SpendingSpike, Flag_RapidCluster
└── Employee, Manager, Department, Vendor, Category, Payment Method

RiskThreshold (disconnected)
└── Label, MinScore → powers the Score 1+/2+/3+ button slicer

Core KPI Measures        Flag Measures             for KPI Cards
├── Total Expenses        ├── Flag Count – Duplicate  ├── Expense/Flagged MoM %
├── % Flagged              ├── Flag Count – Over Limit ├── MoM Color (inverted)
├── Avg Risk Score         ├── Flag Count – Self Approved └── MoM Icon + Label
└── High Risk (Score 3+)   └── Total Flags (All Types)

Department/Employee Breakdown
├── Employees With Any Flag
├── Employees With Score 3+
└── Employees with Self-Approval

KPI cards are built manually — background shapes + text boxes + Card visuals + MoM % cards + line-chart sparklines layered together — rather than relying on a single visual type, for full control over spacing and conditional formatting.


Technical Decisions & Talking Points

Real trade-offs made during the build, not just a feature list.

Flag rate calibration: 38% → ~19% The first pass of rules flagged over a third of all spend — unusable for an investigator. Brought it down by excluding certain categories from the weekend rule, adding a buffer above the policy limit before triggering "over limit," and running a Python distribution analysis to set the spending-spike window empirically instead of guessing a round threshold.

Expense ID stays in the table on purpose Power BI tables silently collapse rows that are identical across all visible columns. Two duplicate transactions — same employee, vendor, amount, date — would merge into one row and understate the risk score. Keeping a unique ID column in any audit/transaction table is non-negotiable.

RANKX / ALLSELECTED trap ALL(Employee) doesn't clear filter context introduced by other active slicers, so the ranking measure was silently ranking within department instead of company-wide. Switching to ALLSELECTED scoped to the Employee column fixed true global ranking while still respecting the department/manager slicers.

Inverted MoM conditional formatting For a risk metric, an increase is the bad outcome — so every MoM card on this dashboard flips Power BI's default color logic: red means "up," green means "down."

Risk Score ≥ 2 as the operational threshold High enough precision to be actionable for a reviewer, not so restrictive that true positives slip through. The disconnected RiskThreshold table lets anyone toggle 1+/2+/3+ live instead of hard-coding one cutoff.

A page was cut, not shipped broken An early Trend page used DATESMTD anchored to TODAY(). The dataset ends June 2026, so "month-to-date" was silently comparing against a real-world today with no data behind it — producing a phantom partial-month dip. Shipping a broken KPI is worse than shipping one fewer page, so the Trend page was removed rather than patched around.


Tools Used

  • Power BI Desktop — DAX measures, calculated columns, disconnected tables, conditional formatting via field value
  • Power Query / M — data transformation and audit rule implementation
  • Python — distribution analysis for empirical threshold tuning
  • pbixray — extracting DAX measures, schema, and relationships for documentation

Repo Structure

Expense_Audit/
├── Expense_Audit.pbix
├── screenshots/
│   ├── overview.png
│   ├── investigation-list.png
│   └── employee-risk.png
└── README.md

Author

Ryan Seguiro — Data Analytics GitHub @nayR02 · LinkedIn · Portfolio (add link)

About

A Power BI dashboard that scores every corporate expense against seven fraud rules — duplicates, over-limit spend, self-approvals, round-number patterns, spending spikes — and ranks employees by risk.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors