Two documents, one page: a plain-language overview for the commercial founder, and a build-ready technical blueprint for the solo technical founder. Both describe the same scope and the same 4-week path to the first paying pilot customer.
No schemas, no APIs, no infrastructure. Everything you need to pitch it, sell it, and talk a customer through it.
A web tool that turns Malaysia's CIPAA 2012 payment-dispute process into a guided countdown. A contractor or subcontractor owed money enters the date they served their Payment Claim; the tool computes every statutory deadline from there — when the other side must respond, when to register at AIAC, when to file the Adjudication Claim, when the adjudicator must decide — and generates the matching government form at each step, with a reminder before each clock runs out.
CIPAA gives any contractor a fast, cheap legal right to force a late payer to pay — faster and cheaper than court. But the right is entirely procedural: miss one of six hard deadlines and the right lapses, no matter how valid the underlying claim is. Most SMEs don't track this correctly on their own, and by the time they call a lawyer, a deadline has often already passed.
Sign up with an email link (no password to remember). First thing the customer sees is a prompt to enter their first claim. Enter the date the Payment Claim was served, who owes the money, and the amount — the tool immediately shows the full deadline timeline before they've paid anything, so they can see the value before committing.
Four weeks to a sellable product, assuming the technical founder works on this full-time and the CHIP payment merchant account is approved within that window (approval lead time is outside our control and unverified — flag this to any pilot customer conversation as a possible launch-date risk). See Document B's roadmap for the week-by-week breakdown.
PRD, architecture, diagrams, data model, API, UI spec, and a phased build plan — detailed enough to hand to an AI coding assistant.
| Problem | SMEs miss statutory CIPAA deadlines because nothing computes or tracks the full stage sequence for them. |
| Users | Claimant (contractor/subcontractor), Referral Partner (lawyer/QS firm, P1), Admin (founders) |
| Core loop | Enter claim → see computed deadlines → download form → mark stage complete → get reminded before the next one |
| Value prop | Never miss a CIPAA deadline — know exactly what to file, by when, with the form ready |
A single-user claim tracker: create a claim, get the full deadline sequence computed up front, see a countdown dashboard, download a pre-filled form for the current stage, get an email reminder, mark stages complete manually. No WhatsApp automation, no multi-client view, no in-app payment collection beyond a single subscription checkout. Enough to run the first five pilot customers and learn whether the computed dates match what their own lawyers tell them.
| Priority | Feature |
|---|---|
| P0 | Claim intake · deadline engine (6 CIPAA stages, MY public-holiday-aware) · countdown dashboard · AIAC form auto-fill for Payment Claim / Payment Response / Notice of Adjudication · email reminders (T-3, T-1, day-of) · one-tap WhatsApp (wa.me link) · self-serve subscription billing · magic-link auth · disclaimer + ToS |
| P1 | Referral-partner multi-client console · case notes / evidence attachments · true WhatsApp Business API automation · yearly public-holiday calendar auto-update · exportable case-timeline PDF |
| P2 | Direct AIAC e-filing integration (contingent on AIAC exposing one) · panel-lawyer marketplace/matching · Singapore SOPA expansion (same mechanic, different statute) · referral-partner analytics |
Deliberately excluded from P0: anything that isn't needed to prove a referred contractor will pay RM149–399 for a correct, tracked deadline. Multi-client and WhatsApp automation are real features a lawyer partner will ask for early — they're P1 because neither blocks the first sale.
graph TD
A[Contractor has an unpaid progress claim] --> B{How did they hear about it?}
B -->|Referred by lawyer or QS firm| C[Visit signup page]
B -->|Found via contractor association| C
C --> D[Sign up with magic link]
D --> E[Create first claim]
E --> F[Dashboard shows full CIPAA deadline timeline]
F --> G[Act stage by stage, reminded before each deadline]
G --> H{Outcome}
H -->|Payer settles before adjudication| I[Claim marked resolved - paid]
H -->|Goes to adjudication, decision delivered| J[Claim marked resolved - adjudicated]
H -->|A deadline is missed| K[Stage marked lapsed - shown as advice to consult a lawyer]
I --> L{Active claims remain?}
J --> L
K --> L
L -->|Yes| F
L -->|No| M[Renew monthly or cancel]
graph TD
A[Land on signup page] --> B[Enter email]
B --> C[Receive magic link by email]
C --> D[Click link, session created]
D --> E{First login?}
E -->|Yes| F[Prompt: add your first claim]
E -->|No| G[Go to dashboard]
F --> H[Enter counterparty, amount, claim-served date]
H --> I[System computes every stage deadline]
I --> J[Show full deadline timeline before saving]
J --> K[Confirm - claim saved, reminders scheduled]
K --> G
graph TD
A[Claim-served date entered] --> B[Compute Payment Response deadline: +10 working days]
B --> C{Response received in time?}
C -->|Admits and pays| D[Stage complete - claim resolved]
C -->|Disputes| E[User elects to refer to adjudication]
C -->|No response by deadline| F[Deemed disputed by law]
E --> G[Serve Notice of Adjudication]
F --> G
G --> H[Compute AIAC registration deadline: +7 days]
H --> I[Register claim at AIAC]
I --> J[Adjudicator accepts appointment]
J --> K[Compute Adjudication Claim deadline: +10 days from acceptance]
K --> L[Serve Adjudication Claim]
L --> M[Compute Adjudication Reply deadline: +5 days after Response]
M --> N[Compute decision deadline: +45 working days]
N --> O{Decision delivered on time?}
O -->|Yes| P[Binding decision - pending final resolution]
O -->|No| Q[Decision void by law - adjudicator forfeits fees]
B -.missed.-> X[Stage marked lapsed]
H -.missed.-> X
K -.missed.-> X
M -.missed.-> X
graph TD
subgraph Claimant
A1[View own claims]
A2[Create and edit own claims]
A3[Download own forms]
end
subgraph "Referral Partner (P1)"
B1[View referred clients' claims - read only]
B2[Generate a referral link for a new client]
end
subgraph Admin
C1[View all claims]
C2[Process billing and refunds]
C3[Inspect deadline-calculation audit log]
end
graph TD
A[User selects a plan: Starter RM149/mo or Per-case RM399] --> B[Redirect to CHIP checkout]
B --> C{Payment successful?}
C -->|Yes| D[CHIP webhook confirms payment]
D --> E[Account activated / case unlocked]
E --> F[Monthly auto-renewal via CHIP]
F --> G{Renewal successful?}
G -->|Yes| F
G -->|No| H[7-day grace period]
H --> I{Paid within grace period?}
I -->|Yes| F
I -->|No| J[Account downgraded to read-only]
C -->|No or abandoned| K[Return to pricing page]
graph TD
A[Support request or dispute flagged] --> B[Admin opens case in admin console]
B --> C[Review claim timeline and deadline audit log]
C --> D{Issue type}
D -->|Billing dispute| E[Process refund via CHIP dashboard]
D -->|Deadline looks wrong| F[Re-run engine against the claim's stored inputs]
D -->|Bug report| G[Log issue, patch, notify affected users]
E --> H[Resolve and close]
F --> H
G --> H
Modular monolith, managed infrastructure throughout, chosen to fit a solo developer at near-zero cost: every piece below runs on a free tier at pilot scale, with a named upgrade trigger for when that stops being true.
| Layer | Choice | Why |
|---|---|---|
| Frontend | Server-rendered pages via the Worker (Hono + JSX), no separate SPA build | One deploy, one repo; no client/server state-sync bugs for a solo maintainer to own |
| Backend | Cloudflare Workers, Hono framework, TypeScript | Same runtime as the frontend; the deadline engine is a pure, unit-testable function |
| Database | Cloudflare D1 (SQLite), free tier | Built-in point-in-time restore covers backups with zero extra setup |
| Auth | Email magic link via Resend; signed session cookie | No password reset flow to build or support |
| Authorization | Row-level ownership check in every query (`WHERE user_id = ?`) | Single-tenant-per-user model; no RLS engine needed at this scale |
| Background jobs | Workers Cron Trigger, once daily | Scans upcoming deadlines, enqueues reminder emails — no separate queue service needed at pilot volume |
| Resend, free tier (3,000/mo) | Upgrade trigger: >3,000 reminder emails/month | |
| Payments | CHIP, RM1 flat FPX, no setup fee | Pay-per-transaction only; no Stripe-style monthly platform fee |
| Hosting | Cloudflare Pages + Workers, free tier | Upgrade trigger: realistically never at this product's volume |
| Security | HTTPS by default, parameterized D1 queries, Cloudflare rate-limiting on auth routes, HMAC-verified payment webhook | No custom infrastructure to secure beyond the Worker code itself |
| Monitoring | A simple `error_log` D1 table written from a top-level try/catch, checked manually | A dedicated observability tool is overkill before there are paying customers to monitor for |
graph LR Browser[Browser / mobile web] -->|HTTPS| Worker[Cloudflare Worker - Hono app + API + Cron] Worker -->|SQL queries| D1[(Cloudflare D1)] Worker -->|send reminder| Resend[Resend - email API] Worker -->|create checkout session| CHIP[CHIP - payment gateway] CHIP -->|webhook: payment confirmed| Worker Worker -->|renders| Forms[Bundled AIAC form templates] Cron[Workers Cron Trigger - daily] --> Worker
erDiagram
USERS ||--o{ CLAIMS : owns
USERS ||--o| SUBSCRIPTIONS : has
CLAIMS ||--|{ CLAIM_STAGES : contains
CLAIM_STAGES ||--o{ REMINDERS : triggers
REFERRAL_PARTNERS ||--o{ REFERRAL_LINKS : refers
USERS ||--o| REFERRAL_LINKS : "referred via (P1)"
USERS {
int id PK
string email UK
string name
string phone
string auth_provider
datetime created_at
}
SUBSCRIPTIONS {
int id PK
int user_id FK
string plan
string status
string chip_customer_id
date current_period_end
}
CLAIMS {
int id PK
int user_id FK
string counterparty_name
string contract_name
date claim_served_date
decimal claim_amount
string status
datetime created_at
}
CLAIM_STAGES {
int id PK
int claim_id FK
string stage_key
date deadline_date
datetime completed_at
string status
datetime form_generated_at
}
REMINDERS {
int id PK
int claim_stage_id FK
string channel
datetime scheduled_for
datetime sent_at
}
REFERRAL_PARTNERS {
int id PK
string name
string firm_name
string referral_code UK
}
REFERRAL_LINKS {
int id PK
int referral_partner_id FK
int user_id FK
datetime created_at
}
No multi-tenancy layer: each user owns their own claims directly. The referral-partner tables are an attribution join, not a tenant boundary — a partner never writes to a client's claim, only reads it.
| Endpoint | Auth | Request | Response |
|---|---|---|---|
| POST /api/auth/magic-link | None | { email } | 204, email sent |
| GET /api/auth/callback | Signed token in URL | — | Sets session cookie, redirects to dashboard |
| GET /api/claims | Session, owner-scoped | — | [{ id, counterparty_name, status, next_deadline }] |
| POST /api/claims | Session | { counterparty_name, contract_name, claim_amount, claim_served_date } | Created claim + computed claim_stages array |
| GET /api/claims/:id | Session, owner-scoped | — | Claim + all stages with current status |
| PATCH /api/claims/:id | Session, owner-scoped | { status } | Updated claim |
| POST /api/claims/:id/stages/:stageKey/complete | Session, owner-scoped | — | Updated stage, status → completed |
| GET /api/claims/:id/stages/:stageKey/form | Session, owner-scoped | — | Pre-filled form document (PDF) |
| POST /api/billing/checkout | Session | { plan } | { checkout_url } |
| POST /api/billing/webhook | HMAC signature from CHIP, no session | CHIP payment event | 200, updates subscriptions |
| GET /api/me | Session | — | Current user + subscription status |
Every /api/claims/* route checks claims.user_id = session.user_id before returning or mutating anything — the only authorization rule the MSP needs.
| Screen | Purpose |
|---|---|
| Marketing / landing page | Outside the app; explains the product, links to signup |
| Sign in / sign up | Email entry → magic link |
| Dashboard | List of claims, soonest deadline first |
| New claim | Counterparty, amount, claim-served date → live deadline preview before saving |
| Claim detail | Full stage timeline, countdown per stage, form download, mark-complete action |
| Billing | Plan picker, CHIP checkout, current plan status |
| Account settings | Name, email, phone (used to pre-fill the WhatsApp reminder text) |
| Referral partner console (P1) | Read-only list of referred clients' claims |
Flat, not hierarchical: Dashboard, Billing, and Settings are the only top-level destinations. Claim detail is reached only from the dashboard list, never bookmarked as a separate navigation item — there's no need for deeper nesting at this scope.
Mobile-first: a contractor checking a deadline is more likely to be on a phone on a job site than at a desk. The dashboard list collapses to stacked cards under 640px; the claim-detail timeline becomes a single column; "mark complete" and "download form" are large tap targets, not small inline links.
Clean legal-utility minimal: generous whitespace, one accent color reserved for primary actions, status communicated through both color and a text label (never color alone), dates and countdowns set in a monospace face so they align and read as data, not prose.
| Phase | Objective | Deliverable | Completion criteria |
|---|---|---|---|
| Week 1 | Deadline engine | A pure, unit-tested function: claim-served date → all six stage deadlines, Malaysia-public-holiday-aware | Matches 3 hand-calculated real-world CIPAA examples exactly |
| Week 2 | Claim CRUD + dashboard | Sign up, create a claim, see the computed timeline on a dashboard | A test user can go from signup to a populated dashboard unaided |
| Week 3 | Forms + reminders | Auto-filled Payment Claim / Payment Response / Notice of Adjudication forms; daily cron sends email reminders | The full P0 loop works end to end for one real pilot claim |
| Week 4 | Billing + polish | CHIP checkout and webhook, WhatsApp tap-link, disclaimer/ToS, mobile pass | A stranger can self-serve sign up and pay without founder help |
| Week 5+ | Post-launch, driven by real feedback | Likely candidates: referral-partner console, remaining AIAC forms | Decided from what the first 5 paying customers actually ask for — not pre-committed |
Dependency to flag: Week 3's form auto-fill needs accurate AIAC form templates sourced in parallel during weeks 1–2 — a research task, not an engineering one, so either founder can own it without blocking the build. Week 4's billing go-live depends on CHIP merchant account approval, whose lead time is unverified — don't promise a launch date to a pilot customer until that approval is confirmed.
This assumes one developer working full-time with AI-assisted development; a part-time pace would roughly double every phase above.
| Stage | Technical founder | Commercial founder |
|---|---|---|
| Discovery | Confirm Malaysia public-holiday data source against AIAC's own guidance | Get 2–3 lawyer/QS firms to agree, in conversation, that a tracking tool is useful rather than competing with their own billable time |
| Planning | Lock the MSP scope above — no additions without cutting something else | Informally test which pricing a referral partner's client would actually pick: RM149/mo or RM399/case |
| Development | Build weeks 1–4 | Line up 3–5 pilot contractors through the referral partners; get a referral lawyer to eyeball the disclaimer wording informally |
| Testing | Fix deadline-calculation edge cases (a holiday landing exactly on a deadline is the one that matters most) | Get pilots to enter a real claim and compare the computed dates against what their own lawyer told them |
| Launch | Deploy, and watch the cron job specifically — a missed reminder is a real liability, not just a bug | Onboard the first paying customers; start the conversation with a second and third referral partner |