Back to hub

Design diagrams

CRC, EERD, Context, Level 1 DFD, Use case and the physical schema for v1.1.

What this page covers

The six design artefacts required for D2 2.2, plus the order workflow. Every diagram on this page is rendered as HTML and CSS so it stays readable on a mobile screen and prints cleanly. Reflects the v1.1 codebase: 62 MySQL tables, courier dispatch, escrow with 48 hour auto-release, community and feed, swaps, bids, lay-bye, and pickup at PEP, Pargo and Paxi.

1. CRC cards

Class, Responsibilities, Collaborators for the 20 most active domain classes in the v1.1 build. Index-card layout so each card fits a single mental chunk.

User

Responsibilities
  • Authenticate with bcrypt password
  • Hold role: buyer, seller, driver or admin
  • Track rating average and review count
  • Accept current terms version
Collaborators
  • Listing
  • Order
  • Review
  • Courier
  • TermsAcceptance

Listing

Responsibilities
  • Hold title, slug, description and condition
  • Store price in cents and price type
  • Track status: draft, live, sold, removed
  • Generate share token for WhatsApp links
Collaborators
  • User (seller)
  • Category
  • ListingImage
  • ListingMedia
  • Offer
  • Auction

Category

Responsibilities
  • Hold name, slug and parent for tree
  • Carry icon and SEO meta
  • Drive nested-set browse paths
Collaborators
  • Listing
  • Category (self)

ListingImage

Responsibilities
  • Store relative image path
  • Track sort order and alt text
Collaborators
  • Listing

ListingMedia (video)

Responsibilities
  • Store MP4 path and poster frame
  • Track duration and aspect
  • Drive the swipe feed
Collaborators
  • Listing
  • FeedRanker

CartItem

Responsibilities
  • Hold listing and quantity per cart
  • Support saved-for-later state
Collaborators
  • Cart
  • Listing

Order

Responsibilities
  • Track state: placed, paid, dispatched, received, completed, cancelled
  • Snapshot delivery, tip and protection fee
  • Carry reference and PayFast pf_payment_id
Collaborators
  • User (buyer, seller)
  • OrderItem
  • EscrowTransaction
  • DeliveryAssignment
  • Dispute

OrderItem

Responsibilities
  • Snapshot title, slug, price at purchase
  • Hold qty and weight at purchase
Collaborators
  • Order
  • Listing

EscrowTransaction

Responsibilities
  • Hold buyer funds until delivery plus 48 hours
  • Track status: held, released, refunded, frozen
  • Carry release_due_at timestamp
Collaborators
  • Order
  • Dispute
  • EscrowReleaseCron
  • PayFast

Courier (driver)

Responsibilities
  • Track on-duty state and last ping
  • Hold home base lat and lng for radius
  • Carry approval status (pending, approved, suspended)
Collaborators
  • User
  • DeliveryAssignment
  • DriverEarning

DeliveryAssignment

Responsibilities
  • Bind order to a courier
  • Track legs: accepted, picked up, delivered
  • Carry payout cents and tip cents
Collaborators
  • Order
  • Courier
  • AssignmentLeg
  • CollectionOTP

CollectionOTP

Responsibilities
  • Generate 6 digit code at handover
  • Expire after 30 minutes
  • Verify at pickup and at delivery
Collaborators
  • Order
  • DeliveryAssignment

Dispute

Responsibilities
  • Freeze escrow on open
  • Hold buyer evidence and seller response
  • Resolve as refund, release or partial
Collaborators
  • Order
  • EscrowTransaction
  • Admin
  • DisputeEvidence

Review

Responsibilities
  • Hold 1 to 5 star rating and text
  • Lock once posted
  • Roll into user rating average
Collaborators
  • User (rater, ratee)
  • Order

ShippingMethod

Responsibilities
  • Quote price by weight and distance
  • Mark as courier, pickup point, self-collect or cash on delivery
Collaborators
  • Order
  • PickupShipment
  • DeliveryAssignment

PickupShipment

Responsibilities
  • Hold pickup point code (PEP, Pargo, Paxi)
  • Track waybill and shelf code
  • Poll status from carrier
Collaborators
  • Order
  • PaxiAdapter

Community

Responsibilities
  • Hold name, slug, suburb and guidelines
  • Track member count and post count
  • Carry visibility (open, private)
Collaborators
  • User (manager, members)
  • CommunityPost
  • Listing

CommunityPost

Responsibilities
  • Hold body, image, attached listing
  • Count reactions and comments
