Deliverable 3

User manual

Step-by-step guide for buyers, sellers, drivers and admins. Covers every feature of Me2You as deployed at m2y.online.

3.1 Introduction

3.1.1 Background

Me2You is a consumer-to-consumer (C2C) marketplace built for South Africa. The platform connects individual buyers and sellers in one unified account model, with escrow payment protection, three delivery options, a community discovery layer and a unified driver capability. The brief is mobile-first, low-bandwidth and POPIA-compliant.

3.1.2 About this website

The stack is the permitted set only: HTML5, CSS3, JavaScript (vanilla, no jQuery in the deployed build), PHP 8.3 (procedural, file-per-route), MySQL 8.0 (62 InnoDB tables, utf8mb4), Bootstrap 5.3.2 from a CDN and Leaflet 1.9.4 for maps. Payments are taken through PayFast (the South African gateway, sandbox in submission and live after merchant KYC). Transactional email runs through Titan SMTP. The pickup-point delivery option calls the Paxi API with a graceful fallback when credentials are absent. Hosting is on AWS EC2 behind an Application Load Balancer with Auto Scaling, RDS MySQL Multi-AZ, ElastiCache Redis and S3 for uploads. The whole stack is defined as Terraform in deploy/terraform/. No CMS is used.

3.2 Technical stack

Me2You is built strictly on the permitted technologies for the module, with no framework code generators and no CMS. The whole application is hand-written and version-controlled. The layers are as follows.

3.2.1 Application and front end

3.2.2 Integrations and infrastructure

The live platform that this manual describes is reachable below. Each operational section that follows links directly to the running page it explains.

3.3 Basics: accessing the website and the admin area

3.3.1 Accessing the website

Open any modern browser (Chrome, Firefox, Safari, Samsung Internet) on a phone, tablet or computer. Navigate to https://m2y.online. The site is fully responsive and works at 375 pixels, 768 pixels and 1280 pixels. No app download is needed.

3.3.2 The admin area

Admins sign in via the same login form. After login, the navigation reveals an "Admin" entry that opens the admin dashboard. The admin area is RBAC-gated: every admin route calls require_role('admin') server-side, so the navigation hint alone is not a security gate; the server check is. Admins can view the dashboard, manage users, moderate listings, manage orders, resolve disputes, approve drivers, run driver payouts, view the escrow ledger and the audit log.

3.4 Registration and authentication

3.4.1 Creating an account

  1. Click "Sign up" in the top navigation.
  2. Fill in full name, email, optional phone, and a password of at least 8 characters.
  3. Tick the POPIA consent box: "I agree to the Privacy Policy and consent to Me2You processing my personal data for marketplace services."
  4. Click "Create account". The account is created with the buyer role and you are signed in immediately.

3.4.2 Logging in

  1. Click "Sign in" in the navigation.
  2. Enter your email and password. The session cookie is HttpOnly and SameSite=Lax. The session id is regenerated on login, which prevents session-fixation attacks.
  3. If you have forgotten your password, click "Forgot password" and follow the email link (valid for one hour).

3.4.3 User roles and the unified account

Me2You uses a unified account model. A single user record can buy and sell from the same profile. The driver capability is an applied-for, admin-approved extension of a regular account, stored in a separate couriers table joined by user_id. The four roles are:

3.4.4 Editing your profile

Open the account menu (top right) and choose "Settings". Update display name, phone, password, avatar, cover image, notification preferences and bank details for payouts. The settings area also holds the POPIA data export and the account-deletion request.

3.5 Buyer guide

3.5.1 Browsing and searching

  1. From the homepage, tap a category pill or type into the search bar. Search uses MySQL FULLTEXT with prefix matching, so "dri" finds "drill" and "driver".
  2. Filter by category, price, condition (new, like-new, good, fair), province and pickup proximity. Sort by newest, price low-to-high, price high-to-low or relevance.
  3. Property and vehicle categories route to specialised browse pages with their own filters.

3.5.2 Product detail page

Each listing renders photos (and optional short video), title, price in rands, condition, full description, seller card with rating, and the action panel. The action panel adapts to the listing kind: a Buy or Lay-bye or Bid tab switcher appears on eligible listings. Open any listing from the browse page above to see a live product detail page.

