A full-stack prototype for creating, viewing, and fulfilling peer-to-peer payment requests.
This project was built as a spec-driven, AI-assisted engineering assignment. It implements the core lifecycle of a payment request system: creation, dashboard management, request detail viewing, fulfillment simulation, decline/cancel actions, and automatic expiration handling.
- Live App: https://payment-request-topaz.vercel.app/
- GitHub Repository: https://github.com/mitralone/payment-request.git
The app includes three demo users for evaluation and E2E testing.
| User | Password | |
|---|---|---|
| Alice | [email protected] |
password123 |
| Bob | [email protected] |
password123 |
| Charlie | [email protected] |
password123 |
The login screen also includes quick-login shortcuts for these accounts.
The prototype supports the following flows:
- Create a payment request using recipient email or phone, amount, and optional note
- Generate a shareable request link
- View outgoing and incoming requests on a dashboard
- Filter by status and search by relevant party
- View request details, including expiration countdown
- Pay, decline, or cancel requests based on user role and request state
- Automatically persist expired requests when detected during reads or actions
This is a prototype system. It does not perform real money movement, notification delivery, or external payment processing.
- Accepts recipient email or phone, amount, and optional note
- Validates amount and contact format
- Creates a
PENDINGpayment request - Generates a unique shareable link
- Outgoing requests for the authenticated requester
- Incoming requests for the authenticated recipient
- Status-based filtering
- Search support
- Empty-state handling
- Displays amount, note, requester, recipient, timestamps, and current status
- Shows expiration countdown
- Conditionally exposes actions based on authenticated user role
- Pay: simulated with a 2–3 second processing delay
- Decline: available to the intended recipient while request is
PENDING - Cancel: available to the requester while request is
PENDING
- Requests expire 7 days after creation
- Expired requests cannot be acted upon
- Expiration is evaluated during reads and actions, and persisted to
EXPIRED
- Request details can be viewed using a share token route
- Unauthorized or unauthenticated viewers receive read-only access
- Only the intended recipient may pay or decline
- Only the requester may cancel
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- Database: Supabase Postgres
- Authentication: Supabase Auth
- ORM: Prisma
- Styling: Tailwind CSS + shadcn/ui
- Testing: Playwright with recorded test runs
- Deployment: Vercel
Amounts are stored as integer cents (amountCents) rather than decimal strings or floating-point values. This avoids precision issues in JavaScript and keeps request amounts deterministic.
Requests follow a strict state machine:
PENDINGPAIDDECLINEDCANCELEDEXPIRED
Only PENDING requests may transition. All terminal states are immutable.
State-changing actions are centralized in the domain layer and enforced server-side. If multiple actions race, only the first successful transition from PENDING persists; later attempts fail cleanly.
Recipient auto-linking is based on case-insensitive email matching only. Phone input is accepted for request creation and shareable-link usage, but is not used for automatic user linking in this prototype.
A request can be viewed through a tokenized route. Anyone with the link may view details, but only authorized users may act on the request.
No background worker is used. Expiration is evaluated lazily during reads and actions, and persisted when discovered. This keeps the implementation simple while preserving correct request state.
- Node.js 20+
- npm
- Supabase project or local Supabase CLI environment
Create a .env file with:
NEXT_PUBLIC_SUPABASE_URL="..."
NEXT_PUBLIC_SUPABASE_ANON_KEY="..."
SUPABASE_SERVICE_ROLE_KEY="..."
DATABASE_URL="..."npm installnpm run db:migrate
npm run db:seednpm run devThe app will be available at http://localhost:3000.
Run the Playwright suite:
npx playwright testThe E2E suite covers:
- login
- create request
- dashboard visibility
- pay flow
- decline flow
- cancel flow
- expiration lockout
- access control for share-link views
Recorded test videos are written to the Playwright output directory.
This project was built using a spec-driven, AI-assisted workflow.
The process included:
- defining project principles with Spec-Kit
- writing and clarifying the feature spec
- generating the implementation plan and task breakdown
- using AI coding assistance for scaffolding and test generation
- validating generated code and refining architecture manually
A detailed breakdown is available in:
docs/ai-workflow.md
- No real payment processor is integrated
- No email or SMS delivery is implemented
- Authentication is simplified for demo use
- Only email is used for automatic recipient linking
- Phone requests remain unclaimed unless accessed via shareable link
- Expiration is handled lazily rather than by scheduled job
- Single currency only (
USD)
- Phone number normalization and matching
- Notification system (email/SMS)
- Background expiration jobs
- Audit logging for state transitions
- Production-grade onboarding and account claiming flows