PayPost is an enterprise-grade fintech and campaign management infrastructure purposefully engineered to solve the systemic trust, concurrency, and financial reconciliation challenges in Indiaβs Creator and UGC Economy.
Traditional influencer marketplaces suffer from slot over-allocation, silent floating-point currency drifts, chaotic revision loops, and spam notification penalties. PayPost eliminates these failure modes at the architecture level through Multi-Document ACID Transactions, an Immutable Double-Entry Ledger, Two-Phase Asynchronous UPI Disbursements, and a TRAI-Compliant Quiet Hours Notification Outbox.
| π Launch Live Web App | βοΈ API Gateway Health | π Technical Blueprint | π 25 Architecture Diagrams | π§ͺ Test Matrix |
|---|
| Tier | Provider | Status | Public URL | Architecture Highlights |
|---|---|---|---|---|
| Frontend Client | Vercel | pay-post.vercel.app | Vite 5 SPA, Tailwind CSS, Mobile-first responsive touch UI | |
| Backend API Gateway | Render | paypost.onrender.com | Node.js Express, Multi-worker polling engine, JWT Guards | |
| Database Cluster | MongoDB Atlas | Encrypted Cloud Replica Set | Multi-document ACID Transactions, Read-isolated sessions | |
| Health Check | REST Endpoint | /api/health |
Real-time gateway status, latency, and uptime timestamp |
π Production Security Standard: All banking mock gateways, Mongo cluster credentials, and JWT secret salts are injected through zero-trust environment vaults. Zero hardcoded secrets exist in the repository.
Ready to test in 30 seconds? Use these pre-loaded sandbox credentials:
| Experience Role | Login Email | Password | What You Can Test |
|---|---|---|---|
| π’ Brand Manager | brand@demo.com |
Password123! |
Create campaigns, review Instagram Reel submissions, approve payouts, and manage revisions. |
| π¨ Creator (Ammar) | creator1@demo.com |
Password123! |
View earnings ledger, request instant UPI withdrawals to bank, and test notification quiet hours. |
| π Applicant Creator | creator2@demo.com |
Password123! |
Browse open marketplace briefs and test concurrent slot reservations with zero slot stealing. |
π Security Notice: Database connection strings, JWT private keys, and credential secrets are strictly decoupled from version control and injected via encrypted cloud environment variable managers (Render Environment Secrets & Vercel Project Environment Variables). MongoDB Atlas connection strings are never exposed in public repositories.
| # | Industry Problem in Creator Platforms | Root Cause | PayPost Architectural Solution |
|---|---|---|---|
| 1 | Over-allocation & Slot Stealing | Read-then-write race conditions when multiple creators apply simultaneously. | Atomic Conditional Reservation: MongoDB $expr: { $lt: ["$approvedCount", "$totalSlots"] } in a single ACID update guarantees zero slot leaks. |
| 2 | Floating-Point Financial Drifts | Using standard JS floating math (0.1 + 0.2 !== 0.3) for rupees causes rounding loss. |
Integer Paise Rule: Every single balance, payout, tax, and fee is stored and calculated strictly as integer paise (βΉ1 = 100 paise). |
| 3 | Unbalanced Ledger / Money Duplication | Wallet balance credited without audit trail; server crash duplicates payouts. | Immutable Double-Entry Ledger: Every rupee credited or debited writes a strictly balanced, immutable journal entry with 0-sum system invariants. |
| 4 | Never-Ending Review Cycles | Brands trap creators in infinite revision loops without paying. | Two-Revision Hard Cap: Strict state machine enforcing a maximum of 2 revision rounds with mandatory feedback; triggers automatic escalation. |
| 5 | Ghost Withdrawals / Double Spends | Creators withdraw twice before external banking gateways return settlement status. | Two-Phase Hold-and-Settle UPI: Funds transition to heldPaise instantly; reconciled asynchronously via idempotent background workers. |
| 6 | Unlawful Spam During Sleep Hours | Automated notifications wake up creators at 2 AM, violating TRAI statutory regulations. | IST Quiet-Hours Outbox: Zero-dependency pure UTC time math (+330 min) holds transactional alerts between 9:00 PM and 9:00 AM IST. |
| 7 | Heavy, Sluggish Mobile Interfaces | Bulky desktop dashboards squeezed down to mobile screens break layout. | Mobile-First 360px Design: Custom responsive card streams, bottom tab bars, and bottom sheets engineered without heavy third-party UI libraries. |
flowchart TD
subgraph ClientLayer ["Client Layer (Mobile & Desktop Responsive)"]
SPA["React 18 + Vite SPA"]
Tailwind["Tailwind CSS 360px Layout Engine"]
AxiosClient["Axios HTTP Interceptor (JWT Auto-Attach)"]
end
subgraph GatewayLayer ["Application Gateway & Security Layer (Express)"]
RateLimit["IP Rate Limiter"]
Cors["CORS Whitelist Guard"]
AuthMiddleware["JWT Authentication Guard"]
RBAC["Role-Based Access Guard (Brand / Creator)"]
end
subgraph BusinessLayer ["Service & Business Domain Layer"]
CampService["Campaign Management Service"]
AppService["Application & Slot Allocator"]
SubService["Submission & 2-Revision State Machine"]
FeeService["Integer Tax & Fee Calculator (TDS + GST)"]
WalletService["Double-Entry Ledger & Wallet Service"]
OutboxService["Quiet-Hours Notification Engine"]
end
subgraph DataLayer ["Database & ACID Transaction Engine (MongoDB Atlas)"]
ReplicaSet[("MongoDB Replica Set (Multi-Document ACID)")]
UsersCol[("Users & Creator Profiles")]
CampaignsCol[("Campaigns")]
AppsCol[("Applications")]
SubsCol[("Submissions")]
WalletsCol[("Wallets")]
LedgerCol[("Immutable Ledger Journal")]
OutboxCol[("Notification Outbox Queue")]
end
subgraph WorkerLayer ["Asynchronous Background Worker Layer"]
PayoutWorker["UPI Withdrawal Reconciliation Worker"]
OutboxWorker["TRAI Quiet-Hours Dispatch Worker"]
MockUPI["Mock Banking Provider (Idempotent Webhooks)"]
end
SPA --> AxiosClient
AxiosClient --> RateLimit --> Cors --> AuthMiddleware --> RBAC
RBAC --> CampService & AppService & SubService & FeeService & WalletService & OutboxService
CampService & AppService & SubService & WalletService & OutboxService --> ReplicaSet
ReplicaSet --- UsersCol & CampaignsCol & AppsCol & SubsCol & WalletsCol & LedgerCol & OutboxCol
PayoutWorker -. Polling & Lock .-> WalletsCol & LedgerCol
OutboxWorker -. Polling & Time Math .-> OutboxCol
PayoutWorker <--> MockUPI
| Layer | Technology | Version | Architectural Rationale |
|---|---|---|---|
| Runtime | Node.js | >= 18.x |
Enterprise-standard JavaScript runtime with asynchronous I/O and event loop efficiency. |
| API Framework | Express.js | ^4.19.2 |
Minimalist HTTP routing engine decoupling controllers, services, and models. |
| Database | MongoDB Atlas | v7.0+ |
Cloud Document Database providing Multi-Document ACID Transactions across Replica Sets. |
| ODM | Mongoose | ^8.3.0 |
Schema definition, automatic validation rules, pre-save hooks, and session-aware querying. |
| Authentication | JWT (jsonwebtoken) | ^9.0.2 |
Stateless, cryptographic access tokens carrying user identity and role claims. |
| Password Security | Bcrypt.js | ^2.4.3 |
Cryptographic salted one-way hashing protecting user passwords against rainbow tables. |
| Frontend Framework | React | ^18.3.1 |
Declarative component UI engine with Virtual DOM reconciliation. |
| Build Tool | Vite | ^5.4.0 |
Ultra-fast ESM-based local development server and optimized rollup production bundler. |
| Styling | Tailwind CSS | ^3.4.1 |
Utility-first CSS framework compiled down to minimal byte size without bloated UI runtimes. |
| Client Routing | React Router DOM | ^6.23.0 |
Declarative client-side routing, protected auth guards, and URL query parameter tracking. |
| Testing Framework | Jest | ^29.7.0 |
Fast, deterministic test runner with built-in code coverage, mocks, and snapshot capabilities. |
| In-Memory Testing | mongodb-memory-server | ^9.1.8 |
Boots isolated in-memory MongoDB replica sets per test run without cloud latency. |
| Deterministic PRNG | mulberry32 algorithm | Native | Seeded pseudo-random number generator powering the 100-action concurrency chaos engine. |
All financial transactions are calculated strictly in Integer Paise (βΉ1.00 = 100 paise). The platform implements statutory deductions governed by Indian Income Tax (Section 194J/194C) and GST laws.
For a campaign milestone deliverable approved at gross reward
| Component | Rate | Formula | Amount (βΉ) | Integer Value (Paise) |
|---|---|---|---|---|
| Gross Campaign Payout | 100% | βΉ5,000.00 | 500,000 |
|
| Platform Commission | 10% | βΉ500.00 | 50,000 |
|
| GST on Commission | 18% | βΉ90.00 | 9,000 |
|
| TDS Withholding | 1% | βΉ50.00 | 5,000 |
|
| Creator Net Credit | 87.2% | βΉ4,360.00 | 436,000 |
PayPost uses Socket.IO for live screen synchronization across brand and creator views, adhering to four core engineering rules:
- Signal + Refetch: Sockets do NOT stream sensitive business data (budgets, reserved/paid amounts, emails, phone numbers, UPI IDs, pitches, notes, or post URLs). They emit only lightweight signals containing resource IDs and status indicators (
{ type: "application:changed", applicationId, status }). The frontend receives the signal and refetches authenticated data from the canonical REST API. - Emit Only After Commit: Inside database transactions, events are queued into a transaction-keyed
WeakMap. If the transaction rolls back or is retried due to transient conflicts, the event queue is cleared. Events are flushed and sent over WebSocket only after the transaction commits successfully. - Server Decides Rooms: Clients cannot arbitrarily subscribe to rooms. Upon JWT handshake authentication, sockets are strictly confined to
user:<userId>androle:<role>. Any client-side join requests are ignored. - Resync on Reconnect & Zero Event Replay: Sockets do not maintain persistent offline message streams. When a disconnected client reconnects, or when a background tab wakes up after >30s, the client broadcasts an internal
resyncevent to fetch fresh REST data.
- In-App Live Updates & Toasts: Real-time Socket.IO notifications and toasts are purely in-app transient UI conveniences. They are not subject to TRAI quiet hours (9:00 PM β 9:00 AM IST) or user communication opt-outs.
- Asynchronous WhatsApp/Email Outbox Queue: The persistent notification outbox queue remains the formal, statutory notification channel dictated by the platform requirements, complete with strict IST quiet hours deferrals, opt-out checks, and worker dispatching. Sockets do not replace the outbox queue; they only keep open browser tabs synchronized.
- Single Server Instance: The current Socket.IO implementation runs on a single server instance. Scaling out horizontally across multiple container replicas requires the
@socket.io/redis-adapter. - No Event Replay: Sockets do not store missed events in offline queues. The frontend handles connection drops via automatic resync on reconnect.
- Free-Tier Sleep Cycles: On free hosting tiers (e.g. Render spin-downs), idle connections close automatically; upon waking, the client automatically falls back to polling and reconnects when the service responds.
PayPost was designed from day one to withstand aggressive concurrent traffic spikes (such as thousands of creators applying for limited slots during a viral brand launch).
sequenceDiagram
autonumber
actor Creator1 as Creator 1 (Tab A)
actor Creator2 as Creator 2 (Tab B)
participant API as Express API Server
participant Mongo as MongoDB ACID Replica Set
participant Ledger as Double-Entry Ledger
Note over Mongo: Campaign State: totalSlots = 1, approvedCount = 0
Creator1->>API: POST /api/applications/:id/approve (Worker A)
Creator2->>API: POST /api/applications/:id/approve (Worker B)
par Atomic Reservation Race
API->>Mongo: updateOne( { _id: campId, $expr: { $lt: ["$approvedCount", 1] } }, { $inc: { approvedCount: 1 } } )
API->>Mongo: updateOne( { _id: campId, $expr: { $lt: ["$approvedCount", 1] } }, { $inc: { approvedCount: 1 } } )
end
Note over Mongo: Document lock acquired by Worker A
Mongo-->>API: Worker A: nModified = 1 (SUCCESS)
Mongo-->>API: Worker B: nModified = 0 (REJECTED - 0 slots left)
API->>Ledger: Commit Creator 1 Reservation
API-->>Creator1: 200 OK: "Creator approved & slot locked"
API-->>Creator2: 409 Conflict: "Campaign slots exhausted"
Note over Mongo: Final State: approvedCount = 1 (Zero Over-Allocation)
| Vulnerability Vector | Classic Failure Mode | PayPost Concurrency Defense | Tested In |
|---|---|---|---|
| Simultaneous Slot Grab | 50 applicants approved for 5 slots due to parallel find() then save(). |
Single-Statement Atomic $expr: Database-level conditional increment; exactly |
tests/application.test.js |
| Submit vs Withdraw Race | Creator submits Instagram reel while simultaneously withdrawing application in another tab. |
Document State Precondition Lock: Submission checks status === 'APPROVED'; withdrawal locks and transitions status in a single atomic query. |
tests/submission.test.js |
| Double Payout Withdrawal | User clicks "Withdraw" twice rapidly; two βΉ500 transactions spawn on a βΉ500 balance. |
Two-Phase Hold-and-Settle: Available balance immediately decremented to heldBalance inside an ACID transaction; duplicate calls get 400 Insufficient Available Balance. |
tests/withdrawal.test.js |
| Worker Crash & Duplicate Payout | Server restarts while bank payout is in-flight. |
Idempotent Reconciliation Worker: Polls HOLD records with timestamps older than 60s; recovers state via provider reference or refunds wallet safely. |
tests/withdrawal.test.js |
A dedicated, comprehensive architectural library is documented with full visual Mermaid charts and mathematical explanations in docs/diagrams/:
| # | Diagram Document | Flow Description & Architectural Purpose |
|---|---|---|
| 01 | 01-system-topology.md | Component architecture across React SPA, Express gateway, MongoDB ACID sessions, and workers. |
| 02 | 02-campaign-lifecycle.md | Full chronological lifecycle from campaign brief to UPI bank payout settlement. |
| 03 | 03-atomic-reservation-race.md | Atomic reservation flowchart showing single-statement $expr update preventing slot over-allocation. |
| 04 | 04-submission-revision-state-machine.md | State machine of deliverable review lifecycle enforcing the strict 2-revision hard cap. |
| 05 | 05-money-flow-and-ledger.md | Financial flow chart demonstrating double-entry accounting and integer paise conservation. |
| 06 | 06-two-phase-withdrawals.md | Two-phase hold-and-settle sequence diagram for asynchronous UPI disbursements. |
| 07 | 07-notification-outbox-quiet-hours.md | Transactional outbox pattern eliminating dual-write bugs with pure UTC quiet-hours math. |
| 08 | 08-database-er-model.md | Complete Entity-Relationship (ER) Diagram covering all 8 collections, indexes, and relations. |
| 09 | 09-auth-and-rbac-flow.md | User authentication, bcrypt salted hashing, JWT claims, and role-based route security. |
| 10 | 10-campaign-creation-and-funding-logic.md | Brief creation, deadline validations, and budget-per-creator funding integrity checks. |
| 11 | 11-campaign-post-approval-edit-rules.md | Safeguards preventing brands from reducing payouts or slots after creators have been accepted. |
| 12 | 12-campaign-cancellation-and-creator-protection.md | Brand campaign cancellation barriers protecting creators with active in-progress deliverables. |
| 13 | 13-creator-reapplication-decision-matrix.md | Decision logic governing when creators can reapply without slot-grabbing exploits. |
| 14 | 14-submit-vs-withdraw-race-condition.md | ACID mutual exclusion between deliverable submission and application withdrawal. |
| 15 | 15-instagram-url-validation-and-deduplication.md | Instagram Post/Reel URL regex sanitization and campaign-wide link deduplication. |
| 16 | 16-statutory-tax-and-fee-deduction-engine.md | Step-by-step integer paise computation pipeline for platform commission, GST, and TDS. |
| 17 | 17-double-entry-wallet-credit-settlement.md | Multi-document ACID session executing deliverable approval, wallet credit, and ledger commit. |
| 18 | 18-withdrawal-two-phase-hold-and-settle.md | State transitions from availableBalance to heldBalance to bank settlement or refund. |
| 19 | 19-withdrawal-worker-polling-and-reconciliation.md | Background worker polling loops, out-of-session banking API calls, and crash recovery. |
| 20 | 20-pure-utc-quiet-hours-time-arithmetic.md | Timezone calculation adding +330 min to UTC to strictly evaluate IST quiet windows (21:00-09:00). |
| 21 | 21-notification-dispatch-and-opt-out-pipeline.md | Worker polling, send-time user opt-out checks, quiet-hours deferral, and mock dispatch. |
| 22 | 22-brand-action-center-aggregation-query.md | Single-trip MongoDB aggregation query driving the Brand Action Center dashboard. |
| 23 | 23-creator-next-actions-urgency-engine.md | Priority weighting algorithm generating the Creator Next Actions banner (deadlines, revisions). |
| 24 | 24-deep-link-auto-focus-and-scroll-flow.md | URL deep-link handling (?tab=submissions&focus=<id>) with tab switching and pulse glow. |
| 25 | 25-seeded-concurrency-chaos-test-engine.md | Deterministic PRNG (mulberry32) chaos test verifying ledger invariants across 100 actions. |
- Node.js:
v18.0.0or higher - npm:
v9.0.0or higher - Git
# Clone the repository
git clone https://github.com/kasimshah19/PayPost.git
cd PayPost
# Configure Backend Environment (includes REALTIME_ENABLED=true)
cp backend/.env.example backend/.env
# Configure Frontend Environment (includes VITE_SOCKET_URL)
cp frontend/.env.example frontend/.env- Backend (
.env):REALTIME_ENABLED=true: Toggles the Socket.IO server engine. Whenfalseor absent, the server gracefully skips Socket initialization and all emits become silent no-ops without altering business execution.
- Frontend (
.env):VITE_SOCKET_URL=http://localhost:5000: Explicit Socket.IO server connection URL. In development, falls back tohttp://localhost:5000. In production, if unset, real-time defaults to offline rather than spamming localhost.
- Render Backend Web Service (
Environment Variables):PORT: Provided dynamically by Render.MONGODB_URI: MongoDB Atlas replica set connection string.JWT_SECRET: 32+ character cryptographic secret.CLIENT_URL:https://pay-post.vercel.app,http://localhost:5173(exact Vercel frontend domain; spaces and trailing slashes are trimmed automatically).REALTIME_ENABLED:trueWORKER_ENABLED:trueNOTIFICATION_WORKER_ENABLED:true
- Vercel Frontend Project (
Project Settings -> Environment Variables):VITE_API_URL:https://paypost.onrender.com/apiVITE_SOCKET_URL:https://paypost.onrender.com- Build-time note: Vite bakes
VITE_*variables into the JavaScript bundle at build time. Whenever you edit environment variables on Vercel, you must trigger a Redeploy.
- Verify Deployed WebSocket / Socket.IO Health:
A healthy response returns an Engine.IO packet starting with
curl "https://paypost.onrender.com/socket.io/?EIO=4&transport=polling"0and a session ID JSON:0{"sid":"...","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000}
# Install backend dependencies
cd backend && npm install
# Install frontend dependencies
cd ../frontend && npm installcd ../backend
# Verify MongoDB Atlas connection and initialize indexes
npm run db:init
# Seed demonstration accounts and test campaigns
npm run seed:demo# Terminal 1: Launch Backend API and Background Workers
cd backend
npm run dev
# Terminal 2: Launch Frontend Web App
cd frontend
npm run devThe frontend will be accessible at http://localhost:5173 and the backend API at http://localhost:5000/api.
When seeded via npm run seed:demo, the following accounts are ready for instant testing:
| Role | Email Address | Password | Permissions & Pre-Configured State |
|---|---|---|---|
| Brand Account | brand@demo.com |
Password123! |
Active campaigns, pending applicant submissions, Action Center cards ready. |
| Creator 1 | creator1@demo.com |
Password123! |
Approved campaigns, deliverables in revision, wallet loaded with earnings. |
| Creator 2 | creator2@demo.com |
Password123! |
Fresh applicant profile ready to browse campaigns and test one-click apply. |
PayPost features 203 passing automated tests across 15 distinct test suites, covering all boundary conditions, tax deductions, concurrent race attacks, and financial invariants.
cd backend
npm testPASS tests/submission.test.js
PASS tests/withdrawal.test.js
PASS tests/auth.test.js
PASS tests/notification.test.js
PASS tests/application.test.js
PASS tests/wallet.test.js
PASS tests/chaos.test.js
PASS tests/dashboard.test.js
PASS tests/e2e.lifecycle.test.js
PASS tests/campaign.test.js
PASS tests/models.test.js
PASS tests/fees.test.js
PASS tests/health.test.js
PASS tests/quietHours.test.js
PASS tests/money.test.js
Test Suites: 15 passed, 15 total
Tests: 203 passed, 203 total
Snapshots: 0 total
Time: 29.944 s
Result: 100% Passing (Zero Flaky Tests)
- Stateless JWT Guard: Cryptographic tokens expired after 7 days, carrying user ID and role claims (
creatororbrand). - Strict Password Hashing: Passwords are salted with 10 bcrypt salt rounds and never saved in plain text.
- Database Unique Constraints: Unique indexes on
[campaignId, creatorId]prevent duplicate applications at the database engine level. - Input Sanitization: All incoming URL parameters, Instagram URLs, and body inputs are validated against strict regex patterns.
- Secret Scanner Utility: Custom pre-commit scanner (
npm run check:secrets) audits all tracked files to guarantee zero API keys or.envsecrets leak into version control.
This project is licensed under the MIT License. Built with β€οΈ for Indian creators and modern digital brands.
Author: Kasim Shah
Connect with me:
- Portfolio: kasim-portfolio-umber.vercel.app
- LinkedIn: Kasim Shah
- GitHub: @kasimshah19
Β© 2026 PayPost β Creator Deliverables & Financial Settlement Engine. All rights reserved.