3.5.3 Cart and checkout

  1. Tap "Add to cart" on any product. The cart icon in the navigation shows a badge count.
  2. Open the cart, adjust quantities and remove items as needed. The subtotal updates live.
  3. Tap "Checkout". Choose a delivery method (see 3.8). Choose a payment method (see 3.13). Optionally add a driver tip.
  4. Review the order summary. Tap "Pay safely". You are redirected to PayFast to enter card details.
  5. On successful payment, you receive a tracking reference (for example, M2Y-9F4K).

3.5.4 Order tracking

Open "My orders" from the account menu to see your order list. Each order shows a status timeline: placed, paid, dispatched, received, completed. The escrow badge sits prominently at the top, showing whether funds are held, released, frozen or refunded. For driver deliveries, the tracking page shows the courier's last known location on a Leaflet map.

3.5.5 Confirming receipt and leaving a review

When the parcel arrives, open the order and tap "Confirm receipt". This releases the escrow to the seller (or starts the 48-hour auto-release if you do nothing). You may then leave a review of the seller. Sellers can also leave a review of buyers; the two-sided review is rendered on each member's profile.

3.5.6 Opening a dispute

  1. On the order page tap "Something not right?".
  2. Choose a reason: not received, wrong item, damaged, not as described, other.
  3. Upload up to four evidence photos (maximum 4 MB each) and describe the problem.
  4. Tap "Submit dispute". The escrow row is frozen immediately, so the seller cannot be paid until an admin resolves.
  5. An admin reviews both sides and resolves within 48 hours: full refund, partial refund or release to seller.

3.6 Seller guide: products (adding, removing, updating)

3.6.1 Becoming a seller

Every member can list. Click "Sell" in the navigation or open the seller onboarding page to verify a phone number, add bank details for payouts and accept the seller agreement.

3.6.2 Adding a product (creating a listing)

  1. Open "Sell" in the navigation. The unified sell wizard asks for kind (item, property, vehicle), category, condition, price (rands), weight, description and photos.
  2. Upload one to six photos (JPEG, PNG or WebP, maximum 2 MB each). MIME is validated server-side using getimagesize so a file extension cannot be spoofed.
  3. Tap "Publish for moderation". The listing enters the pending queue. An admin reviews it within hours. If approved, it goes live and appears in search.

3.6.3 Updating a product

From the seller dashboard open any of your listings and tap "Edit". Change the title, description, price, condition or photos. Saving sends the listing back through moderation if a sensitive field changed; otherwise the change is live immediately.

3.6.4 Removing a product

From the seller dashboard tap the actions menu on a listing and choose "Take down". The listing is hidden from public browse but the historical orders that referenced it stay intact. To re-list, choose "Republish".

3.6.5 Adding a short video

Listings can carry a short MP4 (maximum 15 MB, maximum 30 seconds) alongside photos. Open the listing edit page and choose "Add video". The video appears in the listing gallery and in the discovery feed.

3.6.6 Importing from Facebook

Sellers can paste a Facebook Marketplace URL into the import page. The Open Graph parser pre-fills title, description, price, photos and location, which the seller reviews and confirms.

The site has three menu surfaces:

Categories are stored in the categories table and rendered through the same include on every category surface; adding a new category is a single INSERT and it appears everywhere.

3.8 Shipping and delivery options

Three delivery methods, all with escrow protection, set up in the shipping_methods table:

Me2You driver (door-to-door)

An approved Me2You driver picks up from the seller and delivers to the buyer's address. The delivery fee is distance-based (typically R35 to R90) and is calculated server-side using haversine distance against the courier's last ping. The order is published to the driver job board the moment the buyer pays.

Pickup point (Paxi, Pargo, PEP)

The seller drops the parcel at the nearest store. The parcel moves through the network in two to five business days. The buyer collects from their chosen pickup point using a 6-digit collection code. Network fees apply (typically R40 to R60).

Self-collection

The buyer and seller meet in person. A 6-digit OTP confirms the handover: the buyer shows the code only after inspecting the item, the seller enters it on their phone, and the escrow releases at that moment. Free.

