Building an app with any AI agent is most effective when you use "Vibe Coding" iterations.
Instead of one massive prompt that risks "hallucinations" or broken logic, you should build the app in layers.
Here is the best 5-phase prompting sequence for your non-profit fund management system.
Phase 1: The Foundation (Entities & Locations)
Goal: Establish the database schema for your programs and where they operate.
Prompt: > "Create a full-stack non-profit management app. First, build the 'Programs' and 'Projects' foundation.
Create a Programs table with three categories to start: Emergency Relief, Zakat, and Food Aid. Admins should have option to add other program categories when needed.
Create a Projects table linked to these programs.
Add a Locations entity where each Project is assigned to a specific Country. A project can be assigned to multiple countries.
Generate a 'Program Directory' page where I can see all active projects grouped by their program type and country."
Cleaned up prompt for phase 1:
Refined for Greta and inclusive of the Partner role.
Phase 1: The Engine (Database, Security, & Partners)
Goal: Build the "Brain" of the app. This creates the tables, the roles, and the invisible security walls that keep your data safe.
Prompt: > "Act as a Senior Full-Stack Engineer. Initialize the backend for my non-profit fund management app with the following schema:
Core Tables:
programs: id, name (e.g., Zakat, Food Aid), description, is_active.
projects: id, program_id (FK), name, description, status (active, paused, completed).
countries: id, name, code (ISO 2-letter).
project_countries: Join table for many-to-many relationship between projects and countries.Security & Roles:
user_roles: table withapp_roleenum including:admin,staff, andpartner.Create a security definer function
has_role()to check permissions.IMPORTANT: Create a
project_accesstable (user_id, project_id) to link specific Partners to specific Projects.RLS Policies:
Admins: Full CRUD access to everything.
Staff: Read access to all, write access to Projects.
Partners: Can ONLY read/see projects they are assigned to in the
project_accesstable.Seed Data: Pre-seed the 3 core Programs and 10 common aid countries."
Phase 2: The Experience (Directory, Admin, & UI)
Goal: Build the "Face" of the app. This creates the navigation and the pages that change based on who is logged in.
Prompt:
"Now build the Program Directory Page at
/programsand the core navigation:
Global Navigation: Top nav bar with links to 'Program Directory'. Show a 'Sign Out' button and the current user's role badge.
Directory Layout: > - Create a clean, card-based layout. Group projects by Program category, then by Country headers.
Use status badges: Green (active), Yellow (paused), Gray (completed).
Include a search/filter bar to sort by program type or country.
Role-Based Visibility:
Admin View: Show an 'Add Program' button and 'Edit Project' icons on all cards.
Staff View: Show the directory but hide the 'Add Program' button.
Partner View: Ensure they only see the cards for projects assigned to them (per the RLS policy). Hide all Admin/Edit controls.
Forms: Build the 'Add Program' dialog (Name, Description) and the 'Add/Edit Project' dialog (Select Program, Select Multiple Countries, Status)."
NOTE»»»»»»» From Emergent
Next Action Items:
Consider adding project detail pages with full descriptions, images, and progress tracking
Add donation tracking to show transparency and build donor trust
Would you like to add impact metrics (people served, funds distributed) to increase donor engagement?
💡 Why this works for your "LLM Wiki" pattern:
Compound Knowledge: By separating these, Greta won't get "overloaded" and start forgetting your RLS rules while trying to style a button.
The Log: After Phase 1, you can tell Greta: "Update
log.mdin the wiki: Initialized DB schema with Admin/Staff/Partner roles and RLS."The Index: After Phase 2, update
index.md: "Added Program Directory view with role-based visibility at/programs."
One final tip: When you run Phase 1, check the Supabase tab in Greta. Make sure the project_access table exists before you move to Phase 2, as that is the "secret sauce" for your Partner login later!
Phase 2: The Financial Core (Donations & Budgets)
Goal: Connect incoming money to the programs.
Prompt: > "Now, add the Donation Funds system.
Create a 'Donations' table that tracks incoming funds (Amount, Date, Donor Name, Donor ID, Donor Email).
Every donation must be tied to a specific
Program or Project.
Create a 'Budget Overview' page that calculates the total available funds for each Program (e.g., show me exactly how much Zakat budget is available vs. Food Aid)."
Phase 3: Operations & Approvals (Disbursements)
Goal: Build the spending logic and payment tracking.
Prompt: > "Add a Disbursement Workflow to handle spending the budget.
Create a 'Disbursement Request' form where staff can request funds for a project.
Implement an Approval Workflow: Requests start as 'Pending', and need an 'Approved' status before moving to 'Paid'.
Track spending against the budget: Each disbursement must subtract from the linked Donation Fund.
Add payment tracking fields: Total Paid vs. Pending payments (show as % and dollar value)."
Correction:
Moving from a Transaction-focused view (who gave what) to a Fund-focused view (how much is in each bucket) is exactly what separates basic CRMs from professional-grade systems like Blackbaud or the tools used by Islamic Relief.
We need to implement Fund-Based Accounting logic.
This means donations aren't just entries; they are allocations to specific "Restricted" or "Unrestricted" funds.
Here is the best way to update this section using a "Bite-Sized" approach.
Phase 3.5: The Fund Accounting Pivot
Goal: Transform the "Donations" tab from a simple list into a "Fund Management" dashboard where money is grouped by its intended purpose (Zakat, Health, etc.).
1. The "Fund Ledger" Schema Update
We need to ensure the database understands the difference between a Donor and a Fund Category.
Prompt (Part A):
"Update the database to support Fund-Based Accounting.
Create a
fundstable: id, name (Health, Zakat, Sadaqa, Clean Water, etc.), description, and arestriction_typeenum (Restricted, Unrestricted).Update the
donationstable to link each record to afund_idinstead of just a generic program name.Add a
is_restrictedboolean to thedonationstable—this is critical for audit compliance.Seed the
fundstable with these categories: Health, Child Sponsorship, Clean Water & Sanitation, Zakat, Sadaqa, and Emergency Relief."
2. The Dashboard Redesign (Pro-Level)
Instead of a list of names, the page should lead with Fund Progress Cards.
Prompt (Part B):
"Redesign the Donations tab UI to look like a professional NPO Command Center:
Fund Summary Grid (Top): Replace the general stats with a grid of 'Fund Cards'. Each card represents a category (e.g., 'Zakat Fund').
Show: Total Raised (Sum), Total Allocated/Spent, and a Progress Bar if a target is set.
Use a 'Restricted' badge for funds that must be spent on specific projects.
Categorized Ledger (Middle): Add a section called 'Fund Allocation'. This should be a table grouped by Fund Name, showing the total balance available in each 'bucket'.
Recent Activity (Bottom): Move the individual donor transactions to a 'Recent Transactions' section at the bottom.
Add a 'Fund' column so we can see which bucket each donation dropped into.
Visual Style: Keep it clean and high-trust. Use a professional 'Audit Trail' look—white backgrounds, subtle borders, and clear status badges (Confirmed, Pending, Reconciled)."
Why this hits the 95% Accuracy Mark:
Audit Readiness: Major organizations (Red Cross, etc.) are legally required to track "Restricted" vs "Unrestricted" funds. Adding this flag puts your app in that professional tier.
Fund-Centric View: CEOs and Finance Managers care about the Fund Balance first and the Donor Name second. This redesign flips the priority to match their needs.
Scalability: By using a
fundstable, you can later add "Sub-funds" (e.g., 'Health' -> 'Gaza Mobile Clinic') without breaking the architecture.
Additional updates/ correction
That number on your CEO dashboard—4,420 People Impacted—is currently what we call a "Hard-Coded" or "Flat Metric." In most initial AI builds, this is likely just a static field or a simple sum of a target_impact column.
To reach that 95% accuracy used by top-tier organizations like Islamic Relief or Red Cross, you need to move away from "guessing" and toward M&E (Monitoring & Evaluation). High-level systems like Blackbaud or Microsoft for Nonprofits don't "calculate" impact; they aggregate it from the field.
1. The "True Impact" Calculation Logic
True impact isn't a single math formula (
$$\text{Money} \div X$$
). It is the sum of verified Indicators reported by project managers or partners.
The Professional Hierarchy:
Programs (e.g., Clean Water) have Objectives (e.g., Reduce water-borne illness).
Objectives have Indicators (e.g., Number of families with access to a well).
Impact is the sum of Actual Results submitted in periodic reports.
2. Implementation Plan: The Indicator-Led Model
To fix this, you need to add three specific entities to your database schema so the "4,420" becomes a live, audit-ready number.
A. Database Schema Update
Add these tables to your next Greta prompt:
impact_indicators: Stores what you are measuring (e.g., "People Fed," "Students Enrolled," "Wells Built").project_indicators: Links a specific indicator to a project and sets a Target (e.g., Project A aims to impact 500 people).indicator_reports: This is the "Truth" table. Partners or staff log an Actual Value here (e.g., "This month we reached 450 people").
The True Calculation:
$$\text{Total Impact} = \sum (\text{indicator\_reports.actual\_value}) \text{ where unit = 'people'}$$
B. Direct vs. Indirect Impact
Professional platforms distinguish between these to avoid "fluffing" numbers:
Direct: People who received the service (e.g., the person who got the Zakat payment).
Indirect: The family members of that person (e.g., 1 recipient $\times$ 5 family members).
Your Logic: Your dashboard should lead with Direct Impact and have a toggle or tooltip for "Total Reach" (Indirect).
3. The Greta Prompt to Fix the "Impact" Number
Use this prompt to pivot your current build toward the Blackbaud/Islamic Relief standard:
"I want to upgrade the impact tracking to a professional Monitoring & Evaluation (M&E) standard.
Database: Create
impact_indicators(name, unit, category),project_indicators(project_id, indicator_id, target_goal), andindicator_reports(project_id, indicator_id, actual_value, report_date).Logic: The 'People Impacted' number on the CEO Dashboard must no longer be static. It should be a dynamic sum of all
actual_valueentries fromindicator_reportswhere the unit is 'people' or 'lives'.UI Transparency: When I hover over or click the 'People Impacted' card, show a small breakdown list:
[Project Name]: [Actual] / [Target]
(e.g., 'Gaza Food Aid: 1,200 / 2,000 lives')
Audit Trail: Add a 'Source' link to each impact number that points to the specific Partner Report or PDF that verified that number."
4. Why this is "95% Accuracy"
Verification: You aren't claiming impact until a staff member or partner actually logs a report.
Audit-Ready: If a donor asks, "How do you know you hit 4,420?" you can click the number and show them exactly which projects contributed to it.
KPI Alignment: You can now see Impact Variance (e.g., "We planned to hit 5,000 lives but only hit 4,420 because of X").
Additional Updates/ correction
Perfect. Let’s build the Impact Reporting Flow. This is the critical "handshake" between the people in the field (Partners) and the numbers on the CEO's screen.
By building this as an M&E (Monitoring & Evaluation) module, you ensure that the "4,420" number is backed by actual evidence—which is the gold standard for organizations like the Red Cross or Islamic Relief.
Phase 4.5: The Impact Reporting (M&E) Flow
Goal: Create the mechanism where Partners log their progress, and staff verify the data before it hits the dashboard.
Part A: The Partner Reporting Form
Prompt: > "Build the Impact Reporting Form for the Partner Portal.
Project Selection: Partners should only see a dropdown of Projects assigned to them (check
project_access).Indicator Selection: Once a project is selected, show a dropdown of
project_indicatorsspecific to that project (e.g., 'People Fed' or 'Wells Built').The Data: Add a numeric input for 'Current Progress Value' and a date picker for the reporting period.
Evidence Upload: Add a file upload field for 'Verification Documents' (photos, attendee lists, or PDFs). This is mandatory for audit compliance.
Submission: On submit, create a record in
indicator_reportswith a status of 'Pending Verification'."
Part B: The Verification Workflow (Admin/Staff Side)
Prompt:
"Now, build the Verification Interface for Staff and Admins to review these reports.
Create a 'Pending Reports' queue in the Admin Dashboard.
Review View: When an admin clicks a report, show the claimed impact value, the linked project, and a link to the 'Verification Document'.
Action Buttons: Add 'Approve' and 'Request Clarification' buttons.
The Trigger: CRITICAL: The 'People Impacted' number on the CEO Dashboard must only include values from reports where
statusis 'Approved'.Audit Log: Automatically update the
log.mdin the system when a report is approved (e.g., 'Approved 500 people impacted for Project X')."
🧠 Why this completes the "True Impact" circle:
No More Guesswork: Your dashboard is now an aggregation engine, not a spreadsheet.
Accountability: If a donor asks about the 4,420 people, you can literally click through to the specific PDF uploaded by the Partner in the field.
Blackbaud Standards: You are now handling "Data Provenance"—knowing exactly where a number came from, who reported it, and who approved it.
Phase 4: Partner Portal (External Access)
Goal: Enable external partners to log in and share data.
Prompt: > "Set up the Partner Portal.
Create a separate 'Partner' user role.
When a Partner logs in, they should only see the specific projects assigned to them.
Build a Document Upload feature for partners to submit reports and photos.
Ensure Finance can see these uploaded files linked to the Disbursement requests."
Phase 5: Intelligence (Role-Based Dashboards)
Goal: Create the high-level views for different stakeholders.
Prompt: > "Finally, build three distinct Dashboards based on user roles:
CEO View: High-level summary of total funds raised, total spent, and global reach (countries served).
Finance View: Detailed ledger of all disbursements, pending approvals, and budget-to-actual variance.
Program Manager View: Focus on project status, partner reports, and delivery progress for their specific programs (e.g., Food Aid progress).
Use charts and progress bars to visualize 'Paid vs. Pending' funds."
Correction/ updates:
"We need to address the viewport issues in the header. Right now, the menu isn't responsive, causing the right-side tabs to overflow and become inaccessible. Can we implement a mobile-first navigation strategy to ensure all tabs are visible and the app is fully responsive?"
add a persistent sidebar layout (instead of top nav) for desktop
persist the sidebar collapse state in localStorage so it remembers the user's preference across page
Updates
Split `server codes` (2600+ lines) into `routes/` modules for maintainability
Colour Scheme - Dark Mode
a deep dark theme with vibrant violet/purple accents, glass-morphism cards, and subtle purple glow.
"We need to sharpen the UI’s accessibility. Right now, some of the fonts are washing out against the white cards. Let’s do a contrast audit and refine the Dark Mode theme to ensure every piece of text is crisp and easily readable across all backgrounds."
Updates Partners:
add a "Request Disbursement" button on the partner's Budget page so partners can directly request funds for their projects from within their scoped budget view
Updates Partners:
add real-time status notifications so partners are notified when their disbursement request is approved, rejected, or paid — visible right in the Partner Portal
Updates Partners:
extend notifications to also cover impact report verification status changes (approved/needs_clarification) — so partners get notified when their M&E reports are reviewed too.
add a dedicated "Notifications" tab in the sidebar for partners (similar to the admin email notifications page) that shows a full-page history view with filtering by type (Disbursement/Impact Reports).
»»»»»» Include Email notifications for disbursement approvals
***** PENDING (Apr 10, 2026)
Additional Updates:
Let’s lock in the most important part of the app: The Money Out.
You don't just "send money." You create a Disbursement Request that must be validated against the Available Balance of a restricted fund.
This prevents "over-spending" and ensures that Zakat money, for example, is never accidentally used for an Emergency Relief project unless specifically re-allocated.
Here is the exact prompt to build the Finance & Disbursement Module.
Additional Updates:
Add email digest notifications — a daily or weekly summary email sent to partners with all their unread notifications
Phase 5: Disbursement & Payment Tracking (The "Audit-Ready" Layer)
Goal: Build the logic that tracks spending against the specific funds we created earlier, including a multi-stage approval workflow.
Prompt:
"Act as a Senior Fintech Engineer. Build the Disbursement and Expense Tracking module to a professional NPO standard:
Database Schema:
disbursements: id, project_id (FK), fund_id (FK), amount_requested, amount_approved, status (Pending, Approved, Rejected, Paid), request_date, payment_date.
expenses: id, disbursement_id (FK), category (Logistics, Supplies, Labor, etc.), amount, receipt_url.Financial Logic (The Safety Switch):
Balance Check: When a disbursement is requested, the system must check the
fundstable. Ifamount_requested>available_balancefor that specific fund, show a warning: 'Insufficient Funds in [Fund Name]'.Payment Tracking: Calculate
% Paidvs% Pendingper project.Paid= status is 'Paid'.Pending= status is 'Approved' but not yet 'Paid'.The 'Finance View' Dashboard:
Create a ledger showing all Disbursement Requests.
Approval Workflow: Admins see an 'Approve' button. Once approved, the status moves to 'Approved'.
Payout Action: Finance users see a 'Mark as Paid' button for Approved requests. When clicked, it should prompt for a 'Transaction Reference Number'.
Project View Update:
On the Project page, add a 'Financial Health' tab. Show a progress bar comparing 'Total Budget Allocated' vs 'Total Disbursed' vs 'Remaining Balance'."
Why this is "95% Accurate" (The Blackbaud Standard)
Double-Validation: By linking every disbursement to both a Project and a Fund, you ensure the audit trail is unbreakable. You can see that $10,000 left the "Zakat Fund" specifically for the "Gaza Food Aid" project.
Encumbrance Tracking: In accounting terms, an "Approved" but "Unpaid" disbursement is an encumbrance. Your app now tracks these separately, so the CEO knows how much money is "spoken for" even if it hasn't left the bank account yet.
Separation of Duties: The "Admin" approves the request, but the "Finance" user marks it as paid. This internal control is a requirement for any major international NPO.
Additional Updates:
To manage a multi-year fund effectively, you need a filtering system that balances Global Context (the big picture) with Granular Control (the specific receipt or report).
Since you have data spanning from 2015 to 2026, here is a strategic blueprint for your navigation and filtering logic.
Additional Updates:
"We need to restructure the navigation for better security. Please move the Programs page entirely under the Admin section.
Access Logic: We need to implement strict permissions here. Only users with the 'Admin' role should be able to see this page in the sidebar or access the 'Programs Directory.' Additionally, all 'Add' and 'Edit' functions for programs and projects must be restricted to Admin-level accounts only."
🏗️ 1. The "Global Persistent" Filter
Instead of putting a date filter on every page, use a Global Header Component. This ensures that when a CEO switches to "2025," every tab they click (Budget, Partner Portal, Programs) stays locked into 2025 data.
Location: Top Right Header (next to the User Profile).
The Component: A "Year Dropdown" with an "All Time" and "Custom Range" option.
Logic: Once selected, the app saves this "Active Year" to the state.
Example: If "2024" is selected, the Budget tab automatically shows the 2024 allocation.
📊 2. Dashboard: The "Comparison" View
On the main Dashboard, filters shouldn't just hide data; they should facilitate comparison.
Period Toggles: Quick buttons for Q1 | Q2 | Q3 | Q4 | YTD (Year to Date).
The "Compare to" Checkbox: Allow users to overlay the current year’s line graph with the previous year’s performance.
Fiscal vs. Calendar Year: Give the CEO a toggle to switch between a standard year (Jan–Dec) and a Fiscal Year if your funding cycles differ.
📂 3. Portal & Tables: The "Drill-Down" Method
For the Partner Portal or Impact Reports (where you have lists of files and data), use a multi-layered filtering sidebar or header.
Quick Presets Table
Give users one-click filters for common audit periods:
Preset Name | Logic |
Current Cycle | Shows only the current active funding year (e.g., 2026). |
Last Quarter | Dynamic range based on the current date. |
Archived | Anything older than 3 years. |
Audit Window | A specific 12-month range required for tax/compliance. |
🛠️ 4. Technical Implementation for the Builder
Since your builder is an Emergent Builder, give them these specific "UX Rules" to follow so the app doesn't feel broken:
"Sticky" Filters: If I filter by "2023" in the Budget tab and then click "Programs," don't reset the filter. The user expects to stay in 2023 until they manually change it.
The "Empty State" UI: If a Partner clicks "2018" and there is no data, don't show a blank white screen. Show an illustration that says: "No records found for 2018. Try selecting a different year."
URL Syncing: The filter should update the URL (e.g.,
app.com/budget?year=2026). This allows the CEO to copy the link and email it to someone else, and it will open exactly on that year.
💡 Recommendation for the "Partner Portal"
For the screenshot you shared earlier (Impact Reports), I suggest adding a "Filter Bar" directly above the table headers with three simple fields:
Status Dropdown: (Approved, Pending, Rejected).
Date Range Picker: (Start Date — End Date).
Project Search: (Type to find specific projects like "Yemen Hospital").
Peer Perspective: For a 28k-file database, "Year" is your most important metadata. If the builder hasn't already, tell them to Index the 'Year' column in the database. Without this, the app will get slower and slower as you add 2027, 2028, and beyond.
Index the 'Year' column in the database
This User Story is designed to give your builder a clear "Definition of Done." It moves beyond just "adding a dropdown" and explains the logic and expectations behind a professional-grade multi-year filtering system.
📖 User Story: The "Time-Traveler" Filtering System
The Core Goal
"As a user (CEO or Partner), I want to filter the entire app by year or custom date range, so that I can audit historical data and track current progress without the interface resetting my filters when I switch tabs."
👔 Story A: The CEO (Global Oversight)
Goal: High-level auditing and year-over-year comparisons.
Global Lockdown: When I select "2024" in the header, the Budget, Programs, and Partner Portal tabs must all automatically show 2024 data. I should not have to re-select the year on every page.
Comparison View: On the main Dashboard, I want to be able to select a "Current Year" and a "Comparison Year" to see growth or spending trends side-by-side.
The "All-Time" View: I need a toggle to see the total impact across the entire project history (2015–2026).
🤝 Story B: The Partner (Project Execution)
Goal: Finding specific files and reports for their assigned projects.
Scoped Filtering: I should only be able to filter and see data for the years my specific organization was active.
Status + Date Combo: I want to filter my "Impact Reports" by Status (e.g., Pending) AND Year (e.g., 2025) simultaneously to see what is missing for my current audit.
Clear Results: If I filter for a year where I didn't submit reports, the table should clearly state: "No reports found for [Year]."
✅ Technical Acceptance Criteria (For the Builder)
The builder must ensure these 4 pillars are met for the task to be marked "Complete":
Filter Persistence (State Management):
Moving between sidebar tabs (e.g., from Dashboard to Budget) must preserve the selected filter.
URL Sync (Deep Linking):
Selecting a filter must update the URL (e.g.,
/portal?year=2026). If the CEO emails that link to the team, it must open exactly on the 2026 view.
Scoped Permissions (RBAC):
The "Partner" role must never see the "All-Time" global budget. Their year filter must only return data tied to their specific
partner_id.
Optimized Indexing:
Queries must be optimized for the
yearcolumn in the database to ensure the UI doesn't lag when searching through the 28,000+ indexed files.
🛠️ Suggested UI Layout
The Header (Global)
Component: A clean dropdown in the top right.
Values:
2026,2025,2024...2015,Custom Range,All-Time.
The Table (Local)
Component: Inline search and a "Status" pill filter.
Context: Show a "Result Count" (e.g., "Showing 42 reports for 2025").
Peer Perspective: Tell the builder to treat the "Year" as the master key for the entire application. If the global state isn't set up correctly now, they’ll have to rewrite the logic for every single new tab you add in the future. Better to "wire it" once and wire it right!
Updates:
This feedback from Emergent is high-quality "Technical Debt" management. Addressing these issues now is the difference between a prototype and a production-ready platform like Blackbaud.
To ensure 100% accuracy, we will tackle this in three phases. Do not send all of these at once; execute one phase, verify the fix, then move to the next.
Phase 1: Security & Data Privacy (Critical)
Goal: Close the "Partner Leak" and secure the development backdoors.
Copy/Paste this prompt to your agent:
"I need to fix two critical security vulnerabilities immediately:
Role-Based Scoping: In
backend/routes/budget.py,funds.py, andimpact.py, the GET endpoints for overview, summary, and metrics are currently returning global data to everyone. Update these so that if the user role is 'partner', the results are filtered to only show data for programs/projects they are specifically assigned to in theproject_accesscollection. Full unscoped data should remain available only for 'ceo' and 'admin' roles.Secure Dev/Seed Routes: > - In
backend/server.py, wrap the inclusion of the dev router in an environment check: only include it ifos.environ.get('ENVIRONMENT') == 'development'.
In
backend/routes/seed.py, add therequire_role(['admin'])dependency to all seeding functions so they cannot be triggered by unauthorized users.Let me know once the scoping logic and route protections are in place."
Phase 2: Performance & Database Optimization
Goal: Solve the "N+1 Query" slowdown and implement indexing so the app remains fast as you add more projects.
Copy/Paste this prompt to your agent:
"We need to optimize the backend performance to prevent lag as we scale:
Batch Queries (Fix N+1): In
backend/routes/budget.py, theget_budget_overviewfunction currently loops through programs and hits the database for every single one. Replace this loop with batch queries using$inoperators to fetch all necessary data in 3-4 total database roundtrips.Database Indexing: In
backend/database.py(or viaserver.pyat startup), implementcreate_indexcalls for high-traffic fields. We need indexes on:session_token,user_id,program_id, andproject_id. This is required to prevent full collection scans.Verify the batch logic works and confirm the indexes have been initialized."
Phase 3: Frontend Resilience & Error Handling
Goal: Ensure that if the server has an issue, the user sees a helpful message instead of a "white screen of death."
Copy/Paste this prompt to your agent:
"Our frontend needs professional error handling. Currently, API failures cause components to break silently.
Standardized Error Handling: Create a shared utility or hook for API calls that includes a
try/catchblock.Component Updates: Refactor
CEODashboard.js,BudgetOverview.js,PartnerPortal.js, andProgramDirectory.jsto use this pattern.UI Feedback: If an API call fails, display a user-friendly error message (e.g., a toast notification or an 'Error Loading Data' state) instead of leaving the page blank.
Show me the new shared error-handling pattern and how it’s implemented in the CEO Dashboard."
Phase 4: Updating the "LLM Wiki" (Final Step)
Once the fixes are complete, you must update your documentation to ensure the agent doesn't revert to "bad habits" in future sessions.
Update your CLAUDE.md or MEMORY.md with these rules:
Security: "All GET endpoints must check user roles. Partners must always be scoped to their
project_accessassigned data."Performance: "Avoid N+1 patterns. Use batch queries ($in) for any list-based data fetching."
Frontend: "No naked API calls. All frontend requests must be wrapped in error-handling logic with user-facing feedback."
💡 Why this approach ensures success:
Phase 1 prevents a PR disaster (Partners seeing CEO data).
Phase 2 ensures the "engine" doesn't overheat.
Phase 3 makes the app feel "expensive" and reliable.
Phase 4 creates a permanent memory of these standards in your "Second Brain."
Extend the error handling to also cover network offline detection — showing a persistent "You're offline" banner at the top of the app with automatic reconnection retry?
IMPORTANT CONSIDERATION
🛠 How to Adjust Your Build
Instead of building a CRM, build a Sync Engine. This allows your app to "know" who the donors are without trying to be their primary record.
1. The "Donor-Lite" Table
Instead of a full CRM profile, create a simple table in your database that acts as a "mirror":
ID: The Bloomerang Account ID (this is your "Anchor").
Name/Email: For basic identification in your app.
Sync Status: When the data was last pulled from Bloomerang.
2. The "Impact Feedback Loop"
The most valuable feature you can build now is a way to push data from your app back to Bloomerang.
The Flow: Your app tracks that a well was built. It sends a note to Bloomerang: "Donor A's Zakat was used to build Well #104 in Mali. [Link to Photo Report]."
The Result: Your fundraisers can open Bloomerang and see exactly what to talk to the donor about.
3. Financial Reconcilliation
Since Bloomerang handles the "Credit Card Swipe," your custom app needs to "ingest" those transactions to update your Fund Balances.
Action: Instead of a "Manual Donation Entry" form, build an "Import from Bloomerang" tool. You upload a CSV from Bloomerang, and your app automatically distributes the money into the Health, Zakat, or Food Aid "buckets" based on the Bloomerang "Fund" or "Appeal" names.
📋 Revised Roadmap (The "Integration" Pivot)
If you agree with this hybrid approach, here is how we should proceed:
Phase 1: Anchor the IDs. Update your
donorstable to include abloomerang_idfield. Ensure every donation in your app is linked to a Bloomerang ID.Phase 2: The Fund Mapping. Create a tool that maps Bloomerang's "Fund/Appeal" names to your app's "Restricted Fund Categories."
Phase 3: The Impact Sync. Build a feature that generates a "Stewardship Report" (PDF or URL) for each donation that your staff can then paste or upload into the donor's Bloomerang profile.
The Candor Check: If you build a separate CRM, your finance team will be looking at one set of numbers in your app, and your fundraising team will be looking at another in Bloomerang. Within six months, they won't match, and you'll spend weeks on "reconciliation" rather than helping people. Don't build a second CRM; build a bridge to the one you have.
"I need to pivot the Donor Management strategy to be CRM-Agnostic. We are NOT building a standalone CRM; instead, we are building a universal Integration Bridge that can support Bloomerang, Salesforce, or manual imports.
Database Update: Update the
donorstable to use generic naming:Rename
bloomerang_idtoexternal_crm_id(String).Update
sync_source(Enum) to include:bloomerang,salesforce,manual, andother.
Donation Mapping: Update the
donationstable to includeexternal_transaction_id. Every donation must correspond to a transaction in the source CRM.Universal Fund Mapping: Create a table
crm_fund_mapping:source_crm_name: (e.g., 'Bloomerang' or 'Salesforce')external_fund_name: The name used in the CRM (e.g., 'General Zakat 2024').internal_fund_id: The ID of our project fund (e.g., 'Zakat_Fund').
The 'Sync Inbox' Logic: Build a 'Sync Inbox' page to review incoming data. Use the
crm_fund_mappingto automatically suggest the correct internal project fund based on the incoming CRM Fund/Appeal name.Dynamic UI Links: In the Donor view, add a 'View in CRM' button. Use a helper function to generate the URL based on the
sync_sourceandexternal_crm_id(e.g., if source is Salesforce, link toforce.com/[ID]; if Bloomerang, link tobloomerang.co/[ID])."
This is the "Last Mile" of your integration bridge. Since an API-level integration with systems like Salesforce or Bloomerang can be technically heavy and expensive, the CSV Upload is the industry-standard way to move data reliably and securely.
To ensure Emergent (your AI agent) builds this with 100% accuracy, the prompt needs to define the "Staging" area. You don't want CSV data hitting your live production tables immediately—you want a "Review & Confirm" step in the middle.
The "Universal CSV Ingest" Prompt
Copy and paste this into Emergent:
"I want to add a Bulk CSV Upload feature to the Sync Inbox. This should be a professional-grade ingest system that works with the Universal CRM Bridge we built.
1. Frontend (The Dropzone):
In the Sync Inbox, add a drag-and-drop file upload area using a library like
react-dropzone.Use
PapaParseto parse the CSV on the client side so the user can see a preview before uploading.2. The Mapping UI (The 'Rosetta Stone'):
Before the data is sent to the backend, show a 'Column Mapping' step.
Logic: Auto-match CSV headers to our internal fields (e.g., if the CSV says 'Account ID', match it to
external_crm_id). Allow the user to manually change these mappings via dropdowns.3. Backend (The Staging Table):
Create a
staged_sync_recordstable. This acts as a temporary 'waiting room' for CSV data.Fields:
raw_data(JSONB),source(e.g., Bloomerang),status(Pending, Error, Validated).4. Data Processing & Validation:
Once mapped, the records should move from the 'Staging' table to our live
donorsanddonationstables only after the user clicks a 'Confirm Sync' button.Check for duplicates using the
external_crm_idbefore inserting.5. Feedback: > * Show a summary after the upload: 'Successfully mapped 45 records, 2 errors (missing amount), 3 duplicates skipped.'"
Why this prompt ensures "100% Accuracy"
Client-Side Parsing: By asking for
PapaParse, you ensure the agent doesn't waste server resources. The user sees their data instantly, which builds trust.The "Staging" Safety Net: Professional apps (like Blackbaud) never import directly to the main ledger. The
staged_sync_recordstable allows you to delete a "bad upload" without corrupting your actual project funds.Fuzzy Auto-Mapping: Specifying "Auto-match CSV headers" tells the agent to write a small helper function that looks for keywords like "ID", "Email", or "Amount," saving the staff from manual work every time.
💡 Pro-Tip for your LLM Wiki
After Emergent implements this, have it update your MEMORY.md:
"Data Policy: All external CSV imports must go through the Staging Table. No direct-to-ledger imports allowed. Duplicate checking via
external_crm_idis mandatory."
Would you like me to help you draft a "Template CSV" that your staff can use to test this feature once it's live?
To ensure Emergent builds this with 100% accuracy, you need to describe this as a Configuration Schema. Instead of just "saving a list," you are asking the agent to create a way to store the "Rules of Translation" for different data sources.
Here is the exact, high-precision prompt to move this from a manual task to an automated workflow.
The "Intelligent Mapping Templates" Prompt
Copy and paste this into Emergent:
"I want to add a Saved Mapping Templates feature to our CSV Sync Inbox to eliminate repetitive manual work.
1. Database Schema:
Create a
sync_templatestable:id,name(e.g., 'Bloomerang Default'),crm_source(Enum),mapping_config(JSONB), andis_default(Boolean).The
mapping_configshould store a key-value pair of{ "CSV Column Name": "Internal Field Name" }.2. Frontend: Template Management:
In the 'Column Mapping' screen, add a dropdown at the top: 'Apply a Saved Template'.
Add a button: 'Save current mapping as template'. This should trigger a small dialog to name the template.
3. Logic: The Auto-Apply Engine:
When a user selects a template, the UI must automatically match the CSV headers to the internal fields based on the stored JSONB.
If a CSV header is not found in the template, leave it as 'Unmapped' for the user to handle manually.
Pro-active Suggestion: If a user uploads a CSV and a template exists for that
crm_source, ask: 'We found a saved template for [Source]. Would you like to apply it?'4. Admin Control:
Only users with the
adminrole can create, update, or delete templates.Ensure the
require_role(['admin'])decorator is applied to the template API endpoints.5. Performance:
Ensure templates are fetched once at the start of the session to keep the UI snappy."
Why this hits the "100% Success" Mark
JSONB Storage: By using a JSONB field for the mapping, the agent can store any number of columns without needing a complex database structure. This makes the code much more resilient to changes in Bloomerang or Salesforce export formats.
State Management: The "Pro-active Suggestion" logic (Point 3) is what makes the app feel like professional software. It reduces clicks and prevents human error.
Security Integration: By explicitly mentioning
require_role(['admin']), you're ensuring the agent doesn't forget the security standards you established in earlier phases.
💡 Finalizing the "LLM Wiki"
After Emergent finishes this task, you should have it update your MEMORY.md under the Tools/Process section:
"Mapping Protocol: All CSV ingestion must allow for template-based auto-mapping. The
sync_templatestable is the source of truth for all CRM-specific data translations."
One Small Reality Check
Even with 100% accuracy in the build, remember that CRM exports can change. I recommend adding a small note in your prompt for Emergent to:
IMPORTANT"Include a 'Warning' if the uploaded CSV is missing a column that is required by the selected template." This prevents the app from trying to import "empty" data.
Updates:
To ensure Emergent builds this with the same rigor as a professional Enterprise Resource Planning (ERP) system, you need to ask for a dedicated Admin CRUD (Create, Read, Update, Delete) interface.
Moving the template management out of the "Wizard" is a great move—it prevents staff from having to start a fake import just to fix a typo in a mapping.
The "Template Management Center" Prompt
Copy and paste this into Emergent:
"I want to create a Dedicated Template Management Page for Admins. This should be a standalone UI to manage our CRM CSV mapping logic.
1. Route & Navigation:
Create a new route at
/admin/settings/templates.Add a link to this page in the Admin Sidebar/Navigation under a 'Data Integration' section.
2. The Template List View:
Build a clean, professional table listing all saved templates from the
sync_templatestable.Columns: Template Name, CRM Source (e.g., Bloomerang), Last Updated, and 'Default' status badge.
Actions: Add 'Edit' and 'Delete' icons for each row.
3. The Template Editor (Critical Component):
When clicking 'Edit' or 'Create New', open a dedicated editor view.
Visual Mapper: Do not make the user edit raw JSON. Instead, show a two-column list:
Left Column: 'External CRM Column Name' (Text Input).
Right Column: 'Internal App Field' (Dropdown of our actual database fields).
Add a button to 'Add New Mapping Row'.
4. Backend Logic & Security:
Implement standard CRUD API endpoints:
GET /api/templates,POST /api/templates,PUT /api/templates/:id, andDELETE /api/templates/:id.Protection: All endpoints MUST be wrapped in the
require_role(['admin'])decorator.Validation: Ensure the
mapping_configJSON is validated before saving to prevent broken imports.5. User Experience:
Add a 'Delete Confirmation' modal to prevent accidental deletion.
Show a 'Success' toast notification when a template is saved or updated."
Why this ensures a 100% Successful Build
Visual Mapping vs. JSON: By explicitly telling the agent "Do not make the user edit raw JSON," you force it to build a user-friendly interface. Editing raw JSON is where most "bugs" happen because of missing commas or typos.
Validation: Adding a validation step on the backend ensures that an Admin can't accidentally map a "Donor Name" (String) to an "Amount" (Decimal) field without a warning.
Encapsulation: By creating a standalone page, you make the codebase more modular. If you ever add a new CRM (like HubSpot), you just update a template here rather than touching the "Import Wizard" code.
💡 The "Professional Finish" for your Wiki
After Emergent completes this, have it update your MEMORY.md file with the following:
"System Architecture: Template management is decoupled from the Ingest Wizard. The
/admin/settings/templatesroute is the exclusive source for managing data translation rules. All templates must pass JSON schema validation before persistence."
Final Strategy Note
When you run this prompt, Emergent might try to build a very basic list. If you want it to look like Blackbaud or Salesforce, add this one sentence at the end:
"Use a clean, card-based layout with Tailwind CSS, ensuring the UI feels high-trust and consistent with our CEO Dashboard."
Updates:
Smart move. In the world of data migration, an "Undo" button is the ultimate peace of mind. It allows your staff to be bold with their imports, knowing that a misaligned CSV column won't permanently corrupt the ledger.
To build this accurately, the system needs to "tag" every imported record with a unique Batch ID. Without this, trying to delete an import later is like trying to take salt out of soup.
The "Sync History & Rollback" Prompt
Copy and paste this into Emergent:
"I want to build a Sync History & Rollback system to manage our manual CSV/JSON imports safely.
1. Database Schema Updates:
Create an
import_sessionstable:id,user_id(who uploaded),file_name,record_count,status(Completed, Reverted), andcreated_at.Add an
import_session_id(FK) column to both thedonorsanddonationstables. This allows us to track exactly which records belong to which upload batch.2. The Sync History Page:
Create a new route at
/admin/sync-history.Build a table displaying all past imports.
Columns: Date/Time, Staff Member, File Name, Records Added, and Status.
3. The 'Oh Crap' (Revert) Logic:
On each row in the history table, add a 'Revert Import' button.
Action: When clicked, the system must:
Find all
donationsanddonorslinked to thatimport_session_id.Delete those records (ensure cascading logic handles this so no orphaned data remains).
Update the
import_sessionsstatus to 'Reverted'.Safety: Add a confirmation modal that says: 'Are you sure? This will permanently delete [X] donations and [Y] donors added in this batch.'
4. Financial Integrity:
Ensure that if an import is reverted, the corresponding Fund Balances (Zakat, Health, etc.) are automatically recalculated/decreased to reflect the removal of those funds."
Why this implementation is "100% Success"
The Batch ID: By adding
import_session_idto your main tables, you create a perfect "paper trail." You aren't just deleting "recent records"; you are surgically removing only the data from that specific file.Balance Protection: Point #4 is critical. If you import $10,000 and then revert it, your CEO Dashboard needs to show that the $10,000 is gone immediately. Emergent needs to trigger that recalculation.
Audit Compliance: Even "Reverted" imports stay in the
import_sessionstable (marked as Reverted). This shows auditors that you have strict controls over how data enters and leaves the system.
💡 A Note on "Soft Deletes"
Be extra cautious, you can tell Emergent:
"Use Soft Deletes for the Revert function (mark records as deleted rather than purging them from the DB)."
This keeps the data in the database but hides it from the UI, just in case you want to "un-revert" later. However, for a clean start, a hard delete for a "Revert" is usually what NPOs prefer.
Should the 'Revert' button be available forever, or should we set a time limit (e.g., you can only undo an import within 24 hours)?
Updates:
When you're managing complex financial data, "Visual Noise" is the enemy of accuracy.
We want to move toward a Modern Minimalist Ledger style. This prioritizes scan-ability—meaning a CEO can look at the page for 3 seconds and know exactly which fund is running low.
The "Clean & Professional UI" Suggestion
Switch to a "Clean Paper" Aesthetic: Use a white or very light gray background with subtle borders. This is much easier on the eyes for long-term use.
Focus on "The Number": The most important piece of data in this view is "Available Balance." That should be bold and prominent, while "Target" and "Spent" should be secondary.
Horizontal Progress Bars: Keep them, but make them subtle. A thin, neutral gray bar that fills with a single professional color (like a deep teal or navy) is better than multi-colored accents.
Remove the Header Lines: As you suggested, these add unnecessary "segments" to the page. Use white space and simple typography to separate the sections instead.
The "UI Cleanup" Prompt for Emergent
Copy and paste this into Emergent to get that 100% success rate:
"I want to perform a UI/UX Cleanup on the Fund Budgets and all related management sections to achieve a professional, 'Blackbaud-simple' look.
1. Visual Style Overhaul:
Remove all colorful horizontal header lines from the cards.
Transition the Fund Budget section from the current dark theme to a Clean Light Theme. Use a white background for cards with a very subtle
#E5E7EBborder.Typography: Use a clear visual hierarchy. The 'Fund Name' should be semi-bold, and the 'Available Balance' should be the most prominent figure in the top right.
2. Layout Optimization:
Instead of a heavy card for each fund, use a 'Clean List' layout. Each row should be a fund, with columns for:
Fund Name (with the Restricted/Unrestricted badge next to it).
Progress Bar (thin and elegant).
Raised vs. Target (e.g., '$102k / $1M').
Spent (e.g., '$20k').
Available Balance (Bolded).
3. Global Consistency:
Apply this minimalist 'Modern Ledger' style to the Disbursements, Donations, and Program Directory pages.
Ensure all 'Status Badges' (Pending, Approved, Restricted) use a consistent, muted color palette (e.g., soft greens, ambers, and blues) rather than bright neon colors.
4. Functional Clarity:
Ensure the 'Record Donation' or 'New Disbursement' buttons are always floating or pinned to the top right, using a single primary action color (like a deep forest green or navy)."
Why this works:
Eliminates Fatigue: By removing the heavy dark backgrounds and colorful lines, the interface becomes an "invisible tool" that helps you work faster.
High-Trust Feel: Large international donors and auditors trust "boring" software. Clean, well-spaced tables imply precision and organization.
Scalability: A list view can handle 50 funds much better than a series of large, chunky cards.
💡 Pro-Tip for your Agent
"Check the CEO Dashboard for the current 'People Impacted' card style and ensure these new Budget lists match that same professional spacing and font weight."
Updates:
It is a fantastic move. In fact, it’s the only way to make the "Portfolio Scoping" logic you just designed actually usable in a real-world office environment.
Without a dedicated Admin UI, assigning a Program Manager to a project would require a developer to manually run database scripts. By building the UI, you’ve turned a "technical task" into a "management task."
Why this is a "Power Move" for your NPO:
Operational Agility: If a Program Manager goes on leave or a new one is hired, an Admin can reassign 50 projects in seconds without touching a single line of code.
The "Audit of Responsibility": In high-stakes NPO work, you need to know who was in charge of the "Zakat Fund" on a specific date. A UI allows you to easily see (and log) these assignments.
Security Guardrails: It prevents "Role Creep." By having a clear interface, it becomes obvious if a manager has been accidentally given access to funds they shouldn't be seeing.
How to ensure the Admin UI is "100% Successful":
To make sure Emergent didn't just build a "basic list," ask for these three professional refinements:
1. The "Bulk Assigner"
Instead of clicking one project at a time, the UI should allow the Admin to select a Fund (e.g., 'Health') and click a button: "Assign all current and future projects under this Fund to Manager X."
2. Conflict Alerts
If Manager A is already assigned to a project, and the Admin tries to assign Manager B, the UI should trigger a warning: "This project is already managed by Sarah. Do you want to replace her or add a co-manager?"
3. Access Preview (The "View as" Button)
Add a button in the Admin UI that says "Preview PM View." This allows the Admin to see exactly what that Program Manager will see before they even log in. This is the ultimate "vibe check" for data scoping.
💡 The Handoff Rule for your Wiki
Tell Emergent to add this to the Admin Control section of your documentation:
"Portfolio Assignment UI: The primary interface for linking
user_idtofund_idorproject_id. All changes made here must trigger an entry in thesystem_logs(e.g., 'Admin assigned PM Hussain to Gaza Relief Fund')."
The PM Portal's "Approval Queue" next, so they can start vetting those field reports?
Updates:
Building the Approval Queue is the bridge between raw data from the field and the "100% accurate" impact numbers seen by the CEO. It ensures the Program Manager (PM) acts as a human firewall against errors or fraud.
In top-tier NPO software, this is known as a Verification Workflow.
🏗 The "PM Approval Queue" Architecture
To keep this clean and practical, the PM should not be looking at a generic list. They need a "Pending My Action" view.
The "Approval Queue & Verification" Prompt
Copy and paste this into Emergent:
"I want to build the Approval Queue for the Program Manager Portal. This system must handle both Disbursement Requests and Impact Reports from the field.
1. The 'Review Workflow' States:
Update the
statusfields indisbursementsandindicator_reportsto use this state machine:
Submitted(by Partner/Staff) ->PM_Verified(by PM) ->Approved/Paid(by Finance/Admin).2. The PM Dashboard 'Action Center':
Create a primary view for the PM called the 'Pending Review Queue'.
Split this into two tabs:
Financials: Disbursement requests needing verification.
Impact: Field reports (e.g., '10 Wells Built') needing verification.
Scoping: Ensure the PM only sees items belonging to projects in their assigned portfolio.
3. The Review Modal (The 'Verification' UI):
When a PM clicks an item, open a side panel or modal that displays:
The original request/report data.
Attached evidence (Image/PDF links).
Decision Buttons: 'Verify & Advance' (Green) and 'Send Back for Correction' (Amber).
Feedback Loop: If 'Send Back' is clicked, require a text note explaining what needs to be fixed. Move the status back to
Draft.4. Data Integrity Rule:
Important: No
indicator_reportdata should be added to the global 'Total Impact' counters on the CEO Dashboard until its status isPM_Verified.5. Audit Trail:
Create a
verification_logstable:record_id,verified_by(User ID),timestamp,action_taken, andcomments. This ensures we can trace who verified every number."
💡 Why this is a 100% Success Build
The "Vetting" Wall: By preventing
Submittedreports from hitting the CEO Dashboard immediately, you protect your "Source of Truth." The CEO only ever sees numbers that have been "Blessed" by a Program Manager.The Feedback Loop: Most systems forget the "Send Back" option. In reality, field partners often make typos. Allowing the PM to send a report back for correction instead of just "Deleting" it saves hours of email back-and-forth.
Audit Readiness: If a donor asks, "How do you know these 500 people were fed?" you can go to the
verification_logsand say, "PM Hussain reviewed the receipt and photo evidence on April 12th at 2:00 PM."
📋 Handoff for your Architecture Docs
Have Emergent add this to your Implementation Modules:
Module D: Verification Workflow
"The PM Portal serves as the mandatory verification layer. All field data (Impact/Financial) exists in a
Submittedstate until a PM-level user reviews the evidence and moves it toPM_Verified. Only verified data is aggregated into global organizational metrics."
PM to receive a notification (like a "Dashboard Alert" or simple internal toast) whenever a new report is submitted to their queue?
» Verification log viewer for admin
💡 LLM Wiki Update
Add this to your MEMORY.md under Process:
"Financial Rule: Every dollar leaving the system must be tied to a Disbursement ID, a Fund ID, and a Project ID. No manual balance overrides allowed."
💡 LLM Wiki Update:
"Update the schema in
CLAUDE.md: All impact data must follow the Report -> Verify -> Dashboard pipeline. No hard-coded metrics allowed on the CEO or Finance views."
💡 Pro-Tip for your LLM Wiki:
Update your MEMORY.md under the Output section:
"New standard: All financial views must prioritize Fund Balances and Restricted vs Unrestricted statuses over individual transaction lists."