The platform underneath the pitch.
Operations decisions live on the server. Tenancy is enforced on every route and query. Rules are deterministic. Audit is immutable. This page is the spec.
Built for mall operations. Not for a slide.
The questions a coupon platform has to answer before it ships into a vendor location. POS surface, dropped connectivity, double-scans, refunds, onboarding, validation.
POS-agnostic capture
Redemptions capture on any browser. A store operator opens the redeem console on their phone or a POS-attached tablet and scans the coupon. No deep POS integration required to start. Tighter integrations roll out in Phase 2 against signed merchant commitments.
Offline-tolerant scanning
Codes stay scannable when connectivity drops. The capture queues locally and certifies once the connection returns. No redemptions lost between the till and the cloud.
Idempotent against double-scans
Every redemption write claims a transactional lock keyed by the redemption code. A double-scan returns the original capture, not a second fee. The rules engine emits { allowed, reasonCode, message } so disputes have a paper trail.
Returns and voids, handled honestly
Phase 1 captures certified records. Refunds reconcile at invoice review by Finance. Phase 2 adds an explicit void workflow with audit-tracked reversal. We do not silently rewrite history.
Onboarded by invitation
Every user joins via a signed invitation token. Vendor admins are scoped to their brand at creation. Property admins to their mall. Excellerate Super Admins to the platform. No accidental cross-tenant exposure ever.
Server-side rules engine
Time window, redemption cap, eligibility segment, vendor-location match. All run server-side on every scan against a deterministic rules engine. The UI never decides anything that touches money.
Nine levels. Every redemption traces up the tree.
Permissions enforce at every level, server-side, on every route and query. A vendor admin cannot see a competitor. A property admin cannot reach into another mall.
- 01Platform
Coupex software, RBAC, audit, finance rules.
- 02ClientAccount
Excellerate, with configurable currency and timezone.
- 03PropertyGroup
Portfolio cluster across regions or formats.
- 04Property
Single mall, scoped to its admins and operators.
- 05VendorLocation
Vendor brand at a specific property store.
- 06Campaign
Approved window of activity with rules and segments.
- 07Coupon
Discount design with limits, eligibility, and artwork.
- 08CouponInstance
Unique issued code, QR, or barcode for one shopper.
- 09Redemption
Captured event with fee, certified by finance.
Decisions on the server. Records that hold up.
RBAC enforces on every route and query. Validation, fee calc, and approval state never run in the UI. Idempotent redemption writes prevent double-counting under race conditions.
ZAR with space separators
Money formats as R1 000 with a non-breaking space, matching SA convention across the dashboard and the invoice draft.
Africa/Johannesburg timestamps
Every redemption captures in SAST. Reports default to SAST. No timezone guesswork when a dispute lands.
POPIA-aware customer data
Consent state and source persist on every customer record. Reading a customer detail row writes a customer_detail_viewed entry to the audit log.
Decimal money, never floats
Money stored as Decimal(14, 2), percentages as Decimal(7, 4). Resolved fee rule IDs and resolved percentages persist on every fee calculation.
Demo data is labelled
Seeded data is clearly demo data. No mock figures get presented as production activity. Imports surface failure CSVs rather than failing silently.
Audit across every write
Approvals, redemption certifications, invoice generation, customer access, sign-in events. Every write is captured with actor, action, and timestamp.
A short tour of the request path.
Browser to proxy to auth to services to rules to Prisma to Postgres. Every step adds checks. Every material write spawns an audit row in the same transaction.
Request flow
- 01
Browser
Next.js client components. No business logic. Forms, navigation, presentation.
- 02
Proxy + Auth.js
Edge-runtime proxy gates /app routes. Invitation-only sign-in. RBAC carried on every request.
- 03
Service layer
Server actions and services. RBAC checks first. DTOs serialise Decimal as ZAR strings.
- 04
Rules engine
Pure functions. Resolves fee precedence, validates redemptions, evaluates approval gates.
- 05
Prisma + Postgres
Migrations, transactional writes, idempotent redemption locks, Decimal money.
- 06
Audit log
Every material write captures actor, action, entity, timestamp. Immutable.
Side-channel writes
Every approval, redemption certification, invoice draft, customer detail read, sign-in event, and permission denial branches off the main flow into the audit log table. The write commits in the same transaction as the action it records. No silent failures, no orphan events.
The same pattern carries fee calculations. The resolved fee rule and resolved percentages persist with every Redemption row, so historical fees stay correct even when the rule table changes.
customer_detail_viewed
POPIA-tracked read
redemption_certified
Finance action
campaign_approved
Approval action
permission_denied
Cross-tenant attempt blocked
Customer data is treated as the operator's responsibility.
Consent persisted. Detail reads logged. Audit immutable. The platform makes it harder, not easier, to lose track of who saw what.
Consent persisted on every customer record
Every Customer row tracks consentStatus and source. Updates to either field are themselves audited.
Customer detail reads are logged
Any operator opening a customer detail page emits a customer_detail_viewed entry. The actor, target customer, and timestamp persist. This is POPIA compliance, not an analytics nicety.
Audit immutability is structural
AuditLog rows never update. They only append. Approvals, redemption certifications, invoice generation, sign-in events, and permission denials all flow through the same table.
Run it for yourself.
Seeded properties, vendors, campaigns, certified redemptions, AI recommendations, audit log entries. Everything wired to the same RBAC the production rollout will carry.