3.9 The front page: adding and changing images

The homepage hero image is served from app/shared/hero-logo.png (a 520 by 520, 39 KB optimised asset with explicit width and height and fetchpriority high, so the largest contentful paint stays under target). To change it, replace the file with a similarly-sized image and rebuild the cache. Featured listings under the hero are pulled from the listings table by recency and trust score; the homepage code does not hard-code any image, so adding listings to the demo seed automatically updates the homepage.

3.10 Changing the logo

The Me2You peace-hand logo is in app/shared/ in three sizes (192, 512 and 1024 pixels) plus an Apple touch icon. Replace these four files with new artwork at the same dimensions; the includes pick them up automatically. The hub logo at /hub/shared/logo-peace.png is the same artwork, served by the hub independently so the hub can be rebranded without changing the marketplace.

3.11 Orders

3.11.1 What happens when someone places an order

A single database transaction wraps the whole checkout: the order row is created in "placed" status, the cart items are snapshotted into order_items (so subsequent price changes on the listing do not affect the order), and the cart is cleared. The buyer is then redirected to PayFast.

When PayFast settles, the ITN handler at /webhooks/payfast_itn.php runs four security checks (IP whitelist, signature, server-side validate, amount match against the database). On success it transitions the order to "paid", writes an escrow row in "held" status, and branches on the fulfilment type: for driver delivery it publishes a job to delivery_assignments; for self-collection it mints a 6-digit OTP into collection_otps; for pickup network it stubs a Paxi waybill into pickup_shipments.

3.11.2 What the seller needs to do when an order is received

  1. Watch the email notification from team@m2y.online or the seller dashboard.
  2. Pack the item. For driver delivery, wait for the courier to make contact. For pickup network, drop the parcel at the chosen store and enter the waybill code on the order. For self-collection, arrange a meeting time.
  3. Mark "Dispatched" on the order. The order moves to "dispatched" status.
  4. When the buyer confirms receipt (or 48 hours pass without dispute) the escrow releases. Earnings queue for the Friday payout batch.

3.12 Updating a page on the site

Me2You is a file-per-route procedural PHP application. Each user-facing URL maps to a file under app/, for example /listings/browse.php is app/listings/browse.php. To update a page, edit that PHP file directly. Static legal pages live under app/legal/. Shared chrome (header, footer, navigation, security headers and the Content-Security-Policy) lives in app/includes/header.php and app/includes/footer.php; changes there affect every page. Per-page CSS lives under app/assets/css/pages/ and is loaded only on its matching page, which keeps the per-page CSS small.

To add a new page, create the PHP file in the right directory, require the auth helpers and the header at the top, write the page body with output escaped through e(), and require the footer at the bottom. Add a link to the new page in app/includes/header.php or app/includes/footer.php so it is reachable.

3.13 Payments

Me2You uses a provider-agnostic payment layer (app/config/payments.php). One provider is active today and others are registered as "coming soon" so the buyer sees the roadmap and the operator can activate a new rail by flipping its status, without rewriting checkout:

Money is always handled as an integer number of cents in the database (price_cents, total_cents). The rands() helper is the only place currency is formatted for display, so the rand sign is consistent across the whole site. Payments never bypass escrow: every paid order writes an escrow_transactions row in "held" status that only releases when the buyer confirms or the 48-hour auto-release fires.

3.14 Driver guide

3.14.1 Onboarding

Apply on the driver registration page with SA ID, driver's licence, vehicle type and service area. Submit and you are redirected to the onboarding page which tracks application status. An admin reviews and approves the application within 48 hours. Once approved the "Driver" navigation entry appears in the account menu.

3.14.2 Going on duty and accepting jobs

  1. Open the driver job board. Toggle "On duty" at the top. Only on-duty drivers see open jobs.
  2. Jobs inside your service radius show normally. Jobs outside are greyed out with the actual distance.
  3. Each job card shows pickup to drop-off, distance, estimated time, payout, parcel weight and an escrow badge confirming the buyer has paid.
  4. Tap "Accept job". The system takes a row-level lock on the delivery_assignments row so two drivers cannot both win the same job.

