Senior BA Portfolio: Federal Data Integration
Build a shareable BA portfolio with Jira stories, SQL validation, and an RTM.
Introduction
30 Second Summary
Every Senior BA job description asks for the same proof: requirements documents, traceability matrices, test evidence, SOPs. But most candidates show up to interviews with nothing but resume bullet points and verbal stories. A shareable portfolio with real artifacts changes the conversation entirely.
In this project, you will build a complete Senior BA portfolio in Notion around a realistic federal grants payment data integration scenario. You will write user stories in Jira, build a Requirements Traceability Matrix, validate data quality with SQL, and produce production-ready documentation.
What You'll Build
When you share your Notion link with a hiring manager, they open a single page and see interview-ready proof of the full Agile BA lifecycle, from requirements elicitation through release notes, grounded in a federal data integration scenario.
By the end of this project, you'll have:
- A shareable Notion portfolio with a Jira backlog screenshot showing 5 user stories linked to an Epic, each with detailed acceptance criteria and story point estimates.
- A Requirements Traceability Matrix built as a Notion database where you discover untestable acceptance criteria, fix the gaps, and trace every requirement to a validated test case.
- Proven SQL validation results catching real data quality issues in a Treasury payment feed: orphan payments, overpayments, date mismatches, and payments to closed grants.
- Secret Mission: A training presentation deck for end users and a JAD session agenda template proving stakeholder communication and facilitation skills.
Are there any prerequisites?
This project assumes you have existing Business Analyst experience and a working knowledge of SQL, Jira, and Notion. You should already have accounts set up for Jira Cloud (free plan), Notion (free plan), and Lucidchart (free plan), plus access to any SQL environment (SQL Server, PostgreSQL, MySQL, or SQLite all work).
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters for the role you're targeting.
Set Up Your Portfolio Workspace and Project Infrastructure
Without a structured workspace, BA artifacts end up scattered across tools with no single link to share with interviewers.
In this step, you will build the skeleton that holds every deliverable you create in this project. Notion becomes your portfolio page, Jira holds your user stories, and your SQL environment hosts the sample data you will validate against.
In this step, get ready to:
- Create a Notion portfolio page with placeholder sections for every BA deliverable.
- Set up a Jira Scrum project with an Epic for the Treasury payment feed enhancement.
- Load sample grants and payment data into your SQL environment.
Create the Notion portfolio page structure
Your Notion page is the single shareable URL a hiring manager will open. Setting up the skeleton now means every artifact you build in later steps drops into the right place.
- Open your Notion workspace in your browser.
- In the left sidebar, click the + New page button.
- Title this page BA Portfolio.
- Inside the BA Portfolio page, create a new subpage by typing /page and pressing Enter.
- Title the subpage Federal Grants Payment Data Integration.
Now add the TL;DR callout and section headings inside the subpage.
- At the top of the subpage, type /callout and press Enter to insert a callout block.
- Inside the callout, type the following on separate lines: Problem: (leave blank), Solution: (leave blank), Impact: (leave blank).
- Below the callout, type /heading 2 to create an H2 heading titled Scenario Overview.
- Repeat the H2 heading for each of these sections in order: User Stories, Requirements Traceability Matrix, Data Flow Diagram, Test Cases and Validation, SOP, Release Notes.
Why this page structure?
This mirrors the "Layered Onion" portfolio approach: a TL;DR at the top for time-pressed hiring managers, with progressively deeper evidence below.
Each H2 section maps to a deliverable in the BA lifecycle. By the end of this project, every section will contain interview-ready proof of your work.
Your Notion page should now show the BA Portfolio page in the sidebar, with the Federal Grants Payment Data Integration subpage nested inside it containing the TL;DR callout and seven H2 headings.
Don't see the subpage nested inside BA Portfolio?
Make sure you created the subpage from inside the BA Portfolio page, not from the sidebar. If it appears at the top level, drag it onto the BA Portfolio page in the sidebar to nest it.
Help me fix my Notion page hierarchy.
Create the Jira Scrum project and Epic
Every user story you write in the next step needs a home. A Jira Scrum project with an Epic gives you the backlog structure that mirrors how federal Agile teams actually track work.
- Open your Jira Cloud instance in a new browser tab.
- Click Projects in the top navigation bar.
- Click Create project.
- Select Scrum as the project template.
- Enter Grants Payment Integration as the project name.
- Click Create to finish setting up the project.
Now create the Epic that groups all the user stories for this enhancement.
- In your new project, open the Backlog view from the left sidebar.
- Click Create Epic (or use the + Create issue button and set the type to Epic).
- Set the Epic title to Treasury Payment Feed Integration.
- In the description field, paste: Integrate daily Treasury disbursement data feed into the grants management system to enable automated payment reconciliation, replacing the current manual process.
- Set the Priority field to High.
- Click Save or press Enter to create the Epic.
You should now see the Epic titled Treasury Payment Feed Integration in your Backlog view with a High priority badge.
Don't see the Epic option?
Jira's free plan supports Epics, but the option may be hidden by default. In the Backlog view, look for the Epics panel on the left side. If you do not see it, click Board settings and check that the Epic issue type is enabled for your project.
Help me find the Epic option in my Jira project.
Load sample data into your SQL environment
The sample data represents a grants management system and an incoming Treasury payment feed. It includes intentional data quality issues that you will detect with validation queries in a later step.
- Open your SQL environment (any SQL client connected to a database will work).
- Create the two tables by running this SQL:
-- Existing grants management system table
CREATE TABLE grants (
grant_id VARCHAR(20) PRIMARY KEY,
grantee_name VARCHAR(100),
award_amount DECIMAL(12,2),
award_date DATE,
program_code VARCHAR(10),
status VARCHAR(20)
);
-- New Treasury payment data feed table
CREATE TABLE treasury_payments (
payment_id VARCHAR(20) PRIMARY KEY,
grant_reference VARCHAR(20),
payment_amount DECIMAL(12,2),
payment_date DATE,
agency_code VARCHAR(10),
payment_status VARCHAR(20)
);
What do these tables represent?
The grants table is the existing system of record. It tracks each grant's award amount, date, and current status.
The treasury_payments table represents the new daily feed from the Treasury Bureau of the Fiscal Service. Each row is a disbursement record that needs to be reconciled against the grants table.
- Load the sample data into both tables by running these INSERT statements:
-- Load existing grants data
INSERT INTO grants VALUES ('GRT-2024-001', 'State Health Dept A', 500000.00, '2024-01-15', 'HHS-01', 'Active');
INSERT INTO grants VALUES ('GRT-2024-002', 'County Transit Auth', 250000.00, '2024-03-01', 'DOT-03', 'Active');
INSERT INTO grants VALUES ('GRT-2024-003', 'Rural Ed Consortium', 175000.00, '2024-02-10', 'ED-05', 'Closed');
INSERT INTO grants VALUES ('GRT-2024-004', 'Metro Water District', 320000.00, '2024-04-20', 'EPA-02', 'Active');
INSERT INTO grants VALUES ('GRT-2024-005', 'Veterans Housing Inc', 450000.00, '2024-05-01', 'HUD-01', 'Active');
-- Load Treasury payment feed data (includes intentional data quality issues)
INSERT INTO treasury_payments VALUES ('PAY-50001', 'GRT-2024-001', 125000.00, '2024-03-15', 'HHS', 'Processed');
INSERT INTO treasury_payments VALUES ('PAY-50002', 'GRT-2024-001', 125000.00, '2024-06-15', 'HHS', 'Processed');
INSERT INTO treasury_payments VALUES ('PAY-50003', 'GRT-2024-002', 275000.00, '2024-05-01', 'DOT', 'Processed');
INSERT INTO treasury_payments VALUES ('PAY-50004', 'GRT-2024-003', 50000.00, '2024-07-01', 'ED', 'Processed');
INSERT INTO treasury_payments VALUES ('PAY-50005', 'GRT-2024-006', 100000.00, '2024-06-01', 'HHS', 'Processed');
INSERT INTO treasury_payments VALUES ('PAY-50006', 'GRT-2024-004', 80000.00, '2024-04-15', 'EPA', 'Processed');
INSERT INTO treasury_payments VALUES ('PAY-50007', 'GRT-2024-005', 150000.00, '2024-06-01', 'HUD', 'Processed');
What are the intentional data quality issues?
The payment data contains problems you will catch later with validation queries: an orphan payment referencing a grant that does not exist, a total payment exceeding a grant's award amount, a payment dated before the grant's award date, and a payment against a closed grant.
You do not need to spot them now. The queries in Step 4 will surface each one.
ANSI-standard SQL
This SQL uses ANSI-standard syntax that works in PostgreSQL, MySQL, SQLite, SQL Server, and Oracle. Run it in whichever client you already have set up.
Before you run the verification query, how many rows do you expect in each table based on the INSERT statements above?
- Confirm both tables loaded successfully by running this count check:
SELECT 'grants' AS table_name, COUNT(*) AS row_count FROM grants
UNION ALL
SELECT 'treasury_payments', COUNT(*) FROM treasury_payments;
You should see grants returning 5 rows and treasury_payments returning 7 rows.
Seeing 0 rows or an error?
If you see a "table already exists" error, drop both tables first with DROP TABLE IF EXISTS grants; DROP TABLE IF EXISTS treasury_payments; and re-run the CREATE and INSERT statements.
If the row counts are wrong, confirm you ran all 5 grants INSERTs and all 7 treasury_payments INSERTs without errors.
Help me troubleshoot my SQL sample data loading.
✔️ Awesome, I've got everything!
Great. Confirm you have saved your SQL statements so you can reference them later if needed.
ⓧ I'd like to double check the full code
Scroll up and confirm both code chunks are present in your SQL environment:
- The two CREATE TABLE statements (grants and treasury_payments) with all column definitions.
- Five INSERT statements for grants (GRT-2024-001 through GRT-2024-005).
- Seven INSERT statements for treasury_payments (PAY-50001 through PAY-50007).
Your workspace is ready. You have a Notion page with a clear structure waiting for content, a Jira project with an Epic to hold your user stories, and a SQL environment loaded with realistic federal grants data. Next up, you will write the user stories that define what this integration actually does.
Write User Stories and Acceptance Criteria in Jira
Your workspace is set up and ready. Notion has the portfolio page skeleton, Jira has the Epic, and your SQL environment is loaded with sample data.
User stories are the foundation every other BA artifact traces back to. They give the development team something concrete to estimate, build, and test against. In this step, you'll define the project scenario and write five user stories that anchor the entire integration effort.
In this step, get ready to:
- Write the scenario overview for your federal grants integration project.
- Create 5 user stories with acceptance criteria in Jira, linked to your Epic.
- Embed Jira screenshots into your Notion portfolio as shareable evidence.
Write the scenario overview in Notion
Every portfolio project needs a scenario that grounds the technical work in a real business context. This overview tells a hiring manager what problem the project solves before they look at any artifacts.
- Switch back to your Notion page for Federal Grants Payment Data Integration.
- Click into the Scenario Overview section (below the H2 heading you created in Step 1).
- Paste the following scenario text:
A federal grants management system currently tracks grant awards and obligations. The agency receives a daily CSV file from the Treasury Bureau of the Fiscal Service containing disbursement records for grant payments. Currently, reconciliation is performed manually in spreadsheets, which is error-prone and delays the monthly SF-224 reporting. This enhancement integrates the Treasury payment feed directly into the backend system for automated reconciliation.
What does this scenario establish?
This paragraph packs four critical elements into a tight summary. It names the existing system (grants management), the data source (Treasury Bureau of the Fiscal Service daily CSV), the current pain point (manual spreadsheet reconciliation), and the proposed fix (automated feed integration).
A hiring manager reading this immediately knows the domain, the complexity, and the business impact without needing to scroll further.
- Confirm the scenario text appears under the Scenario Overview heading in your Notion page.
Create five user stories in Jira
Each user story follows the standard Agile format: As a [role], I want [goal], so that [benefit]. You'll also assign story points and write acceptance criteria that define when the story is done.
- Return to your Grants Payment Integration project in Jira.
- Open the Backlog view from the left sidebar.
- Click Create issue at the bottom of the backlog.
- Set the issue type to Story.
- Enter the title: Ingest Treasury Payment Feed.
- Open the story detail by clicking on it, then fill in the Description field with the As-a/I-want/So-that text and acceptance criteria from the reference below.
- Set Story Points to 5 in the story details panel.
- Link the story to your Epic by setting the Parent field (or Epic Link field, depending on your project type) to Treasury Payment Feed Integration.
Use this reference for US-001's description and acceptance criteria:
Title: Ingest Treasury Payment Feed
Story Points: 5
Description:
As a grants system administrator, I want the system to ingest
the daily Treasury CSV file automatically, so that payment
records are available for reconciliation without manual entry.
Acceptance Criteria:
- All rows from the daily CSV are loaded into the
treasury_payments table
- Data is loaded accurately
- No duplicate payment_id values after load
What makes a good user story?
The As-a/I-want/So-that format forces you to name who benefits, what they need, and why it matters. This prevents vague requirements like "make the system better."
Acceptance criteria define the specific conditions that must be true for the story to be considered done. You'll revisit these criteria later to test whether they're truly measurable.
- Confirm US-001 appears in your backlog with the Epic link visible.
Now create the remaining four stories using the same process. Use the reference content below for each:
Title: Validate Referential Integrity
Story Points: 3
Description:
As a data steward, I want the system to flag payments that
reference a grant_id not present in the grants table, so that
orphan payments are identified before reconciliation proceeds.
Acceptance Criteria:
- System flags any payment where grant_reference does not
match an existing grant_id in the grants table
- Flagged records appear in the exception queue
Title: Detect Overpayments
Story Points: 3
Description:
As a grants program manager, I want the system to flag when
cumulative payments to a grant exceed the award amount, so
that overpayments are caught before financial reporting.
Acceptance Criteria:
- System flags overpayments in a timely manner when total
disbursements exceed the grant award_amount
Title: Validate Payment Dates
Story Points: 2
Description:
As an auditor, I want the system to flag payments dated before
the grant's award date, so that timing anomalies are surfaced
for review.
Acceptance Criteria:
- System flags any payment where payment_date is earlier than
the associated grant's award_date
- Flagged records include both dates for review
Title: Flag Payments to Closed Grants
Story Points: 2
Description:
As a grants closeout specialist, I want the system to flag
payments against grants with a status of 'Closed', so that
improper post-closeout disbursements are caught immediately.
Acceptance Criteria:
- System flags any payment where the associated grant status
is 'Closed'
- Flag includes grant_id, payment_id, and payment_amount
- Create each story in Jira using the same steps you followed for US-001: set the title, fill in the description and acceptance criteria, assign story points, and link to the Epic.
Speed up story creation
You can create multiple stories quickly from the backlog view by pressing Enter after each title, then opening each story to add details. This avoids navigating back and forth between the create dialog and the backlog.
Before you check your backlog, predict: how many total story points should you see across all five stories?
- Open the Backlog view and confirm all 5 stories are visible, each showing its story points and linked to the Treasury Payment Feed Integration Epic.
You should see 15 total story points (5 + 3 + 3 + 2 + 2) distributed across the five stories.
Stories not showing the Epic link?
If a story does not show the Epic connection, open the story detail and look for the Parent or Epic Link field. If neither field is visible, click Configure (gear icon) in the detail panel to add the field to your view.
Why aren't my stories linking to the Epic?
Embed Jira screenshots in Notion
Screenshots of your Jira backlog turn your portfolio from a self-reported claim into visual evidence. A hiring manager sees the same view a scrum team would see during sprint planning.
- In Jira, navigate to the Backlog view showing all 5 stories with their Epic link and story points.
- Take a screenshot of the full backlog view using Cmd+Shift+4 (macOS) or Win+Shift+S (Windows).
- Click into any one of the stories (US-001 is a good choice) to open the detail view showing the description and acceptance criteria.
- Take a screenshot of this detail view.
- Switch back to your Notion page and scroll to the User Stories section.
- Type /image to insert an image block, then upload your backlog screenshot.
- Below the backlog screenshot, add a brief annotation: "Jira backlog showing 5 user stories linked to the Treasury Payment Feed Integration Epic, totalling 15 story points."
- Insert another image block and upload your story detail screenshot.
- Add an annotation below it: "Story detail view showing the As-a/I-want/So-that description format and measurable acceptance criteria."
Why annotate screenshots?
Annotations tell the reviewer what to look for. Without them, a screenshot is just an image. A single sentence below each screenshot transforms it into evidence that demonstrates a specific BA skill.
- Confirm your Notion User Stories section now shows both screenshots with their annotations visible.
Screenshots not displaying in Notion?
Make sure you uploaded the image file rather than pasting a clipboard link. Notion's /image block supports PNG, JPG, and GIF uploads directly. If the image appears broken, try re-uploading the file.
Help me embed screenshots in Notion
Your Jira backlog now holds five well-structured stories, and your Notion portfolio has visual proof of your Agile BA work. Next up, you'll build a Requirements Traceability Matrix that maps each of these stories to a testable condition.
Build the Requirements Traceability Matrix and Data Flow Diagram
Your Jira backlog is loaded with 5 user stories linked to the Epic, and your Notion portfolio already showcases them with screenshots. The next question is whether those acceptance criteria are specific enough to actually test against.
A Requirements Traceability Matrix answers that question by mapping each story to a concrete validation method. You'll build one as a Notion database, then create a data flow diagram in Lucidchart showing how Treasury payment data moves through the integration.
In this step, get ready to:
- Build an inline Notion database as your Requirements Traceability Matrix.
- Evaluate each story's acceptance criteria for testability.
- Create a data flow diagram in Lucidchart and embed it in your portfolio.
Create the RTM database in Notion
The RTM lives inside your Notion portfolio page as an inline database. Each row maps one user story to its test case and validation status.
- Switch back to your Notion portfolio page and scroll down to the Requirements Traceability Matrix section (the H2 heading you created earlier).
- Click below the heading and type /Table view, then press Enter to insert an inline database.
- Rename the first column (the Title property) to Requirement ID.
- Click the + button at the right edge of the table header to add a new property. Name it User Story and set the type to Text.
- Add a third property named Acceptance Criteria Summary with type Text.
- Add a fourth property named Test Case ID with type Text.
- Add a fifth property named Validation Method with type Select. Create three options: Manual, Automated, and SQL.
- Add a sixth property named Status with type Select. Create three options: Testable, Untestable, and Validated.
You should now see an empty inline table with 6 columns. Next, populate it with your 5 user stories from Jira.
- Add 5 rows to the database, one for each user story. Fill in the following values for each row:
- Row 1: Requirement ID US-001, User Story Ingest Treasury Payment Feed, Acceptance Criteria Summary data is loaded accurately, Test Case ID TC-001, Validation Method SQL.
- Row 2: Requirement ID US-002, User Story Validate Referential Integrity, Acceptance Criteria Summary flags payments with no matching grant_id, Test Case ID TC-002, Validation Method SQL.
- Row 3: Requirement ID US-003, User Story Detect Overpayments, Acceptance Criteria Summary flags overpayments in a timely manner, Test Case ID TC-003, Validation Method SQL.
- Row 4: Requirement ID US-004, User Story Validate Payment Dates, Acceptance Criteria Summary flags payments dated before grant award_date, Test Case ID TC-004, Validation Method SQL.
- Row 5: Requirement ID US-005, User Story Flag Payments to Closed Grants, Acceptance Criteria Summary flags payments where grant status is Closed, Test Case ID TC-005, Validation Method SQL.
Leave the Status column empty for now. You'll set it in the next substep after evaluating each row.
Database not appearing inline?
If your table opened as a full page instead of inline, click the ... menu next to the database title and select Turn into inline. The table should now display within the portfolio page alongside your other content.
Help me fix my inline database display in Notion
Evaluate each story for testability
Now it is time to set the Status for each row. The test: could a developer write a concrete, pass-or-fail test for this acceptance criteria without asking you any clarifying questions?
- Look at row US-002: "flags payments with no matching grant_id." This is specific. A SQL LEFT JOIN query that returns orphan records would pass or fail this criterion. Set its Status to Testable.
- Look at row US-004: "flags payments dated before grant award_date." This is specific. A date comparison query would pass or fail this criterion. Set its Status to Testable.
- Look at row US-005: "flags payments where grant status is Closed." This is specific. A filtered JOIN on status would pass or fail this criterion. Set its Status to Testable.
Now look at US-001. Its acceptance criteria says "data is loaded accurately." Before you set a status, ask yourself: what does "accurately" mean here? What threshold? What metric would you check?
- You cannot write a SQL test for "accurately" because the criterion does not define what accurate means. Does it mean 100% row count match? Zero duplicates? Loaded within 5 minutes? Set the Status for US-001 to Untestable.
- Now look at US-003. Its acceptance criteria says "flags overpayments in a timely manner." What does "timely" mean? Within 1 hour? Within the nightly batch? There is no measurable threshold here either. Set the Status for US-003 to Untestable.
You have just identified the gap. Two out of five stories have criteria too vague to trace to a quantitative test.
- Below the RTM database, add a Notion callout block (type /callout and press Enter).
- Type the following text inside the callout: "Gap identified: 2 acceptance criteria cannot be mapped to quantitative test conditions."
Your RTM now has 5 rows with 3 marked Testable and 2 marked Untestable, plus a callout flagging the gap.
Why does testability matter in federal BA work?
The PBGC OIT Requirements Document Standard requires every requirement to be Testable, meaning it can be verified against quantitative criteria. Vague acceptance criteria like "loaded accurately" or "in a timely manner" fail this standard because no one can write a definitive pass/fail test.
Catching this gap now, before development starts, is one of the highest-value activities a Sr. BA performs. You will fix these criteria in the next step.
Not sure which rows to mark Untestable?
The key question is: does the acceptance criteria contain a specific, measurable condition? "Flags payments with no matching grant_id" has a clear SQL-testable condition (the LEFT JOIN returns rows). "Data is loaded accurately" does not define what "accurately" means in numeric terms.
Help me evaluate whether my acceptance criteria are testable
Create the data flow diagram in Lucidchart
The data flow diagram shows stakeholders how Treasury payment data enters the system and where validation happens. This visual artifact complements the RTM by mapping the architecture the test cases will validate.
- Switch to Lucidchart in your browser.
- Click + New, select Lucidchart, then select Blank document.
- Click the diagram title in the top left corner and rename it to Treasury Payment Feed Data Flow.
What shapes do I need?
In the left-hand Shapes panel, look for the data flow shape library. It contains four symbol types: External Entity (rectangle), Process (rounded rectangle or circle), Data Store (open-ended rectangle), and Data Flow (arrow). You'll use all four.
- Drag an External Entity shape onto the left side of the canvas. Label it Treasury Bureau of the Fiscal Service.
- Drag a Process shape to the right of the entity. Label it File Intake.
- Draw a data flow arrow from the External Entity to the File Intake process. Label the arrow Daily CSV.
- Drag a Data Store shape below the File Intake process. Label it treasury_payments.
- Draw an arrow from File Intake down to the treasury_payments data store. Label it Load records.
- Drag a second Data Store shape and place it below and to the right. Label it grants.
- Drag a second Process shape to the right of both data stores. Label it Reconciliation Engine.
- Draw arrows from both treasury_payments and grants into the Reconciliation Engine. Label them Read payments and Read grants.
You now have the input side of the flow. The Reconciliation Engine reads from both tables and applies the validation rules you mapped in the RTM.
- Drag two more shapes to the right of the Reconciliation Engine: one labeled Reconciliation Report and one labeled Exception Queue.
- Draw arrows from the Reconciliation Engine to both outputs. Label them Generate report and Flag exceptions.
Your diagram should now show the complete flow: Treasury Bureau sends a daily CSV to File Intake, which loads into treasury_payments. The Reconciliation Engine reads from both tables and outputs a report plus an exception queue.
- Export the diagram as a PNG by clicking File in the top menu, hovering over Export, and selecting PNG. Click Download.
- Switch back to your Notion portfolio page and scroll to the Data Flow Diagram section.
- Type /image and press Enter, then upload the PNG you just exported.
The diagram should now appear inline on your Notion portfolio page under the Data Flow Diagram heading.
Diagram looks blurry in Notion?
When exporting from Lucidchart, make sure you select a high quality setting before clicking Download. Lucidchart defaults to standard resolution which can appear fuzzy when embedded. Re-export at higher quality if needed.
Help me export my Lucidchart diagram at higher resolution
Your portfolio now has two major analytical artifacts: an RTM that maps every requirement to a test, and a data flow diagram that shows stakeholders the integration architecture. In the next step, you'll fix the two untestable criteria and prove the validation rules catch real data issues with SQL.
Refine Acceptance Criteria and Validate with SQL
In the last step, your Requirements Traceability Matrix exposed a real problem. Two acceptance criteria are too vague to trace to a concrete test condition.
"Data is loaded accurately" and "flags overpayments in a timely manner" sound reasonable in a sprint planning meeting. But no QA engineer can write a pass/fail test against them. In this step, you rewrite both criteria into specific, measurable conditions and then prove your validation rules catch real data quality issues with SQL.
In this step, get ready to:
- Rewrite the two flagged acceptance criteria in Jira with quantitative thresholds.
- Execute four SQL validation queries that catch orphan payments, overpayments, date mismatches, and closed-grant payments.
- Document the test results in Notion and update the RTM to show all requirements validated.
Rewrite the flagged acceptance criteria in Jira
The PBGC OIT Requirements Document Standard states that every requirement must be "Testable" against quantitative criteria. Your RTM flagged US-001 and US-003 because their acceptance criteria fail that test.
- Switch back to your Jira project board.
- Open story US-001 ("Ingest Treasury Payment Feed").
- In the Description field, find the Acceptance Criteria section.
- Replace "data is loaded accurately" with the following measurable criteria:
Acceptance Criteria:
- 100% of rows from the daily CSV are loaded into treasury_payments within 15 minutes of file receipt.
- Row count in treasury_payments matches row count in source file.
- Zero duplicate payment_id values after load.
Why these three conditions?
Each line targets a different failure mode. The 15-minute SLA catches integration timeouts. The row count match catches dropped records during file parsing. The zero-duplicate check catches replay issues where the same file is ingested twice.
- Click Save on US-001.
- Open story US-003 ("Detect Overpayments").
- Replace "flags overpayments in a timely manner" with the following:
Acceptance Criteria:
- System flags any grant where SUM(payment_amount) for all linked treasury_payments exceeds the grant award_amount by more than $0.01.
- Flags are generated within the nightly reconciliation batch.
Why $0.01 instead of $0?
Floating-point arithmetic in financial systems can produce rounding differences at the sub-penny level. The $0.01 threshold avoids false positives from rounding while still catching real overpayments.
- Click Save on US-003.
- Return to your backlog view and confirm both stories now show the updated descriptions.
- Take a screenshot of the updated US-001 detail view showing the new acceptance criteria.
- Take a screenshot of the updated US-003 detail view showing the new acceptance criteria.
Can't edit the description?
Make sure you click directly into the Description field on the story detail view. If the field appears locked, check that you are logged in as the project admin (the account that created the project).
Help me update my Jira story acceptance criteria
Run the SQL validation queries against your sample data
Now you have testable acceptance criteria. Time to prove the validation rules actually catch data quality issues hiding in the Treasury payment feed. Each query targets one specific defect category from your user stories.
Before you run the first query, think about what you expect. Your treasury_payments table has 7 rows. How many of those reference a grant_id that does not exist in the grants table?
- Switch back to your SQL environment.
- Run the orphan check query (TC-001) to find payments referencing non-existent grants:
-- Test Case TC-001: Orphan Check
-- Validates US-002: Payments with no matching grant in the system
-- Expected: Returns PAY-50005 (references non-existent GRT-2024-006)
SELECT
tp.payment_id,
tp.grant_reference,
tp.payment_amount,
tp.payment_date
FROM treasury_payments tp
LEFT JOIN grants g ON tp.grant_reference = g.grant_id
WHERE g.grant_id IS NULL;
What does this query do?
The LEFT JOIN keeps every payment row even when there is no matching grant. The WHERE g.grant_id IS NULL filter then isolates only the orphans. These are payments the system cannot reconcile because the grant reference does not exist.
You should see 1 row returned: PAY-50005 referencing non-existent grant GRT-2024-006.
Query returns zero rows?
Confirm your treasury_payments table has 7 rows by running SELECT COUNT(*) FROM treasury_payments. If it returns fewer than 7, re-run the INSERT statements from Step 1.
Help me debug my orphan check SQL query
- Take a screenshot of the query and its result.
- Run the overpayment check query (TC-002) to find grants where total disbursements exceed the award amount:
-- Test Case TC-002: Overpayment Check
-- Validates US-003: Total payments exceeding grant award amount
-- Expected: Returns GRT-2024-002 (award: $250,000, paid: $275,000, over by $25,000)
SELECT
g.grant_id,
g.grantee_name,
g.award_amount,
SUM(tp.payment_amount) AS total_paid,
SUM(tp.payment_amount) - g.award_amount AS overpayment
FROM grants g
JOIN treasury_payments tp ON g.grant_id = tp.grant_reference
GROUP BY g.grant_id, g.grantee_name, g.award_amount
HAVING SUM(tp.payment_amount) > g.award_amount;
What does this query do?
The query groups all payments by their linked grant, sums the payment amounts, and filters for grants where the total exceeds the award amount. The overpayment column calculates exactly how much the grant has been overpaid. This is the rule your updated US-003 acceptance criteria defines.
You should see 1 row: GRT-2024-002 (County Transit Auth) with an award of $250,000, total paid of $275,000, and an overpayment of $25,000.
Getting a GROUP BY error?
Some SQL engines require every non-aggregated column in the SELECT to appear in the GROUP BY clause. Make sure g.grant_id, g.grantee_name, g.award_amount are all listed in your GROUP BY.
Help me fix my GROUP BY clause for the overpayment query
- Take a screenshot of the query and its result.
- Run the payment date validation query (TC-003) to find payments that occurred before the grant was even awarded:
-- Test Case TC-003: Payment Date Validation
-- Validates US-004: Payments dated before the grant award date
-- Expected: Returns PAY-50006 (payment 2024-04-15, award date 2024-04-20)
SELECT
tp.payment_id,
tp.grant_reference,
tp.payment_date,
g.award_date,
g.award_date - tp.payment_date AS days_before_award
FROM treasury_payments tp
JOIN grants g ON tp.grant_reference = g.grant_id
WHERE tp.payment_date < g.award_date;
What does this query do?
The WHERE clause filters for payments dated before the grant's award_date. The days_before_award column shows how many days early the payment arrived. A payment before an award date is a red flag that either the payment was misrouted or the award date is wrong.
You should see 1 row: PAY-50006 with a payment date of 2024-04-15 against a grant awarded on 2024-04-20.
SQL Server users
The date subtraction g.award_date - tp.payment_date works in PostgreSQL and MySQL. If you are using SQL Server, replace it with DATEDIFF(day, tp.payment_date, g.award_date) to get the same result.
- Take a screenshot of the query and its result.
- Run the closed grant check query (TC-004) to find payments against grants that have already been closed:
-- Test Case TC-004: Closed Grant Payment Check
-- Validates US-005: Payments against grants with status 'Closed'
-- Expected: Returns PAY-50004 (payment to GRT-2024-003 which is Closed)
SELECT
tp.payment_id,
tp.grant_reference,
tp.payment_amount,
g.status AS grant_status,
g.grantee_name
FROM treasury_payments tp
JOIN grants g ON tp.grant_reference = g.grant_id
WHERE g.status = 'Closed';
What does this query do?
This query joins payments to their linked grants and filters for grants with a Closed status. A payment arriving after closeout indicates either a delayed disbursement that needs reversal or a grant that was reopened without updating the status field.
You should see 1 row: PAY-50004 with a $50,000 payment to GRT-2024-003 (Rural Ed Consortium), which has status Closed.
Seeing zero rows on the closed grant check?
The status filter is case-sensitive in most SQL engines. Make sure your WHERE clause uses 'Closed' with a capital C, matching the value inserted in your sample data.
Help me troubleshoot my closed grant SQL query
- Take a screenshot of the query and its result.
All four queries returned at least one row. Each row represents a real data quality issue your validation rules successfully caught.
✔️ Awesome, I've got everything!
Great. Confirm you have 4 screenshots saved (one per query result). You will embed these in Notion in the next substep.
ⓧ I'd like to double check the full code
Scroll up and confirm you have all four query chunks present in order:
- TC-001: Orphan Check (LEFT JOIN with WHERE IS NULL).
- TC-002: Overpayment Check (GROUP BY with HAVING).
- TC-003: Payment Date Validation (WHERE payment_date < award_date).
- TC-004: Closed Grant Payment Check (WHERE status = 'Closed').
Each query should have returned exactly 1 row when you ran it against the sample data.
Document test results and close the traceability loop in Notion
Your SQL results prove the validation rules work. Now you need to record those results in your portfolio so a hiring manager can trace from requirement to test to evidence.
- Return to your Notion project page.
- Scroll to the Test Cases and Validation section (currently empty).
- Create an inline table with these columns: Test Case ID (Title), Linked Requirement (Text), Test Description (Text), Expected Result (Text), Actual Result (Text), Status (Select: Pass/Fail).
- Add a row for TC-001: Linked Requirement = US-002, Test Description = "Orphan Check: payments with no matching grant", Expected Result = "PAY-50005 returned", Actual Result = "PAY-50005 returned", Status = Pass.
- Add a row for TC-002: Linked Requirement = US-003, Test Description = "Overpayment Check: total payments exceeding award", Expected Result = "GRT-2024-002 overpaid by $25,000", Actual Result = "GRT-2024-002 returned", Status = Pass.
- Add a row for TC-003: Linked Requirement = US-004, Test Description = "Date Validation: payments before award date", Expected Result = "PAY-50006 returned", Actual Result = "PAY-50006 returned", Status = Pass.
- Add a row for TC-004: Linked Requirement = US-005, Test Description = "Closed Grant Check: payments to closed grants", Expected Result = "PAY-50004 returned", Actual Result = "PAY-50004 returned", Status = Pass.
Why link test cases to user stories?
This is requirements traceability in action. A hiring manager can follow the thread from business need (user story) to verification (test case) to evidence (SQL screenshot). That chain proves you do not just write requirements. You validate them.
- Below the table, embed all 4 SQL query screenshots you saved earlier.
- Scroll up to your Requirements Traceability Matrix database.
- Update the Status column for US-001 from "Untestable" to "Validated".
- Update the Status column for US-003 from "Untestable" to "Validated".
- Confirm US-002, US-004, and US-005 are also set to "Validated" (they were already marked "Testable" and now have passing test evidence).
Your RTM should now show all 5 rows with the Status column reading "Validated." The gap callout from the previous step still sits below the RTM as a record of the problem you solved.
Not sure which rows to update?
In Notion, click the cell in the Status column for each row to change the select value. If you do not see "Validated" as an option, click Create to add it as a new select option. Apply it to all 5 rows.
Help me update my Notion database select options
Your portfolio now tells a complete story. A vague requirement led to an untestable condition. You identified the gap, rewrote the criteria with measurable thresholds, and proved with SQL that the validation rules catch real defects. Next up, you will package this work into operational documentation that proves you think beyond testing.
Write the SOP and Release Notes
Your SQL validation queries just proved the integration rules catch real data quality issues. That evidence is powerful, but a hiring manager also needs to see that you can communicate what was built to people who were not in the sprint.
A BA's job does not end at testing. The operations team needs a procedure document so they can run the feed without you present. Stakeholders need release notes that explain what changed and why. In this step, you will write both documents and tie the entire portfolio together with a completed executive summary.
In this step, get ready to:
- Write a Standard Operating Procedure for the daily reconciliation process.
- Create release notes documenting the enhancement delivery with story IDs.
- Complete the TL;DR executive summary and review the full portfolio.
Write the Standard Operating Procedure in Notion
A Standard Operating Procedure (SOP) is the document an operations team follows when the BA who designed the process is no longer in the room. It must be precise enough that someone unfamiliar with the project can execute it correctly on day one.
- Switch back to your Notion portfolio page.
- Scroll down to the SOP section (the empty H2 heading you created in Step 1).
- Add an H3 heading: Daily Treasury Payment Feed Reconciliation.
Below the title, create the following sections as bold labels or sub-headings, then fill in the content for each one:
- Purpose: Write one sentence explaining this SOP defines the daily process for ingesting and reconciling Treasury payment data against the grants management system.
- Scope: Write one sentence stating this applies to the nightly automated reconciliation batch for all active grant disbursements received via the Treasury Bureau of the Fiscal Service CSV feed.
- Responsibilities: List three roles. Feed Administrator (monitors file intake and staging load). Data Steward (reviews exception flags and data quality). Grants Program Manager (approves reconciled records and escalates overpayments).
- Prerequisites: List what must be in place before the procedure runs. Access to the file intake server, database credentials for the grants system, and the current validation rule configuration.
Now add the core of the SOP. The Procedure section is where most hiring managers focus because it shows you can translate a technical process into repeatable operational steps.
- Add a Procedure sub-heading.
- Write a numbered list with 7 steps covering the full daily cycle:
- Step 1: Receive the daily CSV file from the Treasury Bureau of the Fiscal Service secure file transfer.
- Step 2: Validate file structure (confirm expected column headers, row count, and file naming convention).
- Step 3: Load validated records into the treasury_payments staging table.
- Step 4: Run the four automated validation rules (orphan check, overpayment detection, date validation, closed grant check).
- Step 5: Review flagged exceptions in the exception queue and assign to the appropriate role.
- Step 6: Approve reconciled records that passed all validation rules and mark as final.
- Step 7: Archive the source CSV file with a date-stamped filename for audit trail.
- Below the procedure, add an Exception Handling section. Write 2-3 sentences explaining that exceptions are routed to the Data Steward for triage within one business day. Unresolved exceptions escalate to the Grants Program Manager.
- Add a Revision History table at the bottom with columns: Version, Date, Author, Change Description. Add one row: Version 1.0, today's date, your name, "Initial SOP creation."
Your SOP section should now show a complete, structured document with clear headings and a numbered procedure. Scroll through it to confirm every section has content.
Why does an SOP matter in a portfolio?
Federal IT projects require documented handoff procedures because the BA who designed the process is rarely the person who operates it long-term. An SOP in your portfolio proves you think beyond "build and ship" into "run and maintain."
Hiring managers at firms like Karsun Solutions specifically look for this skill because their agency clients (DHS, FAA, GSA) mandate operational documentation for every system change.
Write the release notes in Notion
Release notes communicate what shipped to stakeholders who were not involved in the sprint. They reference the exact story IDs from your backlog so anyone can trace a delivered feature back to its original requirement.
- Scroll down to the Release Notes section of your Notion page.
- Add an H3 heading: Release 2.4.0 - Treasury Payment Feed Integration.
Below the heading, create these sections with their content:
- Release Date: Enter today's date.
- Release Summary: Write one paragraph stating this release introduces automated Treasury payment feed integration, replacing manual spreadsheet reconciliation with system-driven validation and exception management.
- Features Delivered: Create a bulleted list with each user story ID and title from your Jira backlog:
- US-001: Ingest Treasury Payment Feed.
- US-002: Validate Referential Integrity.
- US-003: Detect Overpayments.
- US-004: Validate Payment Dates.
- US-005: Flag Payments to Closed Grants.
- Known Limitations: Write 2-3 bullet points noting realistic constraints. For example: duplicate detection covers exact payment_id matches only (not fuzzy matching), validation runs nightly (not real-time), and manual override is not yet supported for false-positive flags.
- Dependencies: List what this release depends on. Treasury Bureau of the Fiscal Service daily CSV delivery, grants system database availability, and nightly batch scheduling infrastructure.
- Rollback Procedure: Write 2-3 sentences describing how to revert. Disable the automated file intake job, restore the previous reconciliation spreadsheet process, and notify the Grants Program Manager of the rollback.
Scroll through your release notes section. You should see a structured document with a release date, summary paragraph, five story IDs in the Features Delivered list, and practical sections for limitations, dependencies, and rollback.
Why reference story IDs in release notes?
Tracing delivered features back to their original story IDs closes the loop between planning and delivery. Anyone reading the release notes can jump to the Jira story and see the full acceptance criteria, test evidence, and sprint history. This is the requirements traceability principle in action.
Not sure what to write for Known Limitations?
Think about what the system does NOT do yet. Every release has boundaries. Limitations are not failures. They are honest documentation of scope that builds trust with stakeholders.
Help me write realistic known limitations for a federal data integration release.
Complete the TL;DR and review your portfolio
The TL;DR callout at the top of your portfolio page has been sitting with placeholders since Step 1. Now that every section is complete, you have the full picture to write a concise executive summary.
- Scroll to the top of your Notion portfolio page.
- Find the TL;DR callout block with the Problem, Solution, and Impact placeholders.
- Replace the Problem placeholder with: Manual reconciliation is error-prone and delays SF-224 reporting.
- Replace the Solution placeholder with: Automated daily feed integration with validation rules.
- Replace the Impact placeholder with: Eliminates manual reconciliation, catches 4 categories of data quality issues before they reach financial reports.
Why does the TL;DR matter so much?
A hiring manager reviewing your portfolio link may spend fewer than 30 seconds on the page before deciding whether to scroll deeper. The TL;DR callout at the top gives them the Problem, Solution, and Impact in three lines. If those three lines are sharp, they keep reading.
Now review the entire portfolio from top to bottom. Every section should have content, and all screenshots should be visible.
- Scroll through the full page and confirm each section has content:
- TL;DR callout: Problem, Solution, Impact filled in.
- Scenario Overview: paragraph describing the federal grants reconciliation context.
- User Stories: Jira backlog screenshot and story detail screenshot with annotations.
- Requirements Traceability Matrix: inline database with 5 rows, all showing "Validated" status.
- Data Flow Diagram: embedded Lucidchart PNG.
- Test Cases and Validation: 4-row table with embedded SQL screenshots.
- SOP: "Daily Treasury Payment Feed Reconciliation" with numbered procedure steps.
- Release Notes: "Release 2.4.0" with Features Delivered listing US-001 through US-005.
Missing screenshots or broken images?
If any embedded screenshot shows as a broken image or placeholder, re-upload the image file directly into Notion. Pasted images from clipboard occasionally fail to save if you navigated away before the upload completed.
Help me fix broken image embeds in my Notion portfolio page.
Your portfolio now contains a complete set of BA deliverables from requirements through release documentation. Every section in the page has real, structured content that a hiring manager can review. Next up, you will tackle the Secret Mission and add training materials that prove stakeholder communication skills.
Secret mission
Build a Training Presentation and JAD Session Agenda
Your portfolio proves you can write requirements and validate data. But can you communicate technical changes to non-technical stakeholders and facilitate structured discovery sessions? Training presentations and JAD facilitation are the most visible Senior BA skills on any federal engagement.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on free-tier tools and local files, so there are no ongoing costs.
Resources you used:
- Notion portfolio page (BA Portfolio / Federal Grants Payment Data Integration).
- Jira Cloud project (Grants Payment Integration) with Epic and 5 user stories.
- Lucidchart data flow diagram (Treasury Payment Feed Data Flow).
- SQL tables (grants and treasury_payments) in your SQL environment.
- Local SQL files (sample_data.sql and validation_queries.sql).
- Training presentation (PowerPoint or Google Slides).
Keep everything running
No action needed. Choose this if you plan to share the portfolio link with hiring managers or continue refining your artifacts.
- Your Notion portfolio page remains live and shareable at its current URL.
- Your Jira project stays accessible for future reference or iteration.
- Your Lucidchart diagram stays editable and exportable.
- Your SQL tables and local files remain on your machine.
- All tools used are on free plans, so nothing here incurs cost.
Pause - I'll come back to this later
Free up local disk space and SQL resources while keeping your cloud-based portfolio intact for later.
- Keep your Notion page, Jira project, and Lucidchart diagram as they are. They cost nothing on free plans.
- Drop the SQL tables if you need to free up space in your SQL environment. Run:
- DROP TABLE treasury_payments; and DROP TABLE grants; in your SQL client.
- Keep your local sample_data.sql and validation_queries.sql files so you can reload the data later.
Delete - I don't want to use this again
Remove all project resources completely. Only do this if you are certain you no longer need any of these artifacts.
- In Notion, open the BA Portfolio page. Click the three-dot menu at the top right, then select Move to Trash. This removes the portfolio page and all subpages.
- In Jira Cloud, go to Project Settings in the left sidebar of your Grants Payment Integration project. Scroll to the bottom and click Move to trash. Confirm the deletion when prompted.
- In Lucidchart, locate your Treasury Payment Feed Data Flow diagram in your documents list. Click the three-dot menu on the document card, then select Delete.
- Drop the SQL tables by running these commands in your SQL environment:
DROP TABLE treasury_payments;
DROP TABLE grants;
- Delete your local SQL files. On macOS/Linux, run:
rm sample_data.sql validation_queries.sql training_deck_outline.md
On Windows, run:
Remove-Item sample_data.sql, validation_queries.sql, training_deck_outline.md
- If you created a training presentation in Google Slides, open Google Drive, right-click the file, and select Move to trash. If you used PowerPoint, delete the local file from your computer.
Nice Work!
Nice Work!
You just built a complete, interview-ready Senior BA portfolio grounded in a realistic federal data integration scenario. When a hiring manager opens your Notion link, they see end-to-end proof of the Agile BA lifecycle from requirements elicitation through validated delivery.
You've learned how to:
- Write user stories with testable acceptance criteria in Jira, discover untestable gaps through a Requirements Traceability Matrix, and resolve those gaps with measurable thresholds.
- Validate data quality rules with SQL queries that caught real reconciliation issues: orphan payments, overpayments, date mismatches, and payments to closed grants.
- Produce production-ready SOP documentation, release notes, and a data flow diagram that together form a shareable deliverable package in Notion.
- Secret Mission: Created a training presentation deck and JAD session agenda proving stakeholder communication and facilitation skills.
Ready to quiz yourself?