Full-Stack Developer — Finalize & Deploy BookBridge (Supabase + Stripe + Security Hardening)
Buget: -
HOURLY / PART_TIME
⭐ 0.00 (0)
United States
javascript, php, html5, jquery, web-programming, api, css, api-integration
We are seeking a Full-Stack Developer to finalize and deploy BookBridge, integrating Supabase, Stripe, and enhancing security. The role involves both backend and frontend development, ensuring a seamless user experience and robust security measures. The ideal candidate will have experience with Supabase, Stripe, and security hardening, and be able to work independently to deliver high-quality results.
the admin email address
**Project overview**
BookBridge is a bilingual (EN/FR) student textbook marketplace operating exclusively in Côte d'Ivoire. The complete frontend prototype is finished — a single HTML/CSS/JS file (~216 KB) with all pages, dashboards, fee logic, escrow flows, admin and super admin panels, auth flows, and client-side security hardening already built and working in vanilla JS.
Your job is to wire it to a real backend, implement production-grade security, connect payments, and deploy it. No frontend refactoring is needed.
---
What is already built (you inherit this)
- Home, Browse, Book Share, Escrow Centre, My Account, Contact, Careers, Privacy Policy pages
- Seller dashboard: listings management, ship orders panel, swap requests
- Buyer dashboard: orders, confirm receipt panel, swap requests
- Admin dashboard (6 tabs): approvals queue, listings, users, escrow view-only, disputes
- Super Admin dashboard (4 tabs): escrow release/refund, all customers, admin accounts, platform overview
- 5-step signup: role selection → personal info + full CI address → phone OTP → email OTP → account created
- Forgot password (phone OTP → email reset link) and lost phone (admin notification) flows
- Fee logic fully implemented: even exchanges = 0% fees; sales = buyer +5% tech, seller −10% total; uneven swaps = buyer pays diff +5% tech fee, seller receives diff −10%
- Bilingual EN/FR toggle throughout
- Côte d'Ivoire address fields: 15-city dropdown, 27-region dropdown, +xxx fixed phone prefix
Client-side security already in place (you extend server-side):
- Content Security Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy meta headers
- DOMPurify XSS sanitisation on all user-generated content
- `esc()` and `sanitiseText()` helpers on all DOM insertions
- Client-side rate limiting: login (5 attempts / 15 min), OTP send (3 / 15 min), OTP verify (3 / 5 min)
- OTP expiry (5 minutes), single-use enforcement, 3-attempt lockout
- Session management: 30-minute TTL, auto-expiry check, session warning banner, secure logout
- Role-based access control: `requireAuth()` and `requireRole()` guards on all sensitive actions
- Input validation: email, CI phone (+xxx), password strength, price range
- Client-side audit log mirroring server events
- Password strength indicator in signup form
- Clickjacking prevention (JS + X-Frame-Options)
---
Your scope of work
1. Supabase backend
Set up a Supabase project with the following tables, all with proper types, foreign keys, and indexes:
- `users` — id, name, email, phone_encrypted, role (buyer/seller/admin/super_admin), street_encrypted, city, region, postal_encrypted, country, status, created_at
- `books` — id, seller_id (FK users), title, author, subject, price_fcfa, condition, share_enabled, approval_status, approved_by (FK users), created_at
- `swap_requests` — id, poster_id (FK users), my_book, my_price_fcfa, want_book, want_price_fcfa, status, created_at
- `escrow_transactions` — id, type (sale/share), book_id (FK books), buyer_id (FK users), seller_id (FK users), buyer_pays_fcfa, seller_receives_fcfa, step (0–3), ship_status, tracking_number, stripe_payment_intent_id, created_at, settled_at
- `disputes` — id, txn_id (FK escrow_transactions), filed_by (FK users), reason, status, notes, escalated_to_super_admin, created_at
- `pending_approvals` — id, book_id (FK books), submitted_at, reviewed_by (FK users), decision, decided_at
- `admin_audit_log` — id, admin_user_id (FK users), action_type, target_id, target_type, metadata (JSONB), ip_address, created_at
**Row-level security policies (non-negotiable):**
- Buyers: read own orders in `escrow_transactions` only
- Sellers: read/update own listings in `books`, read own transactions
- Admin role: read all tables; write `books.approval_status`, `disputes.notes`, `pending_approvals`
- Super admin role: full write on `escrow_transactions` (step, settled_at); read all PII columns
- Regular users: cannot read `phone_encrypted`, `street_encrypted`, `postal_encrypted` of other users — ever
- Service role key: never exposed to the client. All privileged operations go through edge functions only.
Deliver SQL migration files as versioned `.sql` files in a `/supabase/migrations` folder.
2. PII encryption at rest
- Phone numbers, street addresses, and postal codes must be encrypted using Supabase Vault or `pgcrypto` before storage
- These fields must be decryptable only by the user themselves and super admin role
- Admin role sees only: name, email, city, role, and status — never raw phone or address
- Ensure encrypted fields are not logged in Supabase logs or email payloads
3. Authentication (Supabase Auth)
Connect the existing 5-step signup flow to real Supabase Auth:
- Email + password with email OTP verification via Supabase's built-in SMTP or a custom Resend/SendGrid provider
- Phone OTP via **Africa's Talking SMS API** (Côte d'Ivoire +225, MTN / Orange CI / Moov networks)
- JWT access tokens with 30-minute expiry and refresh token rotation
- Refresh token revocation on: password change, account suspension, logout
- Session tokens delivered via `HttpOnly`, `Secure`, `SameSite=Strict` cookies — never localStorage
- Forgot password: phone OTP (step 1) → email reset link (step 2 — two-factor recovery)
- Lost phone: trigger admin notification email to system admin mail with encrypted user reference
4. Stripe Connect payments and escrow (XOF / FCFA)
- Integrate Stripe Connect for marketplace split payments in XOF (West African Franc)
- Implement the exact fee logic defined in the frontend:
- Even exchange (diff = 0): zero fees, no escrow transaction created
- Sale: buyer pays price + 5% technology fee; seller receives price − 5% sales − 5% technology (net 90%)
- Uneven swap: buyer pays diff + 5% tech on diff; seller receives diff − 10% fees on diff
- On payment, create a Stripe PaymentIntent and hold funds (do not capture immediately)
- Capture only after buyer confirms receipt — or super admin triggers release
- Super admin Refund button triggers a Stripe refund to the buyer's original payment method
- **Stripe webhook handler (server-side Supabase edge function):**
- Verify every webhook using `Stripe-Signature` header before processing
- Handle: `payment_intent.created`, `payment_intent.succeeded`, `charge.refunded`, `transfer.created`
- Use idempotency keys on all Stripe API calls
- Raw card numbers must never reach your server — use Stripe.js on the client side only
**5. Transactional emails (Resend or SendGrid)**
Build and trigger the following emails, all in both English and French:
| Trigger | Recipient | Key content |
| Book submitted for approval | Seller | Book title, review timeline |
| Book approved and live | Seller | Live listing link |
| Book rejected | Seller | Rejection reason |
| Order confirmed, funds in escrow | Buyer | Amount paid, escrow protection notice |
| Order received — please ship | Seller | Buyer address (decrypted for this use only), tracking instructions |
| Book shipped | Buyer | Tracking number, how to confirm receipt |
| Receipt confirmed, funds released | Seller | Net amount received after fees |
| Dispute opened | Both + admin | Dispute ID, reason, next steps |
| Dispute escalated | Super admin | Full dispute context |
All emails must:
- Never include raw phone numbers or full PII beyond what is operationally necessary
- Use masked references (e.g. last 4 digits of phone) where identification is needed
- Include an unsubscribe link for marketing emails (transactional emails are exempt)
**6. Admin and super admin backend enforcement**
The frontend dashboards are fully built. You enforce everything server-side:
- Book approval: `POST /api/approve-book` — verifies caller has `admin` or `super_admin` JWT role before updating `books.approval_status` and triggering seller email. Logs to `admin_audit_log`.
- Escrow release: `POST /api/release-escrow` — verifies `super_admin` JWT. Triggers Stripe transfer to seller. Updates `escrow_transactions.step = 3`. Logs to `admin_audit_log`.
- Escrow refund: `POST /api/refund-escrow` — verifies `super_admin` JWT. Triggers Stripe refund. Logs to `admin_audit_log`.
- User suspension: `POST /api/suspend-user` — verifies `admin` JWT. Sets `users.status = suspended`. Revokes all active sessions.
- All admin actions logged to `admin_audit_log` with: `admin_user_id`, `action_type`, `target_id`, `target_type`, `metadata`, `ip_address`, `created_at`
7. Additional security hardening (server-side)
These must be enforced at the infrastructure level, not just the frontend:
- Rate limiting at the edge**: Vercel/Netlify middleware enforcing 100 req/min per IP for general endpoints, 5 req/min for auth endpoints
- CORS policy**: Supabase project only accepts requests from your production domain — no wildcard origins
- API key hygiene**: All keys (Supabase, Stripe, Africa's Talking, email provider) stored as environment variables. No keys committed to GitHub. Rotate all keys every 90 days (document the process).
- Dependency scanning**: Enable GitHub Dependabot on the repository
- Database backups**: Configure daily automated Supabase backups. Weekly offsite backup to S3 or equivalent.
- Branch protection**: Main branch requires pull request review before merge — no direct pushes
8. Production deployment
- Deploy frontend to Netlify or Vercel with GitHub CI/CD (main branch → production)
- Supabase project on paid plan (required for edge functions and realtime)
- Provide DNS configuration instructions for a `.ci` domain
- All secrets stored as environment variables — never hardcoded
- Configure Stripe webhook endpoint in Stripe dashboard with correct event subscriptions
- Run the deployed URL through [securityheaders.com](https://securityheaders.com) — must achieve grade A before handoff
---
Deliverables
1. Private GitHub repository with all code, SQL migrations in `/supabase/migrations`, and `.env.example`
2. Updated `bookbridge.html` with real Supabase JS client calls replacing all demo functions
3. Supabase edge functions for all privileged server-side operations
4. Stripe Connect integration with correct XOF/FCFA fee logic and verified webhook handler
5. Africa's Talking SMS OTP working on real +xxx country phone numbers
6. 9 transactional email templates (EN + FR) live and tested
7. Admin and super admin accounts configured with correct Supabase roles
8. Deployed production URL with grade A on securityheaders.com
9. README covering: architecture overview, local dev setup, environment variables, deployment steps, key rotation guide, how to add/remove admin users
---
Tech stack
Supabase (Postgres + Auth + Vault + Edge Functions + Realtime) · Stripe Connect (XOF) · Africa's Talking SMS · Resend or SendGrid · Netlify or Vercel · Vanilla JS (no framework — do not refactor the frontend)
Payment milestones
| # | Deliverable | % |
| 1 | Supabase schema + RLS + PII encryption + real auth (email + phone OTP) live and tested | 20% |
| 2 | Stripe Connect escrow with correct FCFA fee logic + verified webhook handler | 15% |
| 3 | All 9 transactional emails (EN + FR) triggered and delivered | 15% |
| 4 | Admin and super admin backend enforcement live with audit logging | 25% |
| 5 | Production deployment + securityheaders.com grade A + README | 25% |
Screening questions:
Have you integrated Stripe Connect for a marketplace with split payments before? Share a project example and describe how you handled the escrow/hold logic.
Have you worked with Africa's Talking or any SMS OTP API for West African phone numbers? Which countries and networks?
Have you implemented PII encryption at rest in Postgres using Supabase Vault or pgcrypto? Describe your approach.
Have you written row-level security policies in Supabase that differentiate between multiple roles (user, admin, super admin)? Describe the most complex policy set you have built.
Are you comfortable working with vanilla JS (no React or Vue)? The frontend will not be refactored — your work is purely backend and integration.
__What is your fixed-price bid and estimated timeline to complete all five milestones?
Engagement type: Fixed price, milestone-based. Single developer or small team fine. Must be available for async communication (Slack or email) throughout.
Deschide pe Upwork