Collaborators
  • Community
  • User
  • PostComment
  • PostReaction

Auction

Responsibilities
  • Hold start, reserve and current bid
  • Track ends_at and close trigger
  • Award to top bidder at close
Collaborators
  • Listing
  • Bid
  • AuctionCloseCron
  • Order

LaybyePlan

Responsibilities
  • Reserve listing for buyer
  • Schedule weekly instalments
  • Release reservation on default
Collaborators
  • Listing
  • User
  • LaybyePayment
  • Order (on completion)

Offer (and Swap)

Responsibilities
  • Carry buyer counter-price in cents
  • Or propose a swap listing
  • Track accepted, rejected, expired
Collaborators
  • Listing
  • User
  • Order

Wishlist

Responsibilities
  • Watch a listing for price drop
  • Fire alert when price drops
Collaborators
  • User
  • Listing
  • PriceDropAlertCron

ListingImport

Responsibilities
  • Parse a Facebook Marketplace export
  • Stage rows for review
  • Convert approved rows to live listings
Collaborators
  • Seller (User)
  • Listing
  • Admin

2. Entity relationship diagram

Core 20 entities and their relationships, in a tabular EERD style. Primary keys are highlighted, foreign keys are blue. Relationship lines are noted under each card.

users

  • id BIGINT
  • email VARCHAR(190) UNIQUE
  • password_hash CHAR(60)
  • display_name VARCHAR(80)
  • role ENUM role
  • status ENUM enum
  • rating_avg DECIMAL(3,2)
  • persona ENUM

1 to many: listings, orders (as buyer or seller), reviews, follows.

categories

  • id INT
  • name, slug UNIQUE
  • parent_id INT NULL (self)
  • icon, sort, is_active

Self-referencing tree. 1 to many: listings.

listings

  • id BIGINT
  • seller_id users.id
  • category_id categories.id
  • title, slug, condition
  • price_cents INT, price_type ENUM
  • weight_kg, status ENUM
  • share_token CHAR(12)

1 to many: listing_images, listing_media, offers, bids. Many to many: wishlists.

listing_images

  • id BIGINT
  • listing_id listings.id
  • path, sort INT

Many to one: listings.

listing_media

  • id BIGINT
  • listing_id listings.id
  • kind ENUM (video)
  • path, poster_path
  • duration_s INT

Many to one: listings. Drives the feed.

carts and cart_items

  • id BIGINT
  • user_id users.id
  • listing_id listings.id (in items)
  • qty INT

One cart per user. Many items per cart.

orders

  • id BIGINT
  • buyer_id, seller_id
  • reference CHAR(12) UNIQUE
  • subtotal_cents, delivery_cents
  • tip_cents, protection_cents
  • total_cents INT
  • fulfillment_type ENUM
  • status ENUM state machine
  • pf_payment_id VARCHAR(64)

1 to many: order_items. 1 to 1: escrow_transactions, delivery_assignments.

order_items

  • id BIGINT
  • order_id, listing_id
  • title_snapshot, slug_snapshot
  • price_cents_snapshot
  • qty INT

Many to one: orders. Snapshots protect against price edits after sale.

escrow_transactions

  • id BIGINT
  • order_id UNIQUE
  • amount_cents INT
  • status ENUM held/released/refunded/frozen
  • release_due_at DATETIME
  • released_at, payout_ref

1 to 1: orders. Watched by escrow_release cron.

couriers

  • id BIGINT
  • user_id users.id UNIQUE
  • on_duty TINYINT
  • home_lat, home_lng DECIMAL(9,6)
  • radius_km INT
  • status ENUM approval

1 to 1: users. 1 to many: delivery_assignments, driver_earnings.

delivery_assignments

  • id BIGINT
  • order_id UNIQUE
  • courier_id
  • status ENUM open/accepted/picked_up/delivered/failed/cancelled
  • payout_cents INT

1 to 1: orders. 1 to many: assignment_legs.

collection_otps

  • id BIGINT
  • order_id
  • kind ENUM (pickup, delivery)
  • code CHAR(6)
  • expires_at DATETIME
  • used_at DATETIME NULL

Two per order: one for pickup handover, one for delivery handover.

disputes

  • id BIGINT
  • order_id
  • opened_by users.id
  • reason TEXT
  • status ENUM open/closed
  • resolution ENUM

1 to many: dispute_evidence. Freezes escrow on open.

communities

  • id BIGINT
  • name, slug UNIQUE
  • suburb VARCHAR(80)
  • manager_id users.id
  • member_count, post_count

