PayPilot is a full-stack AI operations platform for small merchants and D2C brands. It runs a fleet of AI agents that continuously analyse a store's transaction data, surface ranked growth opportunities, and act on them — plan, create, approve and launch campaigns, draft retention plays, and project what-if outcomes. Built with a FastAPI + SQLAlchemy backend and a React + TypeScript + Tailwind + Recharts frontend.
Everything ships seeded with realistic merchant data (one store, ~870 customers, ~15k orders) so the entire product is explorable immediately after install.
- AI Command Center — chat with an agent fleet that answers over your own business data.
- Agent-driven dashboard — ranked "plan of action" cards generated from daily briefs, each with a reason and a working action button.
- Campaign lifecycle — AI drafts, merchant approval, controlled launch, and measured revenue lift
(
draft → approved → live → completed). Nothing goes live without your approval. - Customers & segments — momentum scoring, lifecycle segments, and retention play details.
- Analytics — revenue trends, order value, acquisition channel mix, campaign performance, and a 7×24 selling-intensity heatmap.
- Forecast & simulator — honest projections from the store's own patterns plus a "Growth Simulator" for what-if planning.
- Activity feed — a transparent log of every agent action.
- Settings — business profile, account security (change password), AI engine status, and notification preferences.
backend/ FastAPI + SQLAlchemy (SQLite for dev, PostgreSQL in production)
app/
agents/ growth · customer · marketing · finance · operations · strategy
services/ analytics · forecasting · ai engine · campaigns · simulator · security
routers/ auth, dashboard, analytics, customers, campaigns, insights,
forecast, daily-brief, activity, simulator, actions, ai
seed/ deterministic starter data (fixed RNG, seeds once)
frontend/ Vite + React 19 + TypeScript + Tailwind + Recharts
src/
lib/ API client, shared types, auth, toast, formatting
components/ hand-rolled UI kit + layout (sidebar / topbar / AI-ask modal)
pages/ dashboard, AI center, customers, campaigns, analytics,
forecast, activity, settings, simulator, login, onboarding
Six agents continuously score the merchant's data and emit insights with scores, severities, and executable actions. The Strategy agent ranks them into a daily plan of action (the dashboard priority cards). Executing an action writes a real entry to the activity feed and can draft a campaign or a customer retention play — the loop is insight → action → visible change.
backend/app/services/ai/ ships a built-in deterministic engine (local) so the whole platform works
offline with zero API keys. Set AI_PROVIDER=gemini and add GEMINI_API_KEY to route agent answers
through the Gemini API; any Gemini failure falls back to the built-in engine automatically.
Requirements: Python 3.11+, Node 20+.
cd backend
python -m venv .venv
.venv\Scripts\activate # Windows (macOS/Linux: source .venv/bin/activate)
pip install -r requirements.txt
copy .env.example .env # optional — defaults work as-is
python -m uvicorn app.main:app --host 127.0.0.1 --port 8000The database is seeded automatically on first startup only when it is empty
(paypilot.db). Databases that already contain a merchant are never reseeded or
reset on restart.
Force a fresh seed with: python -m app.seed --reset.
cd frontend
npm install
copy .env.example .env # optional for dev — see below
npm run dev # http://localhost:5173The Vite dev server proxies /api/* to http://127.0.0.1:8000 automatically,
so local development needs no environment file. If you prefer an explicit URL,
set VITE_API_BASE_URL (or the legacy VITE_API_URL) in frontend/.env.
Production build (incl. typecheck — tsc -b): npm run build.
The bundled starter store is pre-seeded and logs in directly:
- Email:
merchant@paypilot.demo - Password:
paypilot123
These are the credentials of the seeded development account (created once per
fresh database). Passwords are stored as PBKDF2-SHA256 hashes and verified on
every login — the email/password above are not used to authenticate requests;
authentication uses the bearer token returned by POST /api/auth/login. On the
login page, "Use developer account" pre-fills these credentials for
convenience. In production you can change them via the
DEMO_MERCHANT_EMAIL / DEMO_MERCHANT_PASSWORD environment variables before
the first seed.
| Variable | Default | Purpose |
|---|---|---|
AI_PROVIDER |
local |
local = built-in engine; gemini = live Gemini API |
GEMINI_API_KEY |
(empty) | Your Gemini key; only used when AI_PROVIDER=gemini. Never commit. |
GEMINI_MODEL |
gemini-2.0-flash |
Gemini model name |
DATABASE_URL |
sqlite:///./paypilot.db |
SQLAlchemy URL. Production: platform Postgres URL |
CORS_ORIGINS |
http://localhost:5173,http://127.0.0.1:5173 |
Additional dev origins (comma-separated) |
FRONTEND_URL |
(empty) | Deployed frontend origin, e.g. https://paypilot-web.onrender.com. Added to CORS. Required in production. |
DEMO_MERCHANT_EMAIL |
merchant@paypilot.demo |
Email of the seeded merchant account |
DEMO_MERCHANT_PASSWORD |
paypilot123 |
Password hashed into the seeded merchant account |
| Variable | Default | Purpose |
|---|---|---|
VITE_API_BASE_URL |
(empty —— dev proxy used) | Absolute URL of the backend API. Required in production. |
VITE_API_URL |
(deprecated fallback) | Older name for the API base URL; VITE_API_BASE_URL wins if both are set |
Never commit real secrets (.env files, API keys, database credentials) — all
three .gitignore files already exclude .env.
The repository includes render.yaml, a Render blueprint that provisions three
resources: a PostgreSQL database, a Python web service (FastAPI), and a
static site (React SPA).
- Push this repository to GitHub.
- In the Render dashboard: New + → Blueprint → connect the repository.
- Render creates
paypilot-db,paypilot-apiandpaypilot-webautomatically.
The blueprint already wires:
DATABASE_URL→ the provisioned Postgres (no manual host/credentials).FRONTEND_URL→https://paypilot-web.onrender.com(CORS).VITE_API_BASE_URL→https://paypilot-api.onrender.com(baked into the production frontend bundle at build time).- Backend starts with
uvicorn app.main:app --host 0.0.0.0 --port $PORT. - Health check:
GET /api/health(also aliased at/health).
| Service | Variable | Notes |
|---|---|---|
paypilot-api |
AI_PROVIDER=gemini |
Optional — live Gemini answers inside deployed AI. |
paypilot-api |
GEMINI_API_KEY |
Your key (never commit it). Without it the app uses local automatically. |
paypilot-api |
DEMO_MERCHANT_PASSWORD |
Change the seeded account password from the published default if desired. |
Both seed runs and normal restarts are safe: seeding only happens once on an empty database, so production data is never wiped on redeploy.
Frontend (Static Site):
- Root directory:
frontend - Build command:
npm install && npm run build - Publish directory:
dist - Environment:
VITE_API_BASE_URL=https://paypilot-api.onrender.com
Backend (Web Service, Python):
- Build command:
pip install -r requirements.txt - Start command:
python -m uvicorn app.main:app --host 0.0.0.0 --port $PORT(or equivalentlypython -m app.main) - Health check path:
/api/health - Environment:
DATABASE_URL=<your render postgres url>,FRONTEND_URL=https://paypilot-web.onrender.com, optionalAI_PROVIDER=gemini+GEMINI_API_KEY, optionalDEMO_MERCHANT_PASSWORD
Database (PostgreSQL): create via the Render dashboard and point
DATABASE_URL at its Internal Database URL. The app normalises
postgres://… to postgresql://… automatically.
All /api/* routes except auth require Authorization: Bearer <access_key>. The access key is the
token returned by POST /api/auth/login (per-seed, never a hardcoded value).
| Endpoint | Purpose |
|---|---|
POST /api/auth/login · /api/auth/onboarding |
session + merchant setup |
GET/PUT /api/auth/merchant · POST /api/auth/change-password |
profile + account security |
GET /api/dashboard |
metrics, revenue series, ranked priority cards, health |
GET /api/analytics?days= · /api/analytics/heatmap?days= |
trends, segments, campaign perf, 7×24 heatmap |
GET /api/customers · GET/POST /api/customers/{id} |
list w/ momentum + segments, create, deep detail |
GET /api/campaigns · POST · /{id}/approve · /{id}/launch · /ai-draft |
full campaign lifecycle + AI draft |
GET /api/forecast?period_days= |
historical + projected series, factors, confidence |
GET /api/daily-brief |
morning brief for the topbar / dashboard |
GET /api/activity |
agent action feed (polled by the UI every 30s) |
POST /api/actions/execute |
run any insight's suggested action |
POST /api/ai/chat · /api/ai/analyze |
agent chat / report |
POST /api/simulator |
what-if model & 30-day revenue projection |
GET /api/health (also /health) |
public health check (no auth) — used by Render |
- Passwords are hashed with PBKDF2-SHA256 (100,000 iterations, per-user salt); plaintext is never stored or returned.
- Login normalises email and is case-insensitive; invalid credentials return a generic 401.
- Campaign launches are gated: only approved campaigns can be launched.
- The bundled development account uses a freshly generated access key per seed, not a published constant.
- CORS uses explicit origins (local dev origins plus
FRONTEND_URL); a*wildcard is never allowed with credentialed requests. - Database credentials, API keys, and secrets come from environment variables only;
.envfiles are git-ignored and never committed.
- Deterministic. Seeded with a fixed RNG; metrics and forecasts are pure functions of the data, so behaviour is stable and reproducible between runs.
- Frontend mirrors the API.
frontend/src/lib/types.tsstays in lockstep with the OpenAPI schemas; untyped endpoints (insights / daily-brief) are typed on the client. - The forecast is honest. It projects from your own weekly trend + recent-dip dampening + weekday patterns; the simulator reuses the same model on adjusted inputs.