AI-powered escrow for Nigerian peer-to-peer commerce.
Money sits in a holding account until both sides honour the deal. Risk stack: deterministic rules + Isolation Forest feed an umbrella score; in the current dashboard build the composite run is post-fund (non-blocking) and updates trust β see FRAUD_DETECTION_FLOW.md. Escrow releases and payouts still go through Squad-backed flows.
Problem Β· Solution Β· Squad APIs Β· AI / Data Β· User Flow Β· Quick Start Β· Impact Β· Docs
Who is suffering? Millions of Nigerians buying and selling on WhatsApp, Twitter/X, Instagram, Jiji, and Facebook Marketplace. These platforms have no built-in payment protection.
Why it matters right now:
- Nigeria's informal e-commerce is estimated at over $10 billion annually, and the majority of peer-to-peer transactions happen outside regulated marketplaces.
- 1 in 3 online buyers in Nigeria has experienced a failed delivery or outright scam (NOIPolls / EFInA surveys).
- Sellers face the reverse problem β chargebacks and fake "item not received" claims with no neutral arbiter.
- Existing escrow solutions are either bank-grade (minimum β¦5M, corporate-only) or informal (a friend holds the cash). There is no consumer-grade, AI-protected escrow for everyday transactions.
The trust gap costs the ecosystem real money. Buyers overpay for "safe" channels (COD markups, marketplace fees), sellers lose honest customers who refuse to pay first, and repeat commerce never forms.
Tunde, 27, Lagos. Sells refurbished phones on Twitter/X. His buyers want delivery before payment; he wants payment before shipping. Neither side trusts the other. He loses ~3 deals per week to trust breakdown. ScrowPay lets both sides lock funds in escrow, verify each other's identity and reputation, and complete the deal with zero risk.
Amaka, 24, Abuja. Buys fashion items from Instagram vendors. She has been scammed twice β paid via bank transfer, got blocked. She now only buys from sellers who accept ScrowPay because she can see their Trust Score and knows her money is locked until she confirms delivery.
These are the thousands of everyday Nigerian buyers and sellers who trade informally online and need a simple, trustworthy middle-ground.
ScrowPay is a peer-to-peer escrow platform where money is held in a Squad virtual account until both sides honour the deal. Around that core payment flow, we layer AI to prevent fraud before it happens and resolve disputes automatically when it does.
How it works in one sentence: Seller lists, buyer funds (money goes to a holding account via Squad), goods are delivered, buyer confirms, money releases to seller β and AI watches every step.
| Layer | What it does |
|---|---|
| Escrow engine | State machine over Created β Funded_Locked β In_Transit β (Completed | Disputed) plus Cancelled / Refunded terminal paths in the DB schema and TransactionService |
| Squad payment rails | Virtual accounts for every user + a central holding account + NIP transfers for payouts |
| AI risk scoring | AnomalyDetectionEngine: RiskEngineService (rules) + IsolationForestService (Flask Isolation Forest). Wired today: evaluate() runs after a successful fund and feeds TrustEngineService.onAnomalyEvaluated β non-blocking. Product goal: optional pre-fund gate. |
| AI dispute agent | Gemini 2.0 Flash multimodal agent that reads complaints + photo evidence and issues binding verdicts |
| Face re-verification | Gemini-powered face match for high-risk actions (large withdrawals) against signup reference photo |
| Trust engine | Dynamic 0-100 reputation score with tiers, history, and Instant Release eligibility |
| Admin console | Moderation dashboard for manual dispute review, face audit, and risky transaction monitoring |
Squad is the complete financial backbone of ScrowPay. We use three product lines across eight API endpoints:
| Method | Endpoint | What it does in ScrowPay |
|---|---|---|
POST |
/virtual-account |
Creates a real NUBAN for every user. Squad validates BVN against NIBSS (name, DOB, gender, phone) β giving us bank-grade KYC at zero extra cost. |
GET |
/virtual-account/customer/{id} |
Retrieves account details and balance for the dashboard. |
GET |
/virtual-account/{identifier} |
Looks up a user by their unique identifier. |
Why it's central: Every user gets a real Nigerian bank account. Buyers fund escrow by transferring Naira to the holding virtual account. No virtual accounts = no money movement = no product.
| Method | Endpoint | What it does in ScrowPay |
|---|---|---|
POST |
/payout/account/lookup |
Verifies destination bank + account name before any transfer β prevents misdirected payments. |
POST |
/payout/transfer |
Releases escrow funds to the seller (or refunds the buyer) via NIP instant transfer. |
POST |
/payout/requery |
Re-queries transfer status for confirmation β ensures idempotency. |
GET |
/merchant/balance |
Fetches the Squad Merchant Ledger balance in real-time (30s polling). |
GET |
/payout/list |
Lists all historical transfers for audit. |
Why it's central: Every escrow release, every refund, every withdrawal flows through these endpoints. Supports 21+ Nigerian banks.
The dashboard polls Squad every 30 seconds for the live available balance, combining it with locked-in-escrow amounts from the database to show users their complete financial picture.
Implementation files:
frontend/squad-api-service.jsβ Virtual Account API clientfrontend/SquadTransferService.jsβ Transfer/Payout API clientfrontend/BalanceService.jsβ Balance orchestrator with 30s TTL cache
Full technical deep-dive: docs/SQUAD_API_INTEGRATION.md
ScrowPay addresses two AI pillars: Fraud Prevention and Automated Dispute Resolution.
RiskEngineServiceβ deterministic, in-browser rules (counterparty, amount, time-of-day, etc.). No Gemini in this path today (legacy listing check was removed).IsolationForestServiceβ browser client β Pythonai-engineIsolation Forest/api/v1/score.
Current product wiring (dashboard.html): after a buyer successfully funds, anomalyEngine.evaluate() runs in the background and trustEngine.onAnomalyEvaluated ingests the composite score. Funding itself is not blocked by this call in the present implementation (see FRAUD_DETECTION_FLOW.md). Verdicts and features are still logged for audit when the pipeline runs.
Design thresholds (umbrella): see AnomalyDetectionEngine.js (BLOCK_THRESHOLD / REVIEW_THRESHOLD) β distinct from any copy that still mentions β>80 blockβ from older marketing drafts.
When a buyer raises a dispute:
- The Gemini 2.0 Flash agent receives: transaction context, free-text complaint, up to 4 uploaded photos
- It returns a structured JSON verdict:
favoredParty,confidence,payout,reasoning,evidenceCited - High-confidence verdicts (>90%) auto-execute. Lower confidence routes to the admin console for human review.
- Face re-verification β High-value withdrawals: Gemini multimodal compare vs. optional Cloudinary signup reference (
FaceVerificationService) - Device fingerprint β
DeviceFingerprintService(FingerprintJS) supplies visitor ID for ML features + audit; not a separate βbehavioural modelβ layer inAnomalyDetectionEnginev2.1 (behavioral_scoreis null) - Trust Score engine β
TrustEngineService: deterministic 0β100 score from counters +last_anomaly_score; tiers Low / Building / Trusted / Elite; marketing copy onweb.htmlmaps these to three plain-language bands
Full technical deep-dive: docs/AI_INTELLIGENCE.md
A step-by-step walkthrough of the complete product experience:
- Phone + email
- Email OTP (6-digit; demo fallback
123456when engine unreachable) - BVN
- Name + gender + DOB (must match BVN / NIBSS)
- Squad virtual account creation (NUBAN)
- Face intro
- Blink liveness (MediaPipe) + optional Cloudinary reference upload
- Address (state β LGA β ward)
- 6-digit PIN (hashed via
PINService) - Success β sign in
- Seller creates listing β Description, price (β¦100 β β¦10M), delivery timeline (inspection UI optional / legacy field)
- Buyer joins β Enters
TXN-{uuid}; sees seller trust + listing context (pre-fund anomaly UI is limited in current wiring) - Buyer funds escrow β Demo path:
demo_balancedebit + state βFunded_Locked; Squad still powers VA, payouts, and releases in the wider system - Seller ships β Marks as shipped; both parties notified
- Buyer inspects β Confirms receipt OR raises a dispute
- Money releases β Funds transfer to seller's bank via Squad NIP payout
- Buyer files dispute with description + photo evidence
- AI agent analyzes and returns verdict with confidence score
- High confidence β auto-resolved. Low confidence β admin queue
- Resolution triggers automatic fund movement (refund / release / split)
Full walkthrough with screenshots: docs/USER_FLOW.md
Who can this reach:
- Immediate: ~50M Nigerians active in informal online commerce (WhatsApp, social media, classifieds)
- Year 1 target: 10,000 active users processing β¦500M+ in escrow transactions
- Expansion: Every African market with similar trust gaps β Ghana, Kenya, South Africa
How quickly:
- Zero-install (web app, no app store approval needed)
- Integrates with existing commerce channels β sellers share a transaction link on WhatsApp/Twitter
- Viral loop: every transaction exposes a new counterparty to ScrowPay
| Revenue stream | Model |
|---|---|
| Transaction fee | 1.5% of escrow amount (capped at β¦5,000 per transaction) |
| Instant Release | Premium feature for Elite-tier users (Trust Score β₯ 95) |
| API access | B2B escrow-as-a-service for marketplaces and logistics platforms |
Technical scalability:
- Stateless frontend (vanilla JS + CDN) β scales horizontally behind any CDN/load balancer
- Turso (distributed SQLite) β edge-replicated, handles millions of reads
- Squad handles all payment infrastructure β no PCI compliance burden
- AI engine is a stateless Flask container β auto-scales independently
| Claim | Evidence |
|---|---|
| Trust is the #1 barrier to Nigerian e-commerce | NOIPolls 2023: 67% of online shoppers cite fear of fraud as primary concern |
| Informal e-commerce exceeds $10B | EFInA Access to Financial Services survey + CBN reports on informal sector |
| 1 in 3 buyers has been scammed | Consumer protection data from FCCPC + independent surveys |
| Escrow reduces dispute rates by 60-80% | Payoneer & Escrow.com public case studies on marketplace trust |
| Isolation Forest is effective for transaction fraud | IEEE 2022 survey on unsupervised anomaly detection in financial data |
| BVN verification deters fraud | NIBSS data: BVN-linked accounts have 40% fewer fraud incidents |
| Real-time risk scoring improves catch rates | Stripe Radar public benchmarks + academic literature on pre-authorization scoring |
Full research citations: docs/RESEARCH_VALIDATION.md
Detailed step-by-step (with copy-paste commands and a comprehensive FAQ) is in SETUP_CHECKLIST.md.
Docker is the only supported way to run this project. No Python, no Node.js, no nginx β the bundled docker-compose.yml brings up the entire stack.
- Docker Desktop (with Compose v2) β https://www.docker.com/products/docker-desktop
- Git
- A free account on Turso (database)
- A sandbox account on Squad (payments)
- Recommended: free accounts on Google AI Studio (Gemini), Cloudinary (image storage), and Resend (email)
git clone <repository-url> scrowpay
cd scrowpay
cp .env.example .envEdit .env and fill in at minimum:
TURSO_DATABASE_URL=libsql://your-db.turso.io
TURSO_AUTH_TOKEN=eyJ...
SQUAD_SECRET_KEY=sandbox_sk_...
SQUAD_PUBLIC_KEY=sandbox_pk_...Copy the three templates and paste in your real values. None of these are auto-generated β each one has a *.example you copy from:
# Windows
Copy-Item frontend\env.js.example frontend\env.js
Copy-Item frontend\gemini-config.example.js frontend\gemini-config.js
Copy-Item frontend\cloudinary-config.example.js frontend\cloudinary-config.js
# Mac/Linux
cp frontend/env.js.example frontend/env.js
cp frontend/gemini-config.example.js frontend/gemini-config.js
cp frontend/cloudinary-config.example.js frontend/cloudinary-config.jsEach file's header explains exactly what to paste.
frontend/env.jsβ Turso + Squad keys (same values as.env, the browser needs its own copy)frontend/gemini-config.jsβ Google AI Studio key (unlocks dispute AI + face re-verification)frontend/cloudinary-config.jsβ Cloudinary cloud name (unlocks real image storage)
If you skip the Gemini / Cloudinary ones, the app still runs β it just degrades cleanly:
| Missing config | Degraded behaviour |
|---|---|
gemini-config.js |
Dispute auto-resolution disabled; face re-verification disabled. Rule-based risk only. |
cloudinary-config.js |
Dispute photos + face references fall back to base64 inline storage (hackathon mode). |
Resend key in .env |
Notifications still appear in the bell dropdown; no email is sent; signup OTP falls back to a dev code in the console. |
docker compose up -d
docker compose logs -f # watch boot| Service | URL |
|---|---|
| Frontend (landing page) | http://localhost:8080/web.html |
| Sign-in | http://localhost:8080/sign-in.html |
| Dashboard (after sign-in) | http://localhost:8080/dashboard.html |
| Admin console | http://localhost:8080/admin.html (requires is_admin flag) |
| AI risk engine | http://localhost:5000 |
| AI engine health | http://localhost:5000/health |
That's it. Create an account, fund a transaction, raise a dispute, watch the AI agent rule on it.
This is the path to take to see everything working in ~5 minutes:
- Sign up two accounts (use two browsers / incognito windows).
- Both go through phone β OTP (
123456) β BVN β name β liveness blink β address β PIN - Both end up with a Squad virtual account
- Both go through phone β OTP (
- Seller creates an escrow listing (β¦10,000 iPhone case), copies the transaction ID.
- Buyer joins the transaction with the ID.
- Watch the AI risk score appear; with a new account it flags "new account" but passes.
- Buyer funds it β money moves into the holding virtual account β notifications fire (bell + email).
- Seller marks as shipped β both get notified.
- Buyer raises a dispute with a description and a photo of the (allegedly) damaged item.
- The dashboard uploads the photo to Cloudinary β calls the Gemini dispute agent β gets a verdict.
- High confidence (>90%) β auto-resolved with fund transfer.
- Lower confidence β falls into the admin console queue.
- Admin opens
admin.html, sees the pending dispute, clicks it, reviews the photo + AI recommendation, and resolves it. Funds move; both parties get notified. - Try a large withdrawal (β₯ β¦500,000) β the face re-verification modal opens, captures a fresh frame, sends both your stored signup photo + the new frame to Gemini, and only releases the withdrawal on a "same person" verdict.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BROWSER β
β β
β web.html ββΊ account-creation.html ββΊ sign-in.html β
β β β
β βΌ β
β dashboard.html β
β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ΄ββββββββββββββ β
β β 30+ vanilla-JS services on `window.*`: β β
β β β’ TransactionService β’ StateMachineService β β
β β β’ BalanceService β’ TrustEngineService β β
β β β’ DisputeService β’ DisputeAgentService (Gemini) β β
β β β’ IsolationForestService β’ RiskEngineService β β
β β β’ AnomalyDetectionEngine β’ DeviceFingerprintService β β
β β β’ FaceVerificationService (Phase F, Gemini multimodal) β β
β β β’ CloudinaryService β’ NotificationService β β
β β β’ EmailOTPService β’ DeviceFingerprintService β β
β β β’ SessionService β’ SquadAPIService β β
β β ... β β
β βββββββββββ¬βββββββββββββββββββ¬ββββββββββββββββββ¬ββββββββββββββββ¬βββ β
β β β β β β
β admin.html (Phase G): separate page for manual dispute β β
β review, face audit, risky-txn monitor, user directory β β
βββββββββββββββΌβββββββββββββββββββΌββββββββββββββββββΌββββββββββββββββΌβββββ
βΌ βΌ βΌ βΌ
ββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββ
β Turso DB β β Squad API β β AI Engine β β Cloudinaryβ
β (libSQL, β β (virtual a/c β β (Flask + β β (photo + β
β HTTP) β β + transfers)β β IsoForest) β β face refs)β
ββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββ
β² β²
β β
ββββββββββββββββ β
β Gemini API β β
β (dispute β ββββββββββββ
β agent + β β Resend β
β face verify β β (email) β
β + risk hint)β ββββββββββββ
ββββββββββββββββ
Three deployable units:
| Unit | Tech | Port | Purpose |
|---|---|---|---|
frontend/ |
Vanilla JS + nginx | 8080 |
Static files; all UI + business logic |
ai-engine/ |
Python Flask + scikit-learn | 5000 |
Anomaly scoring + email proxy |
| External services | Turso, Squad, Gemini, Cloudinary, Resend | n/a | DB, payments, AI, storage, mail |
For a top-to-bottom walkthrough of every service, table, and flow, see APP_GUIDE.md (~500 lines, deliberately exhaustive).
- 10-stage account creation (phone + email, email OTP, BVN, Squad VA, liveness, address, 6-digit PIN) with BVN verification via Squad
- MediaPipe blink liveness check, with the captured frame uploaded to Cloudinary as a face reference (non-blocking if upload fails)
- Buyer-funded transactions: demo build debits
demo_balancethen locks state; Squad virtual accounts + holding/payout paths power real money movement in integrated environments - Deterministic state machine:
Created β Funded_Locked β In_Transit β Completed(plusDisputed,Cancelled,Refunded) - Auto-release when delivery / inspection timers fire (
StateMachineService) - Trust score with tiers (Low / Building / Trusted / Elite) and Instant Release eligibility
- Anomaly pipeline (
AnomalyDetectionEngine) βRiskEngineService(rules) +IsolationForestService(Flask ML). Current dashboard wiring: runsevaluate()post-fund and feedsTrustEngineService(non-blocking). Optional Gemini on listings is not enabled in code today. - Multimodal dispute resolution agent β Gemini 2.0 Flash reads the complaint + up to 4 photos and returns a structured JSON verdict (
favoredParty,confidence,payout,reasoning,evidenceCited) - Face re-verification gate β on high-value withdrawals, compares a fresh capture against the signup reference photo using Gemini multimodal; results are persisted to
face_verificationsfor audit
- Per-user notification feed with category filters and unread counts (bell icon)
- Transactional emails via Resend (funding confirmed, shipment, dispute opened, dispute resolved, face check failed)
- Email at signup with OTP delivery via the AI-engine email proxy
- Pending dispute queue with photo evidence, AI recommendation, and one-click resolution (refund / release / split)
- Face verification audit log filterable by verdict
- Risky transaction monitor (risk score β₯ 50)
- User directory with search
| Layer | Technology | Why |
|---|---|---|
| Frontend | Vanilla JS, HTML5, Tailwind CSS (CDN) | Zero build step, deploys anywhere static |
| Database | Turso (libSQL over HTTP) | Distributed SQLite; free tier is generous; HTTP API works from the browser without a backend |
| Payments | Squad API | Nigerian payment rails; virtual accounts; BVN verification |
| Risk ML | Python 3.11, Flask, scikit-learn (Isolation Forest) | Industry-standard unsupervised anomaly detection |
| Dispute AI | Google Gemini 2.0 Flash | Multimodal (text + image), JSON-mode output, low latency |
| Image storage | Cloudinary | Unsigned upload presets β no backend needed |
| Resend | Modern email API with a clean dashboard | |
| Face liveness | MediaPipe Face Mesh | Runs entirely in browser; no PII leaves the device for liveness |
| Device ID | FingerprintJS open-source v4 | Stable visitor IDs for sock-puppet detection |
| Container | Docker + Docker Compose | One-command local + production deploys |
scrowpay/
βββ README.md β you are here (answers: what, how, run it)
βββ APP_GUIDE.md β exhaustive technical deep dive
βββ DEPLOYMENT.md β production deployment recipes
βββ SETUP_CHECKLIST.md β copy-paste reproducibility script
βββ CONTRIBUTING.md β contribution guidelines
βββ LICENSE β MIT
βββ .env.example β environment variable template
βββ .gitignore
βββ docker-compose.yml β the only thing you run β brings up ai-engine + frontend
βββ nginx.conf β nginx config for the frontend container
βββ start-dev.sh / start-dev.bat β thin convenience wrapper around `docker compose up`
β
βββ docs/ β detailed documentation for judges
β βββ SQUAD_API_INTEGRATION.md β deep dive into all Squad API usage
β βββ AI_INTELLIGENCE.md β AI/ML architecture and data pipeline
β βββ USER_FLOW.md β step-by-step product walkthrough
β βββ RESEARCH_VALIDATION.md β evidence and citations for claims
β
βββ screenshots/ β product screenshots for submission
β βββ README.md β screenshot index
β
βββ frontend/ β all UI + business logic (vanilla JS)
β βββ README.md β per-file service index
β βββ web.html β landing page
β βββ account-creation.html β 10-stage signup
β βββ sign-in.html β phone + 6-digit PIN login
β βββ dashboard.html β main app (the big one)
β βββ admin.html β Phase G admin console
β βββ *.js β 30+ services; one class per file on window.*
β βββ env.js.example β copy to env.js (gitignored)
β βββ cloudinary-config.example.js β copy to cloudinary-config.js (gitignored)
β βββ gemini-config.example.js β copy to gemini-config.js (gitignored)
β βββ state-lga-area.json β Nigerian states / LGAs / wards
β
βββ ai-engine/ β Python Flask microservice
β βββ README.md
β βββ app.py β Flask app: /api/v1/score, /notify/*, /health
β βββ train_model.py β Isolation Forest training script
β βββ generate_synthetic_data.py β synthetic transaction generator
β βββ requirements.txt
β βββ Dockerfile
β βββ models/ β isolation_forest_model.pkl (committed)
β
βββ scripts/ β utility scripts
βββ README.md
βββ make-admin.ps1 β grant admin access (Windows)
βββ make-admin.sh β grant admin access (Mac/Linux)
βββ make-admin.bat β grant admin access (Windows CMD)
The admin console at /admin.html is gated by a database flag β there's intentionally no UI to grant yourself access.
Sign up normally, then run the helper script (it reads your Turso credentials from .env, so you never have to paste them):
# Windows - by user id (most reliable):
.\scripts\make-admin.ps1 -UserId 1
# Or by phone number:
.\scripts\make-admin.ps1 -PhoneNumber "+2348012345678"# macOS / Linux / WSL
./scripts/make-admin.sh --id 1
# or
./scripts/make-admin.sh +2348012345678If phone lookup fails even though the user exists, the script lists recent users with their ids β re-run with -UserId <n> / --id <n> to bypass phone matching (hidden whitespace in the stored phone can defeat exact equality).
Or for the manual route, run this SQL against your Turso database (Turso CLI, dashboard, or any libSQL client):
UPDATE users SET is_admin = 1 WHERE id = 1;
-- or
UPDATE users SET is_admin = 1 WHERE phone_number = '+2348012345678';Either way, the user now sees an "Admin Console" link in their profile panel, and admin.html will load for them. See scripts/README.md for full options.
- View all pending disputes (transactions stuck in
Disputedstate) - See the AI agent's recommendation + confidence for each
- Resolve manually with notes (refund buyer / release to seller / split 50/50)
- Audit the face verification log filtered by verdict
- Monitor high-risk transactions
- Search the user directory
Non-admin users hitting /admin.html see a 403 splash with a link back to the dashboard. The page makes zero non-public queries until the is_admin = 1 check passes.
Schema is auto-created and auto-migrated on first app load via TursoDBService.initializeSchema(). There are no separate migration files β every CREATE TABLE / ALTER TABLE lives in turso-db-service.js and is idempotent (IF NOT EXISTS / column existence checks).
Tables: users, transactions, transaction_state_history, disputes, trust_scores, trust_score_history, device_fingerprints, ai_risk_logs, security_logs, notifications, email_otps, face_verifications.
Full table-by-table description in APP_GUIDE.md Β§ 10.
curl -X POST http://localhost:5000/api/v1/score \
-H "Content-Type: application/json" \
-d '{
"user_id": "test_user",
"transaction_amount": 50000,
"transaction_velocity": 3,
"account_age_days": 45,
"device_fingerprint": 5432,
"time_of_day": 14,
"counterparty_trust_score": 75
}'Expected: {"risk_score": <0..100>, "verdict": "pass" | "fail", "anomaly_indicators": [...]}
See Demo flow above.
The AI engine ships a small pytest suite. Run it inside the container so you don't need a local Python install:
docker compose exec ai-engine pytest test_api.py test_model.pyThe frontend services don't have unit tests yet (see Known limitations).
| File | What it covers |
|---|---|
| README.md | Problem, solution, Squad APIs, AI, user flow, impact, quick start (this file) |
| docs/SQUAD_API_INTEGRATION.md | Deep dive into all 8 Squad API endpoints and how they power the product |
| docs/AI_INTELLIGENCE.md | AI/ML architecture: Isolation Forest, Gemini dispute agent, face verification |
| docs/USER_FLOW.md | Step-by-step product walkthrough with UI descriptions |
| docs/RESEARCH_VALIDATION.md | Evidence, citations, and validation for all claims |
| APP_GUIDE.md | ~500-line exhaustive walkthrough β every service, every table, every flow |
| SETUP_CHECKLIST.md | Copy-paste reproduction script for a fresh clone |
| DEPLOYMENT.md | Production deploys to Vercel / Netlify / VPS, Squad sandboxβproduction swap |
| CONTRIBUTING.md | Contribution guidelines (code style, JSDoc, commit format) |
| frontend/README.md | Per-service index of every JS file in frontend/ |
| ai-engine/README.md | AI engine API spec, model training, performance benchmarks |
| screenshots/README.md | Product screenshot index |
We're explicit about what's not production-grade. None of these affect the demo flow:
| Area | Status | Workaround / plan |
|---|---|---|
| OTP at signup | Hardcoded to 123456 β no SMS provider wired |
Termii or Twilio integration is a one-file change |
| Manual rate limiting | App-level only (rate-limiting-integration-example.js) |
Move to nginx / Cloudflare in production |
| Push notifications | Email only; no web-push or mobile push | Service worker + FCM/APNs |
| Frontend unit tests | None | Vitest + jsdom |
Disputes ai_reasoning column |
Not persisted (only the verdict + confidence are) | Add column; admin console will display it |
See CONTRIBUTING.md. Short version:
- One class per file, attached to
window.* - JSDoc every public method
- Follow the existing service-load order in
dashboard.html - Never commit
.env,frontend/env.js,frontend/gemini-config.js, orfrontend/cloudinary-config.js
MIT β see file for details.
Built for the Squad Hackathon. Special thanks to:
- Squad for excellent payment APIs and sandbox tooling
- Turso for a libSQL HTTP API that lets the browser talk to SQLite directly
- Google AI Studio for accessible multimodal Gemini access
- Cloudinary for unsigned upload presets that work without a backend
- Resend for the cleanest transactional email API around
Questions? Issues? Open a GitHub issue or check the troubleshooting section in DEPLOYMENT.md.
Built with care for Nigerian commerce.