1 to many: community_members, community_posts.

community_posts

  • id BIGINT
  • community_id
  • author_id
  • listing_id NULL
  • body TEXT

1 to many: post_comments, post_reactions.

auctions and bids

  • id BIGINT
  • listing_id UNIQUE
  • start_cents, reserve_cents
  • current_bid_cents
  • ends_at DATETIME

1 to many: bids. AuctionCloseCron awards top bidder.

laybye_plans

  • id BIGINT
  • listing_id, buyer_id
  • total_cents, paid_cents
  • instalment_cents, weeks INT
  • status ENUM

1 to many: laybye_payments. Reserves the listing.

offers

  • id BIGINT
  • listing_id, buyer_id
  • amount_cents, swap_listing_id NULL
  • status ENUM
  • expires_at DATETIME

Many to one: listings. Accepted offer becomes an order.

wishlists

  • id BIGINT
  • user_id, listing_id
  • alert_below_cents INT NULL

Watch list with optional price drop alert.

reviews

  • id BIGINT
  • order_id, rater_id, ratee_id
  • stars TINYINT (1 to 5)
  • body TEXT

One per order per direction (buyer to seller, seller to buyer).

3. Context diagram (Level 0)

Me2You as a single process with all real external entities and the labelled data flows. The system at the centre is everything inside m2y.online.

Buyerbrowses, places orders, opens disputes
Sellerlists items, ships, gets paid
Driveraccepts jobs, picks up, delivers
orders, listings, locations, OTPs flow inward
Me2You marketplace auth, listings, cart, checkout, escrow, dispatch, payouts, community, feed, disputes
payments, ITN webhooks, waybills, email and SMS flow outward
Community managermoderates posts, approves members
Adminmoderates, resolves disputes, runs payouts
PayFastSA payment gateway, ITN webhook
Paxi, Pargo, PEPpickup point waybills and status
Titan SMTPtransactional email (orders, OTP, alerts)
WhatsApp shareoutbound share-link only, no API
Facebook Marketplace importseller-uploaded JSON, parsed locally
Pickup point (physical)shelf code matches OTP at counter

4. Data flow diagram (Level 1)

Real processes for v1.1, with their data stores. Sixteen processes total. Stores are keyed Dn so they cross-reference the schema.

Buyer
Seller
Driver
Admin
P1 Auth and RBACregister, login, session, terms
P2 Browse and searchfull-text MATCH, filters, suggest
P3 Manage listingscreate, edit, renew, expire
P4 Cartadd, update qty, save for later
P5 Checkout and paymentorder create, PayFast redirect, ITN
P6 Order managementdispatch, receive, complete
P7 Share and WhatsAppsigned share token, click track
P8 Admin panelmoderation, KPIs, payouts
P9 Social feedswipe video feed, ranking, watch time
P10 Communitiesjoin, post, comment, react
P11 Swaps, bids and lay-byeoffers, auctions, instalments
P12 Driver dispatchjob board by radius, accept, OTP
P13 Driver earnings and payoutsper-job ledger, weekly CSV run
P14 Escrow ledgerhold, release, refund, freeze
P15 Dispute resolutionopen, evidence, refund or release
P16 Listing importparse Facebook Marketplace export
D1 usersusers, password_resets, terms_acceptances
D2 cataloguelistings, listing_images, listing_media, categories
D3 salescarts, cart_items, orders, order_items
D4 moneyescrow_transactions, payment_log, refund_requests
D5 deliverycouriers, delivery_assignments, assignment_legs, collection_otps, pickup_shipments
D6 payoutsdriver_earnings, driver_payouts, tips
D7 socialcommunities, community_members, community_posts, post_comments, post_reactions, follows
D8 trustreviews, disputes, dispute_evidence, user_reports, user_blocks, user_verifications
D9 commerce extrasoffers, auctions, bids, laybye_plans, laybye_payments, wishlists, saved_searches, referrals
D10 opsnotifications, messages, audit_log, tracking_events, settings, experiments

5. Use case diagram

Five actors and the use cases each performs. "Include" calls are noted in italics; "extend" calls are noted with a plus sign.

