Requirements
Requirements
- Distributor-specific pricing and variant-level inventory per region.
- Card payments (Paystack) and Mobile Money, reconciled reliably under retry.
- A configurable Buy-Now-Pay-Later lending product with KYC-gated approval.
- Four separate, securely authenticated user types with no privilege overlap.
- Secure handling of identity documents submitted for KYC.
- Fast, installable performance on low-end Android over patchy connections.
Research
Research & planning
- Studied Paystack's payment and webhook lifecycle to design reconciliation that survives retries and out-of-order delivery.
- Mapped the Mobile Money flow used locally, where the order/PO number becomes the payment reference and is confirmed over WhatsApp.
- Applied the OWASP Top 10 directly to authentication, CSRF and access control across all four portals rather than as a generic checklist.
Solution
The solution
I designed and deployed the platform in vanilla PHP and MySQL, delivering the full lifecycle from requirements gathering and database modelling through architecture, production deployment, scheduled processing and post-launch support. That's a deliberate tradeoff: no framework, no build step, chosen so the client's own team could host and maintain it cheaply on standard shared hosting, at the cost of writing more plumbing by hand.
Pricing is distributor-driven: a master catalogue holds a reference price and the admin's private cost, while the price a customer actually pays is set by the distributor serving their region, so the same SKU can be priced differently across the country without duplicating the catalogue.
The BNPL engine runs an internal credit score, generates a digital contract and an instalment schedule (1–24 months, 0–22% flat interest, capped non-compounding late fees), and a scheduled cron job charges instalments automatically as they fall due, all gated behind KYC verification.
Paystack card payments and Mobile Money are both integrated. Standard orders settle out-of-band via Mobile Money and WhatsApp confirmation; pre-order deposits go through a Paystack webhook verified with HMAC-SHA512 and processed idempotently, so a retried or duplicate event can never double-apply.
Four secure authentication domains (customers, distributors, administrators and Credit Officers) each carry TOTP two-factor authentication, account lockout, passwordless OTP and role-based access control, so a compromised customer session can never reach admin or distributor tooling.
Architecture
System architecture
Flayona is a server-rendered PHP application over MySQL (mysqli), installed as a PWA. Cross-cutting concerns (authentication guards per role, CSRF, payments, KYC upload, credit logic and audit logging) live in a shared library so every page composes the same vetted building blocks rather than reimplementing security per route.
Four separate portals sit behind their own auth guards: the customer storefront, the admin back office, the credit-officer portal that reviews BNPL applications, and the distributor portal with its own point-of-sale, stock and orders.
Payment is asynchronous by design: standard orders resolve out-of-band via Mobile Money and WhatsApp confirmation, pre-order deposits go through a signature-verified Paystack webhook, and a cron job drives automated BNPL instalment charging independently of any user session, so a customer closing their browser mid-checkout can never leave the order in an ambiguous state.
Data
Database design
The schema (30+ tables in production) is organised around commerce and credit. A master products table carries a reference price and the admin's private cost, while a distributor_products table sets the region-specific price and distributor_variant_stock tracks stock per distributor: the mechanism that makes distributor-specific pricing possible without duplicating the catalogue.
Orders link to order_payments (card or Mobile Money), and BNPL orders additionally link to a KYC application, a credit score and a schedule of instalments. Roles are separated at the data layer too: admins, credit officers and distributors are distinct account types with their own credentials and TOTP secrets.
Features
Key features
Distributor-specific pricing
Region-based fulfilment with per-distributor pricing and variant-level inventory, so the same catalogue is priced differently by region without duplication.
Configurable BNPL lending
1–24 month terms, tiered flat-interest pricing (0–22%), automated instalments, capped non-compounding late fees, gated behind KYC.
Paystack + Mobile Money
Card and Mobile Money payments; card flows reconciled via HMAC-SHA512-verified, idempotent webhooks.
Four secure authentication domains
Customers, distributors, admins and Credit Officers, each with TOTP 2FA, account lockout and passwordless OTP.
KYC document handling
Identity documents stored privately behind ownership-checked, authenticated access.
Distributor POS & stock
Distributors run point-of-sale, manage stock and fulfil orders from their own portal.
Loyalty, promotions & internal credit scoring
Configurable loyalty, membership, pre-order, professional-discount and internal credit-scoring capabilities.
Audit logging across every portal
An append-only audit trail records sensitive actions across all four authentication domains.
Engineering
Engineering decisions
Framework-free by deliberate tradeoff
Vanilla PHP and MySQL with no framework or build step: a conscious choice prioritising the client's ability to host and maintain the platform cheaply over developer convenience.
Full lifecycle ownership
Requirements gathering, database modelling, architecture, production deployment, scheduled processing and post-launch support, delivered end to end for the client.
Idempotent, race-safe payments
Webhook processing keys off signature verification and idempotency so retries and concurrent events can't double-apply.
KYC-gated credit
BNPL approval is strictly gated behind identity verification, encoded so the rule can't be bypassed by any code path.
Security
Security & correctness
- TOTP two-factor authentication and account lockout across all four authentication domains.
- HMAC-SHA512 webhook signature verification before any payment state changes.
- Idempotent, race-safe transaction reconciliation.
- Private, ownership-checked storage for KYC documents.
- CSRF protection and role-based access control throughout.
Interface
Screenshots




Reflection
Lessons learned
Payment correctness comes from modelling state precisely: idempotency and signature verification aren't optional extras once real money is involved.
Separating auth domains cleanly at the start avoids cross-role access bugs later; retrofitting that separation is much harder.
A client's hosting budget is a real design constraint, not a footnote. It shapes stack choices as much as functional requirements do.
What's next
Future roadmap
- This is ongoing client work; further features are scoped directly with the client as the platform grows.