3.14.3 Active delivery

  1. Navigate to the seller. Tap "Arrived at pickup", scan the parcel barcode (or type the order reference) and tap "Picked up".
  2. Drive to the buyer. Send periodic GPS pings in the background; the buyer's tracking map updates live.
  3. On arrival, capture proof of delivery: photo of the parcel at the address, buyer's signature on screen, and tap "Submit POD".
  4. The order flips to "received" and the 48-hour escrow countdown begins.

3.14.4 Earnings and payout

The driver earnings page shows this week, pending payout, month total, average per job, recent payout batches and full job history. Drivers are paid every Friday via bank EFT in one batch. Tips are 100 percent to the driver (no platform cut) and ride alongside the same EFT.

3.14.5 Ratings

The driver ratings page shows the star rating from buyers plus acceptance, on-time and cancellation KPIs. Drivers in the top 15 percent get "Gold driver" status, which gives priority visibility and a small per-delivery bonus.

3.15 Community and discovery

3.15.1 Discovery feed

The discovery feed is a vertical short-video feed with tabs For You, Following and Near me. Only the on-screen video plays, to keep prepaid data use low. Tap to unmute. Swipe up adds to cart, swipe in the opposite direction adds to the wishlist (Watch). Inline social bar lets the buyer like, comment, share, follow and shop without leaving the feed.

3.15.2 Community hubs

Community hubs group people by town, suburb, security estate or interest. Each hub has its own "what's happening" feed (updates, events, safety alerts) and a roster of members. A per-community manager (a different role from the site-wide admin) can approve members, pin posts and publish events without touching the global RBAC.

3.15.3 Following and saved searches

The following page shows the people and communities you follow. The saved-searches page stores named search queries and notifies you when a new listing matches. The check_saved_searches cron runs every 15 minutes.

3.16 Transaction depth: lay-bye, auctions, swap, watch

3.16.1 Reserve with deposit (lay-bye)

On eligible listings the action panel offers a "Lay-bye" tab. The buyer pays a deposit into escrow, the seller reserves the item and approves within the chosen window, and the buyer pays the remainder in instalments. A timestamped risk acknowledgement is recorded for both parties.

3.16.2 Auctions

Time-boxed listings show a countdown, current bid, minimum next bid (price-scaled increments: R1 for cheap items, R100 for expensive ones), and a bid form. The bid endpoint is transaction-guarded so two bids cannot both win.

3.16.3 Swap offers

The "Propose a swap" button on the product detail page opens a flow where the buyer picks one of their own listings to offer in trade, writes a message, and sends. The seller sees both items side by side and accepts, declines or counters. A message thread is opened automatically.

3.16.4 Watch and price-drop alerts

Tap the heart on any listing to "Watch" it. A row is written to wishlists. When the seller drops the price, the price_drop_alerts cron sends a notification: "Price dropped from R349 to R299 on Nike Air Max."

3.16.5 Seller vacation mode

Sellers can pause their shopfront without delisting. The vacation page carries a toggle; when on, all of the seller's listings display a "back on" date and new orders are paused.

3.17 Privacy, POPIA and account control

The account settings page holds POPIA-related controls:

Passwords are hashed with bcrypt and automatically rehashed on login if the cost factor increases. Every database query uses PDO prepared statements with EMULATE_PREPARES off, so prepared parameters are bound at the protocol layer. Output is escaped through e() everywhere. CSRF tokens are session-bound and validated with hash_equals.

3.18 Admin guide

Every page below is RBAC-gated and reachable only by a signed-in administrator. Each opens the live admin tool it describes.

3.18.1 Dashboard and KPIs

The admin dashboard shows active users, live listings, 30-day GMV in rands, open disputes and an "attention queue" for items that need triage. Below the tiles: a recent orders table with buyer and seller names, a top-categories breakdown and a 30-day GMV chart.

3.18.2 User management (CRUD)

The user management page is a searchable, filterable table. Clicking a row opens a side drawer with the user's profile, order history and KYC status. Admins can edit name, email, role and status (active, suspended, deleted). Only the super-admin can hard-delete.