Buyer

  1. Register and accept terms (includes Login)
  2. Browse categories
  3. Search with full-text and filters
  4. Watch the swipe video feed
  5. Open a listing
  6. Add to wishlist (with price drop alert)
  7. Add to cart
  8. Make an offer (counter price)
  9. Propose a swap (listing for listing)
  10. Place a bid on an auction
  11. Start a lay-bye plan
  12. Checkout (includes PayFast redirect)
  13. Pay deposit and instalments
  14. Track an order
  15. Receive an order (verifies delivery OTP)
  16. Self-collect at pickup point or seller (OTP)
  17. Leave a review
  18. Open a dispute + (extends Receive)
  19. Follow a seller
  20. Join a community and post
  21. Share a listing on WhatsApp
  22. Save a search

Seller

  1. Create a listing (images and optional video)
  2. Set price type (fixed, auction, accepts offers)
  3. Edit and renew a listing
  4. Import from a Facebook Marketplace export
  5. Respond to offers and swaps
  6. Approve a lay-bye plan
  7. Generate a share link
  8. Confirm dispatch (include OTP at pickup)
  9. Track payouts (escrow released after delivery plus 48h)
  10. Reply to reviews
  11. Set vacation mode
  12. Apply for driver capability

Driver

  1. Onboard (KYC tier, vehicle, home base)
  2. Go on duty (heartbeat ping)
  3. See available jobs by radius
  4. Accept a job
  5. Navigate to seller pickup
  6. Confirm pickup (OTP from seller)
  7. Navigate to buyer drop
  8. Confirm delivery (OTP from buyer)
  9. See earnings ledger
  10. Cash out (weekly payout run)
  11. Rate the buyer and the seller

Admin

  1. Moderate listings (live, hide, remove)
  2. Moderate community posts
  3. Approve driver applications
  4. Approve KYC tier upgrades
  5. Resolve disputes (refund, release, partial)
  6. Freeze and release escrow
  7. Run the weekly driver payout (CSV download)
  8. View KPIs (GMV, orders, escrow held)
  9. Audit log inspection
  10. Toggle experiment flags
  11. Manage settings (fees, holding period)
  12. Handle user reports and blocks
  13. Suspend or restore accounts

Community manager

  1. Create a community
  2. Set visibility (open or private)
  3. Approve member join requests
  4. Pin and remove posts
  5. Suspend a member from a community
  6. Set community guidelines

6. Database schema (62 tables)

The 62 physical tables in db/schema.sql, grouped by domain so the marker can navigate. The key columns of the most important tables are shown in full.

Domain 1: users and access

Identity, addresses, sessions, terms acceptance, password resets.

  • users
  • addresses
  • password_resets
  • terms_acceptances
  • user_verifications
  • user_reports
  • user_blocks
  • follows
  • settings
  • subscriptions

Domain 2: catalogue

Listings and their images, video media, categories, comments and reactions.

  • categories
  • listings
  • listing_images
  • listing_media
  • listing_comments
  • listing_reactions
  • listing_imports
  • properties
  • vehicles
  • geocode_cache

Domain 3: cart, orders and escrow

Carts, orders, line items, escrow ledger, refunds, payment audit.

  • carts
  • cart_items
  • cart_saved_items
  • orders
  • order_items
  • escrow_transactions
  • refund_requests
  • payment_log

Domain 4: delivery and drivers

Courier roster, on-duty pings, assignments, legs, OTPs at pickup and delivery, pickup-point shipments, earnings and payouts, GPS telemetry.

  • couriers
  • delivery_assignments
  • assignment_legs
  • collection_otps
  • pickup_shipments
  • driver_earnings
  • driver_payouts
  • tips
  • tracking_events
  • driver_pings

driver_pings GPS telemetry trail for delivery ETA learning.

Domain 5: disputes, trust and reviews

Reviews, disputes and their evidence, audit trail, cached trust scores.

  • reviews
  • disputes
  • dispute_evidence
  • audit_log
  • user_risk_scores

user_risk_scores Cached trust and risk score per user (feed, fee and escrow perks).

Domain 6: community and feed

Communities, members, posts, comments and reactions on posts.

  • communities
  • community_members
  • community_posts
  • post_comments
  • post_reactions

Domain 7: offers, auctions, lay-bye, wishlist

Counter-offers and swaps, auctions and bids, lay-bye plans and instalments, wishlists, saved searches, referrals.

  • offers
  • auctions
  • bids
  • laybye_plans
  • laybye_payments
  • wishlists
  • saved_searches
  • referrals

Domain 8: messaging and notifications

Direct messages, notifications, reports.

  • messages
  • notifications
  • reports

Domain 9: experimentation

Feature flag rollouts and event capture for A/B style toggles.

  • experiments
  • experiment_assignments
  • experiment_events

Key tables in full

users (key columns):

