A production-ready member management and payment processing platform built for Brilliant Child College 2007 alumni to manage dues, events, and help-desk operations with real-time updates and secure automated flows.
- Framework: React Router v7 (Framework Mode)
- Styling: Tailwind CSS
- Icons: Lucide React
- Components: UI components based on shadcn/ui
- Client State: TanStack Query & React Context
- Framework: Express.js with TypeScript
- Contract: ts-rest for type-safe API communication
- Database: MongoDB via Mongoose
- Authentication: Better Auth
- Payments: Paystack API
- Background Jobs: Upstash QStash/Workflow
- Real-time: Server-Sent Events (SSE)
The system uses a two-tier onboarding process to ensure all members are verified and have complete profiles.
- Registration: Admins can register members. New members receive a temporary password via email (Upstash QStash).
- First Login: Members log in, verify their email, and complete their profile information.
- Onboarding Checklist:
- Basic Info (Phone, Gender, Location, Occupation)
- Update Profile Avatar (Cloudinary)
- Complete Bank Details (for future payouts or transfers)
- Completion: Once all steps are completed, the
isOnboardedstatus is updated, and the user gains full access to the dashboard.
The core of the application is a secure payment processing engine for dues, event fees, and donations.
- Initialization: A member selects a payment type (e.g., Monthly Dues). The client calls
initializePayment, and the server communicates with Paystack to generate a unique transaction reference and checkout URL. - Processing: The user is redirected to Paystack's secure portal to complete the transaction.
- Verification: After payment, the user is redirected back to
/dashboard/payments/verify. The server then confirms the status with Paystack's API. - Sync & SSE: Once verified, the transaction is recorded in MongoDB. An SSE event (
payment:completed) is broadcasted to all logged-in sessions to update UI stats in real-time.
- Event Creation: Admins create events with descriptions, dates, and optional fees.
- Engagement: Members can mark interest in events.
- Payments: If an event has a fee, members can pay directly through the integrated payment flow.
- Ticketing: Members can create support tickets for technical or payment-related issues.
- Resolution: Admins manage tickets from the dashboard, assigning staff and updating status (Open -> In-Progress -> Resolved).
- Communication: Status updates trigger real-time notifications to the affected member via SSE.
The application maintains a persistent connection (/api/v1/sse/stream) to keep the dashboard alive without manual refreshes.
- Broadcasts include:
payment:completed,ticket:updated,event:created, andmember:created. - These events automatically trigger TanStack Query cache invalidations, ensuring the UI always displays fresh data.
βββ client/ # React Router 7 Frontend
β βββ app/
β β βββ components/ # UI & Shared Components
β β βββ context/ # Stores & Application State
β β βββ features/ # Feature-specific logic (dashboard, payments, etc.)
β β βββ routes/ # Page components & layouts
β β βββ lib/ # Utilities (storage, queryClient)
β βββ public/ # Static Assets
βββ server/ # Express.js Backend
β βββ src/
β β βββ config/ # Environment, Auth, & DB Config
β β βββ contract/ # ts-rest API definitions
β β βββ middleware/ # Security, Rate Limiting, Auth
β β βββ models/ # Mongoose Schemas
β β βββ workflows/ # Upstash Workflow Jobs
β β βββ routes/ # API Implementations
β βββ index.ts # Entry Point
- Security Headers: Managed via Helmet with custom CSP policies for Cloudinary and Paystack.
- Rate Limiting: Granular rate implementation for sensitive endpoints (Auth, Payments) using
express-rate-limit. - Validation: Strict input sanitization and typing via Zod across both client and server.
Create a .env.development file in the server/ directory for local development, or .env.staging for staging. On Vercel, set these as Environment Variables in the project dashboard.
# ββ App ββ
NODE_ENV=development
# ββ Database (MongoDB) ββ
DATABASE_URL=mongodb://localhost:27017
DATABASE_NAME=bcc007pay
# ββ Authentication (Better Auth) ββ
BETTER_AUTH_URL=http://localhost:4600
BETTER_AUTH_SECRET=<generate with: openssl rand -hex 32>
# ββ URLs ββ
CLIENT_URL=http://localhost:4500
SERVER_URL=http://localhost:4600
# ββ Cloudinary (Media Uploads) ββ
CLOUDINARY_CLOUD_NAME=<your-cloud-name>
CLOUDINARY_API_KEY=<your-api-key>
CLOUDINARY_SECRET_KEY=<your-secret-key>
CLOUDINARY_UPLOAD_PRESET=<your-upload-preset>
# ββ Paystack (Payments) ββ
PAYSTACK_SECRET_KEY=<your-secret-key>
PAYSTACK_PUBLIC_KEY=<your-public-key>
# ββ Upstash (Redis + Background Jobs) ββ
UPSTASH_REDIS_REST_URL=<your-redis-url>
UPSTASH_REDIS_REST_TOKEN=<your-redis-token>
QSTASH_TOKEN=<your-qstash-token>
QSTASH_URL=<your-qstash-url>
# ββ Resend (Email) ββ
RESEND_API_KEY=<your-resend-api-key>
# ββ Sentry (Error Tracking) ββ
SENTRY_DSN=<your-sentry-dsn> # Optional# ββ Sentry (Source Maps) ββ
SENTRY_AUTH_TOKEN=<your-sentry-token>
SENTRY_ORG=<your-sentry-org>
SENTRY_PROJECT=<your-sentry-project>
# ββ E2E Testing (Playwright) ββ
E2E_ADMIN_EMAIL=admin@example.com
E2E_ADMIN_PASSWORD=<password>
E2E_MEMBER_EMAIL=member@example.com
E2E_MEMBER_PASSWORD=<password>| Service | Purpose | How to Get |
|---|---|---|
| MongoDB | Database | MongoDB Atlas or local instance |
| Paystack | Payment processing | Paystack Dashboard β Settings β API Keys |
| Cloudinary | Image uploads | Cloudinary Console β Dashboard |
| Upstash | Redis cache + QStash workflows | Upstash Console β Create Redis DB + QStash |
| Resend | Transactional emails | Resend Dashboard β API Keys |
| Better Auth | Auth (uses its own keys) | Generate BETTER_AUTH_SECRET via openssl rand -hex 32 |
| Sentry | Error monitoring (optional) | Sentry β Projects β Client Keys |
To ensure a high-standard, production-ready codebase, the project follows a strict branching and CI/CD strategy.
main: The production-ready branch. Only merges fromstagingare allowed via Pull Requests.staging: The integration branch. All feature branches and bug fixes must be merged here first for testing.feature/*orfix/*: Temporary branches for new development or patches.
Both main and staging branches are protected to prevent accidental direct pushes and ensure quality:
- Pull Requests (PRs) Required: All changes must go through a PR. Direct pushes to
mainandstagingare blocked. - Status Checks: GitHub Actions must pass (Linting, Typechecking, Unit Tests, E2E Tests) before a merge is permitted.
- Code Reviews:
mainrequires at least 1 approving review from a code owner.stagingrequires a successful PR and passing CI (no manual approval required for solo development speed).
- Admin Enforcement: These rules apply to everyone, including repository owners, to ensure a consistent workflow.
- CI (GitHub Actions): Every PR to
stagingormaintriggers an automated pipeline:- Server: Typechecks and Vitest unit/integration tests.
- Client: Typechecks, Vitest unit tests, and Playwright E2E tests.
- Deployment:
- Merges to
maintrigger a production deployment to Vercel for both client and server applications.
- Merges to
When starting a new task:
- Create a feature branch from latest
staging. - Push changes and open a PR targeting
staging. - Use the provided PR Template to describe your changes.
- Once CI passes and the PR is merged, create a subsequent PR from
stagingtomainfor production release.