3.18.3 Listing moderation

The moderation page shows the queue of pending listings plus flagged live listings, with system risk signals (price anomaly, off-platform call-to-action, new-account flag). Three actions: approve, request edit, reject and warn. A rejection requires an audit note.

3.18.4 Order management

The order management page shows the full orders table with status filter pills. Click any order for the detail view: items, buyer and seller, delivery tracking, status workflow, escrow state and admin actions (force complete, issue refund, add note).

3.18.5 Dispute resolution

The disputes page opens disputes oldest first. The split panel shows the buyer's side and the seller's side with their evidence. Three resolution buttons: refund buyer (escrow refunded, order cancelled), partial split (admin enters the amounts), release to seller (escrow released, order completed). A resolution note is required. Both parties are emailed.

3.18.6 Escrow ledger

The escrow ledger is a read-only ledger of every escrow transaction. Use it to verify the auto-release cron is working, check frozen escrows tied to open disputes and reconcile against PayFast settlement reports.

3.18.7 Driver approvals and payouts

The verifications page holds the queue of driver applications with their ID and licence uploads. The driver payouts page groups pending driver earnings by driver, exports a bank-ready CSV for the weekly EFT batch and marks the batch as paid once the bank confirms.

3.18.8 Audit log

The audit log records every admin action: actor, action, target type, target id, timestamp and a note. Required for POPIA accountability and useful for support investigations.

3.19 Checking web traffic and statistics

Three signals are available out of the box:

A Lighthouse CI workflow runs on every push and asserts mobile performance, accessibility, best-practices and SEO budgets against the four most-visited pages. An external uptime monitor (UptimeRobot) pings the health endpoint every five minutes and emails on failure.

3.20 Appendix: setting up the website

3.20.1 Local development

mysql -u root -p -e "CREATE DATABASE m2y CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root -p -e "CREATE USER 'm2y'@'localhost' IDENTIFIED BY 'm2y_dev'; GRANT ALL ON m2y.* TO 'm2y'@'localhost';"
mysql -u m2y -pm2y_dev m2y < db/schema.sql
for f in db/migrations/*.sql; do mysql -u m2y -pm2y_dev m2y < "$f"; done
for f in db/seeds/*.sql;      do mysql -u m2y -pm2y_dev m2y < "$f"; done

php -S localhost:8080 -t app app/router.php

Open http://localhost:8080 in any browser. The router script makes the PHP built-in server serve the custom 404 page (Apache uses ErrorDocument; the router emulates that for local dev).

3.20.2 Production deployment (AWS)

cd deploy/terraform
terraform init
terraform validate
terraform plan
terraform apply

The Terraform stack provisions a VPC, an Application Load Balancer with HTTP-to-HTTPS redirect, an Auto Scaling group of EC2 instances, RDS MySQL Multi-AZ with 7-day backups, ElastiCache Redis Multi-AZ, an S3 uploads bucket, Secrets Manager and a CloudWatch alarm set (with SNS email) plus an AWS Budgets cost alarm. Each instance bootstraps from deploy/user-data.sh: install PHP and Apache, pull secrets from Secrets Manager into Apache SetEnv, install the CloudWatch agent, run deploy/migrate.php behind a Redis lock. The complete runbook is in deploy/GO-LIVE-EC2.md and every external account (PayFast, Titan, Paxi, GoDaddy) is documented in deploy/EXTERNAL-ACCOUNTS.md.

3.20.3 Demo accounts (password password123)

PayFast sandbox card for the demo flow: 4000 0000 0000 0002, expiry 12/30, CVV 123.

3.21 Troubleshooting and help

3.21.1 Common errors

ErrorCauseFix
Bad CSRF tokenSession expired or form submitted twiceRefresh the page and try again
403 ForbiddenWrong role for this pageSign in with the correct role
PayFast "Payment failed"Card declined or bank timeoutTry again or use a different method
File too largePhoto exceeds 2 MBResize before upload
Listing rejectedModerator flagged itCheck the rejection reason in the seller dashboard and edit
OTP expiredThe 6-digit code is valid for 24 hoursContact support to issue a new code

3.21.2 Getting help