ColumnTypeNotes
idBIGINT PKauto increment
emailVARCHAR(190) UNIQUElowercased on insert
password_hashCHAR(60)bcrypt cost 12
display_nameVARCHAR(80)public
roleENUM('buyer','seller','driver','admin')defaults to 'buyer'
statusENUM('active','suspended','deleted')FK guarded
rating_avgDECIMAL(3,2)denorm cache
personaENUM('seller','collector','hobbyist','specialist','service')profile flair
created_atTIMESTAMPdefaults NOW

orders (key columns):

ColumnTypeNotes
idBIGINT PKauto increment
referenceCHAR(12) UNIQUEpublic reference, e.g. M2YAB12CD34
buyer_id / seller_idBIGINT FK users.idbuyer plus seller (single seller per order)
subtotal_centsINTsum of line items
delivery_centsINTflat per method
tip_centsINT0, 1000, 2000 or 5000
protection_centsINTbuyer protection fee from settings
total_centsINTserver-side recomputed at PayFast redirect
fulfillment_typeENUMdriver_door_to_door, pickup_network, self_collect_inspect, cash_on_delivery
statusENUMplaced, paid, dispatched, received, completed, cancelled, disputed
pf_payment_idVARCHAR(64)set by ITN handler

escrow_transactions (key columns):

ColumnTypeNotes
idBIGINT PK
order_idBIGINT UNIQUE FK orders.id1 to 1
amount_centsINTbuyer total, ex driver tip
statusENUM('held','released','refunded','frozen')state machine
release_due_atDATETIMEset 48h after delivered_at
released_atDATETIME NULLset by cron
payout_refVARCHAR(64) NULLAUTO-{order.reference} for cron releases

couriers (key columns):

ColumnTypeNotes
idBIGINT PK
user_idBIGINT UNIQUE FK users.id1 to 1 with user
on_dutyTINYINT(1)1 if heartbeat in last 5 min
home_lat / home_lngDECIMAL(9,6)radius centre
radius_kmINT10, 20 or 30
statusENUM('pending','approved','suspended')admin gated
vehicle_typeENUM('foot','bike','car','bakkie','van')

delivery_assignments (key columns):

ColumnTypeNotes
idBIGINT PK
order_idBIGINT UNIQUE FK1 to 1
courier_idBIGINT FK couriers.idnullable until accepted
statusENUM('open','accepted','picked_up','delivered','failed','cancelled')
payout_centsINTbase plus per km
accepted_at ... delivered_atDATETIMEtimestamps per leg

communities (key columns):

ColumnTypeNotes
idBIGINT PK
slugVARCHAR(80) UNIQUEe.g. soweto-thrift
nameVARCHAR(120)
suburbVARCHAR(80)denorm for search
manager_idBIGINT FK users.idcommunity manager
visibilityENUM('open','private')
member_count / post_countINTcached counts

auctions (key columns):

ColumnTypeNotes
idBIGINT PK
listing_idBIGINT UNIQUE FK
start_cents / reserve_centsINTmin and reserve
current_bid_centsINTcached top bid
top_bidder_idBIGINT FK users.id NULL
ends_atDATETIMEauction_close cron checks
statusENUM('live','closed','cancelled')

laybye_plans (key columns):

ColumnTypeNotes
idBIGINT PK
listing_idBIGINT FK
buyer_idBIGINT FK users.id
total_cents / paid_centsINTbalance is total minus paid
instalment_centsINTweekly
weeksINTtypical 4 to 12
statusENUM('pending','approved','active','completed','defaulted','cancelled')

offers (key columns):

ColumnTypeNotes
idBIGINT PK
listing_idBIGINT FK
buyer_idBIGINT FK users.id
amount_centsINTcounter price
swap_listing_idBIGINT FK listings.id NULLset for a swap proposal
statusENUM('pending','accepted','rejected','expired','withdrawn')
expires_atDATETIME48h default

7. Order status workflow

State transitions on the orders table. Each arrow names the trigger and the side effect (escrow, dispatch, payouts).

placedorder created, escrow row created with status=held
PayFast ITN verifies payment
paidescrow holds funds; dispatch job offered to drivers in radius
dispatchedseller or driver confirms pickup (OTP); ETA shown to buyer
delivery OTP verified at drop
receiveddelivered_at set; release_due_at set to now plus 48h
completed
cron releases escrow; seller paid; driver earning row created
cancelled
before paid: no charge. After paid: refund_requests row created
disputed
opens dispute; escrow status flips to 'frozen'; admin decides outcome

8. Schema decision notes