DataPulse
A business analytics dashboard that turns any sales CSV into KPIs, charts and forecasts — pointed at a new dataset by editing a column mapping rather than the code.
- Pipeline
- Ingest · transform · forecast
- Service modules
- Five, one job each
- Forecasting
- Prophet
- Automated tests
- Two
- Context
- Public project · two contributors
- Contributors
- Rafay Khattak & Muhammad Umar Nadeem
- Period
- May 2026
- Shape
- One Streamlit application over a managed Postgres database
- Configured by
- Column mapping — a new dataset needs no code change
- Status
- Public prototype · hosted deployment unresolved
- Visibility
- Public repository · every claim here is checkable in source
Covers
Stack
- Python
- Pandas
- Streamlit
- Plotly
- Prophet
- SQLAlchemy
- Supabase
- Gemini
The product shape
DataPulse is written to be used rather than read. Its own documentation opens by saying so — a business owner or an examiner should be able to work the thing without opening a Python file — and that framing decides most of what follows.
The path through it is a pipeline. CSVs land in a raw folder; ingestion normalizes their headers and loads them; transformation folds several raw tables into one business-ready analytics table; the dashboard reads from that table, and forecasting hangs off the same one.
The code is layered to match. Pages render, services hold the business logic — authentication, data access, KPI calculation, forecasting — pipeline components do the loading and reshaping, configuration holds the dataset mapping, and a shared UI module owns styling and chart helpers. Each file has one job, which is what keeps a project this size legible.
Administrator
Runs the pipeline
Viewer
Reads the dashboard
Ingestion
CSV, headers normalized
Transformation
One analytics table
KPI service
Business measures
Visualization
Plotly
Forecasting
Prophet
Column mapping
Python or YAML
Assistant
Question to SQL
Supabase Postgres
Via SQLAlchemy
Two roles, six pages
There are two kinds of person in the system. An administrator manages users, sets business targets, runs the pipeline and triggers forecasts; a viewer sees the dashboard and the reports and cannot reach any of that.
That split is why the settings and pipeline pages exist separately at all. Deleting data, resetting the system and changing who has access are precisely the actions you do not want one click away from a read-only dashboard.
Pages
- Login
- Analytics hub
- Business insights
- Data pipeline
- Settings
- Assistant
Administrator only
- User management
- Business targets
- Pipeline runs
- Forecast runs
- System logs
- Data reset
Viewer
- Dashboard
- Charts and KPI cards
- Date range filter
- CSV export
Insights
- Revenue
- Order count
- Average order value
- Trend over time
- Forecast chart
- Progress against target
Pipeline
- CSV ingestion
- Header normalization
- Transformation to one table
- Standalone forecast run
Services
- Authentication
- Data access
- KPI calculation
- Forecasting
- Assistant
Six pages over five service modules. The repository is public, so this list is checkable rather than asserted.
Business-agnostic, for real
The product claim is that DataPulse works for any business, and the column mapping is what makes that true rather than aspirational. A dataset needs a date column, a value column and a unique record ID; a customer column is optional.
Pointing the application at a different business means editing that mapping — in a Python config or a YAML file, both of which are committed — so the names in the system line up with the names in the CSV. No application logic changes. It is a small idea, and it is the entire difference between a dashboard for one dataset and a dashboard for any.
Everything downstream reads the mapped names and neither knows nor cares what the source file called them. The KPIs fall out of that table: revenue, order count, average order value, and the trend across whatever date range the reader selects.
One analytics table, built from the mapped CSVs
The selected date range
- Revenue
- Order count
- Average order value
- Progress against target
KPI cards, trend charts and a downloadable CSV
Mapping, not migration
Changing which business the dashboard serves is a configuration edit, not a schema change. The mapping names which CSV column plays each role, and everything downstream — the KPI service, the charts, the forecast — reads those roles rather than the source file's own column names.
revenue ÷ orders → average order valueForecasting, and what it is not
The forecasting path fits Prophet to the historical series in the analytics table and renders the result beside the actuals, which is genuinely useful for the planning conversations the product is aimed at.
What the project does not do is evaluate it. There is no held-out period, no baseline to compare against, and no error metric reported anywhere. A forecast chart that looks plausible is not a measured forecast, and that distinction is the whole reason this page calls the work analytics with forecasting rather than machine learning.
That is a gap in the evidence rather than a criticism of the choice. Prophet is a reasonable tool for a small business series. It simply has not been shown to be right here — and showing it would be cheap: one held-out window and one baseline would settle the question.
What the forecast is
- Prophet fitted to the historical series
- Refitted as more data is loaded
- Rendered beside the actuals
- Useful for a planning conversation
What it is not
- Evaluated against a held-out period
- Compared to any baseline
- Reported with an error metric
- A machine-learning result
- Analytics
- with forecasting
- not
- AI research
The assistant that writes SQL
There is a feature in the repository its documentation never mentions: a conversational assistant that answers questions about the data by writing SQL against it.
The flow is careful. It reads live column metadata for the analytics tables and builds a compact schema description, decides whether the question is a data question at all, asks the model for a single SELECT constrained to those tables, runs it, and then asks the model again to turn the returned rows into a sentence.
The part worth pointing at is that it does not trust the model. The prompt asks for a SELECT with no semicolons — and then the code independently checks that the statement begins with SELECT, contains none of a list of write and schema-modifying keywords, and carries no semicolon, and appends a row limit if the model did not set one. A prompt instruction is a request; the guard is what actually holds.
It is a keyword denylist and a row cap rather than a sandbox, and nothing in the repository measures how often the generated SQL answers the question asked. Both of those sit in the limits below rather than being glossed over here.
- Schema from live metadata
- Question routing
- Constrained generation
- Independent SQL validation
- Enforced row limit
- Model fallback
What is actually tested
There are two automated tests. One checks a KPI calculation against known data; the other checks that the application can load data from the database.
Two is a small number, and this page says so rather than describing them as a suite. What they do cover is the seam most likely to fail silently — a KPI that quietly computes the wrong thing looks exactly like a KPI that works — so as a first test to have written, it is the right one.
- 01A KPI calculation checked against known data
- 02A database integration check on the application's data path
- 03Configurable column mapping, committed in both Python and YAML
- 04Ingestion, transformation and prediction as separate components
- 05Five service modules with one responsibility each
- 06An example environment file committed; the real one is not
Known-data KPI test
- Source
- Transform
- Expected KPI
- Test
- Pass
The chain names what the KPI test walks, not what it returns; its inputs and values are not reproduced here. Two tests is the entire suite — no coverage figure is claimed, and none has been measured.
How it was served
The application ran on Streamlit Community Cloud against a Supabase-hosted Postgres database, reached through SQLAlchemy with the connection string supplied as an environment value. An example environment file is committed; the real one is not.
Whether that deployment is still live is unresolved, so it is not presented here as a running demo. What is reproducible is the local path: the repository carries a development container definition and a pinned requirements file, so the environment is described rather than assumed.
Browser
Streamlit Community Cloud
Application hosting
Streamlit application
Pages and services
SQLAlchemy
Connection from environment
Supabase
Managed Postgres
What holds, and what does not
The repository is public, so the left column below can be checked rather than taken on trust — the structure, the mapping, the forecasting path and the SQL guards are all there to read.
The right column is where this would have to grow to be a data-science case study rather than an application one. None of it is difficult. None of it is done.
Verified
- The layered structure — pages, services, components, configuration
- Column mapping that onboards a dataset without a code change
- A Prophet forecasting path, end to end
- Independent validation and a row cap on the assistant's SQL
Not verified
- Forecast quality — no baseline, no held-out period, no error metric
- Assistant accuracy — nothing measures whether its SQL answers the question
- Role enforcement — the separation exists but no test asserts it
- Whether the hosted deployment is still live
Next proof
- A held-out window
- A stated baseline
- An assistant answer set
- Role tests
What would strengthen it
Not a roadmap — the specific things that would turn this from an application into evidence. Each one converts a claim on this page from an assertion into a number.
- 01
Public-safe dataset
A reproducible dataset published beside the work, so a reader can run it.
- 02
Runtime validation
Checks that run with the pipeline rather than beside it.
- 03
Baseline comparison
A stated baseline for any forecast to be measured against.
- 04
Error metrics
Explicit forecast error, reported rather than implied.
- 05
Assistant evaluation
A fixed set of questions with known answers, so accuracy is a number rather than an impression.
- 06
Role tests
Tests that assert a viewer cannot reach an administrator's actions.
Current status
The repository and everything in it are public and available: the layered source, both mapping formats, the forecasting path, the assistant and the two tests.
What is not available is any evaluation, and the hosted deployment's state is unresolved. The rows below keep those apart rather than folding them into a summary that would read as finished.
- Public repository
- Available
- Layered source
- Available
- Column mapping
- Python and YAML, both committed
- Forecasting path
- Implemented
- SQL assistant
- Implemented · undocumented upstream
- Automated tests
- Two committed
- Forecast evaluation
- None
- Hosted deployment
- Unresolved
Roles and guards
- Two roles — administrator and viewer — with different pages reachable
- User management, targets, pipeline runs and data reset are administrator-only
- Passwords are hashed by the authentication service rather than stored as given
- The assistant's generated SQL is validated independently of the prompt
- Generated queries carry a row limit whether or not the model set one
- Database credentials come from the environment; an example file is committed, the real one is not
Concept level, and checkable — the repository is public. The separation is not covered by any test, which the limits section states rather than hides.
Evidence boundary
Supported
The repository is public. It shows a layered application — pages, services, pipeline components, configuration and shared UI, each with one job — a configurable column mapping that onboards a new dataset without touching application logic, a Prophet forecasting path, two separated roles, and a Gemini-backed assistant that turns questions into guarded SELECT statements against the analytics schema.
Not overstated
Forecast quality is not evaluated anywhere: no baseline, no held-out period, no error metric. The assistant's SQL is guarded but not measured — nothing checks how often its answers are right. Two automated tests exist, which is two. Role enforcement, data provenance and whether the deployment remains live are unverified, and the contribution split between Rafay Khattak and Muhammad Umar Nadeem is not documented, so none is claimed.
Technical notes
The application is a single Streamlit process reading and writing a Supabase-hosted Postgres database through SQLAlchemy. Ingestion loads CSVs and normalizes their headers, transformation folds them into one analytics table, and Prophet produces the forecast from it. It was deployed through Streamlit Community Cloud; whether that deployment is still live is unresolved, so it is not presented here as a running demo.
Core stack
- Python
- Pandas
- Streamlit
- Plotly
- Prophet
Data
- SQLAlchemy
- Supabase Postgres
- CSV ingestion
- Column mapping in Python or YAML
Assistant
- Google Gemini
- Schema-aware prompting
- SELECT-only validation
- Enforced row limit
Deployment & environment
- Streamlit Community Cloud
- Pinned requirements
- Development container
Testing
- pytest
- Two committed tests
- Repository
- Public
- Public artifacts
- Dashboard, KPI, chart, export, forecast and assistant screenshots can be added here once captured from a running instance.
Source
View Public RepositoryContributors
- Rafay Khattak
- Muhammad Umar Nadeem