Mota — Requirements Specification
SDLC phase: Analysis (Chapter 3.7)
Purpose: Define exactly what gets built, in a form that can be traced to tests and scope decisions. Every FR has an ID and an acceptance criterion. Anything not listed here is out of scope by default.
Priority scale (MoSCoW):
- M — Must. v1 cannot ship without it.
- S — Should. v1.1 if time allows; otherwise v1.2.
- C — Could. Backlog.
- W — Won't (this release). Explicitly excluded, with a reason.
1. Personas
P1 — Tino, the owner-operator (primary consumer)
- 34, drives a 2014 Honda Fit (used Japanese import) in Harare
- Bought it 2 years ago, no service history came with it
- Uses WhatsApp constantly, EcoCash daily, data on a bundle
- Has a mechanic he vaguely trusts but no way to verify anything
- Goal: don't get ripped off, don't get stranded, sell the car for a fair price later
- Fear: the gearbox failing and costing more than the car is worth
- Behaviour: will not spend 5 minutes on a form. Will abandon anything that asks for too much.
P2 — Chido, the careful planner (secondary consumer)
- 41, drives a 2019 Toyota Fortuner, has a service plan at a dealership
- Tracks expenses in a spreadsheet already
- Goal: cost-per-km visibility and a clean resale record
- Behaviour: will fill in detail if the output is worth it. Good source of referrals, small segment.
P3 — Farai, the garage owner (primary payer)
- 38, runs a 3-bay workshop in Msasa, 4 employees, single owner
- Books are a hardcover exercise book plus WhatsApp
- Cannot tell you which customer is due back
- Wants more repeat customers, hates "lead generation" platforms that send tyre-kickers
- Goal: predict his own workload and keep good customers
- Behaviour: mobile-first, low patience, will pay only after seeing a booking come through
P4 — Priya, the parts shop owner (secondary payer)
- 45, runs a spares shop, stocks NS-3 CVT fluid, brake pads, filters
- Wants buyers who already know what they need
- Goal: qualified demand with correct fitment
- Behaviour: will pay for placement if it produces sales
2. Functional requirements
Module: VEH — Vehicle & profile management
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-VEH-01 |
User can register with phone number via OTP |
M |
A new user completes OTP and reaches the home screen in <60s on a 3G connection |
| FR-VEH-02 |
User can add a vehicle with make, model, year, current odometer, registration |
M |
Vehicle appears on home screen immediately; make/model/year selectable from a seeded list of the top 40 Zim models with free-text fallback |
| FR-VEH-03 |
User can add multiple vehicles |
S |
Second vehicle can be added and switched between without re-auth |
| FR-VEH-04 |
User can edit vehicle details; edits are timestamped |
M |
Odometer edit is recorded in the vehicle history so interval calculations remain traceable |
| FR-VEH-05 |
User can archive a vehicle (sold) without deleting its history |
S |
Archived vehicle is hidden from home but its service log and PDF remain accessible |
| FR-VEH-06 |
Odometer can be updated independently of a service event |
M |
Update is reflected in the next service-due calculation within the same session |
Module: REC — Records (service, fuel, expense)
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-REC-01 |
User can log a service event in <30 seconds |
M |
Timed usability test: 8/10 first-time users complete in <30s without instruction |
| FR-REC-02 |
Service event captures: date, odometer, service type, cost (USD), garage (optional), notes (optional) |
M |
All fields persist; only date and type are mandatory |
| FR-REC-03 |
User can log a fuel fill-up with litres and odometer |
M |
Fill-up appears in the timeline and feeds the km/l calculation |
| FR-REC-04 |
System calculates and displays km/l and cost per km |
M |
Calculation is correct to 1 decimal across ≥3 consecutive fill-ups; shows "insufficient data" below 2 fill-ups |
| FR-REC-05 |
User can log a free-form expense (tyres, battery, repairs) |
S |
Expense appears in the timeline and in cost-totals |
| FR-REC-06 |
Records are editable and soft-deletable with undo |
M |
Deleted record is recoverable for 30 days; measure is removed from totals immediately |
| FR-REC-07 |
All write operations succeed offline and sync when connectivity returns |
M |
Airplane-mode test: log 3 events, return to signal, all 3 appear server-side exactly once |
| FR-REC-08 |
User can attach a photo of a receipt or part to a record |
C |
Photo stored; visible in the record detail |
| FR-REC-09 |
System flags statistically abnormal fuel consumption |
C |
Consumption >25% above the user's trailing 3-fill average triggers an advisory |
Module: DUE — Deadline & reminder engine
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-DUE-01 |
System computes next service due from model reference data + current odometer |
M |
For a seeded model, computed interval matches the reference table exactly |
| FR-DUE-02 |
System tracks ZINARA licence and insurance expiry as user-entered dates |
M |
Both appear on the home dashboard with days remaining |
| FR-DUE-03 |
System computes "due soon" and "overdue" states |
M |
Thresholds: due-soon at 500km or 30 days; overdue at 0km or 0 days past |
| FR-DUE-04 |
User can override any computed interval |
M |
Override is persisted with a note and takes precedence over reference data |
| FR-DUE-05 |
System sends escalating reminders: 30 days, 14 days, 7 days, 1 day, overdue |
M |
Each stage fires exactly once per deadline occurrence |
| FR-DUE-06 |
System displays why a service is due ("CVT fluid: 78,400km / due at 80,000km") |
M |
Reasoning string is present on every due item — never a bare "service due" |
| FR-DUE-07 |
User can mark a reminder as "not now" and reschedule it |
S |
Rescheduled reminder fires at the new date only |
| FR-DUE-08 |
System prompts for an odometer update if the last reading is >30 days old |
S |
Prompt appears at most once per week |
| FR-DUE-09 |
Reminders delivered via push, with WhatsApp deep-link fallback |
M |
If push permission is denied, the user can still action the reminder from an in-app inbox |
Module: HIS — Service history & export
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-HIS-01 |
User can view a chronological service timeline per vehicle |
M |
All records render in reverse-chronological order with no missing entries |
| FR-HIS-02 |
User can export a PDF service history |
M |
PDF contains vehicle identity, all service events with date/odometer/cost, and totals; generated in <5s offline |
| FR-HIS-03 |
User can share the PDF via WhatsApp and other native share targets |
M |
Native share sheet opens with the PDF attached |
| FR-HIS-04 |
PDF includes a verification QR code |
S |
QR resolves to a read-only page confirming the record exists and its created date |
| FR-HIS-05 |
User can see aggregate cost of ownership |
S |
Total spend, spend per km, and spend by category for a selectable period |
Module: GAR — Garage directory & lead handoff
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-GAR-01 |
User can browse garages with location, services offered, and contact |
M |
Directory loads <3s on 3G; ≥8 garages seeded at launch |
| FR-GAR-02 |
User can filter garages by service type ("CVT specialists") |
M |
Filter returns only garages configured for that service |
| FR-GAR-03 |
From a due reminder, user can request a booking from 1–3 garages |
M |
Request creates a lead record with the vehicle and required service attached |
| FR-GAR-04 |
Garage receives the lead in the console and via WhatsApp |
M |
Lead appears in console within 60s; WhatsApp notification contains vehicle, service, and contact |
| FR-GAR-05 |
User can call or WhatsApp a garage directly from the listing |
M |
Deep link opens the dialler or WhatsApp with the correct number |
| FR-GAR-06 |
Garage can mark a lead as booked / lost / no-response |
M |
Status change is timestamped and attributed to that garage |
| FR-GAR-07 |
Garages cannot see a user's phone number until the user requests contact |
M |
Directory listing exposes no contact detail for the owner; PII is released only on explicit booking request |
| FR-GAR-08 |
Garage listings carry a visible trust tier: listed (added from public info), claimed (has an account), reviewed (documents verified), suspended |
M |
Tier renders on every listing card and detail screen. Adopted from ZWPRICE's model — a binary verified flag loses the distinction that matters most to a consumer |
| FR-GAR-09 |
A "we are not the seller" disclaimer is shown before a booking is confirmed |
M |
Rendered in-flow, not only in terms. Mota does not guarantee workmanship, price, or availability |
| FR-GAR-10 |
A lead request requires phone verification (OTP) before it is sent |
M |
Prevents spam leads, which is the fastest way to lose garage trust |
Module: PRI — Parts & labour price index
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-PRI-01 |
Partner garages can submit prices for parts and labour by category |
M |
Submission form completes on a phone in <60s per item |
| FR-PRI-02 |
User can search a part/service and see partner prices with date |
M |
Every price displays its as_of date; no price ever appears undated |
| FR-PRI-03 |
Prices older than 90 days are visibly flagged as stale |
M |
Stale badge present; stale prices sort below fresh ones |
| FR-PRI-04 |
User can see a range (min/median/max) for a part category |
S |
Range computed from ≥3 current submissions; otherwise hidden |
| FR-PRI-05 |
User can submit a price they were quoted (crowdsourced) |
C |
Submission appears as unverified and is visually distinct from partner prices |
| FR-PRI-06 |
Sponsored parts shop placement is distinguishable from organic listings |
M |
Sponsored entries carry a visible "Sponsored" label — no dark patterns |
Module: GRG — Garage console (web + mobile web)
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-GRG-01 |
Garage can register and manage its listing |
M |
Listing goes live after verification; ≤10 min to complete |
| FR-GRG-02 |
Garage can see leads assigned to it |
M |
Lead list sorts by recency; unread leads highlighted |
| FR-GRG-03 |
Garage can see which of its recorded customers are due for a service |
S |
Requires the owner to have shared a vehicle with the garage; otherwise shows "no data" explicitly |
| FR-GRG-04 |
Garage can see the price index for its own categories |
S |
Garage sees how its prices compare to the median |
| FR-GRG-05 |
Garage can view and settle its invoice |
M |
Invoice shows leads, subscription, total; "pay via Paynow" and "record cash payment" both available |
| FR-GRG-06 |
Garage subscription auto-renews monthly with email/WhatsApp notice |
S |
Renewal notice sent 3 days prior; failure to renew downgrades, does not delete data |
Module: ADM — Admin
| ID |
Requirement |
Priority |
Acceptance criterion |
| FR-ADM-01 |
Admin can verify, suspend, and edit garage listings |
M |
Verification state change takes effect immediately in the consumer app |
| FR-ADM-02 |
Admin can view lead attribution and billing status per garage |
M |
Report reconciles against Paynow settlement |
| FR-ADM-03 |
Admin can seed and edit the vehicle reference table |
M |
Editing a model's interval recalculates upcoming dues for affected vehicles |
| FR-ADM-04 |
Admin can respond to a data-subject access or deletion request |
M |
Deletion removes PII from primary storage and records the action in an audit log |
3. Non-functional requirements
Measurable, with a target and a test method. Vague NFRs are unenforceable.
| ID |
Requirement |
Target |
Test method |
| NFR-PERF-01 |
Cold app start |
<3s on a US$80 Android over 3G |
Measured on a reference device |
| NFR-PERF-02 |
Log a service event (form open → saved) |
<30s end-to-end, ≤4 taps to save |
Timed usability test |
| NFR-PERF-03 |
Home dashboard render |
<1.5s from cache, <3s from network |
Reference device, cold cache |
| NFR-PERF-04 |
Initial JS bundle |
<200KB gzipped |
Build report |
| NFR-PERF-05 |
Data per typical session |
<500KB |
Network inspector |
| NFR-PERF-06 |
PDF generation |
<5s for 50 records, works offline |
Device test |
| NFR-PERF-07 |
Garage console lead visibility |
<60s from user request |
Timed end-to-end test |
Reliability & offline
| ID |
Requirement |
Target |
| NFR-REL-01 |
Offline write durability |
100% of writes persisted locally and eventually synced exactly once |
| NFR-REL-02 |
Sync conflict resolution |
Last-write-wins per field with an audit trail; no silent data loss |
| NFR-REL-03 |
Availability (backend) |
99.5% monthly — accepted trade-off for managed Supabase |
| NFR-REL-04 |
Reminder delivery |
≥95% of scheduled reminders delivered within 1 hour of schedule |
| NFR-REL-05 |
Data durability |
Daily automated backups, 7-day retention |
Security & privacy
| ID |
Requirement |
Target |
| NFR-SEC-01 |
All data in transit over TLS 1.2+ |
Enforced; no plaintext fallback |
| NFR-SEC-02 |
Row-level isolation between users |
RLS policy on every table; a user cannot read another user's vehicle by ID |
| NFR-SEC-03 |
Row-level isolation between garages |
A garage cannot read another garage's leads or prices |
| NFR-SEC-04 |
Owner phone number not exposed to garages without explicit booking request |
Enforced at the API layer, not the UI |
| NFR-SEC-05 |
Payment credentials never stored |
Paynow handles all payment data; we store only transaction references |
| NFR-SEC-06 |
Data subject deletion completed within 30 days |
Documented and auditable |
| NFR-SEC-07 |
CDPA compliance: POTRAZ data controller registration |
Completed before public launch |
| NFR-SEC-08 |
Cross-border transfer basis documented |
Before public launch — see open question Q3 |
Usability & accessibility
| ID |
Requirement |
Target |
| NFR-USE-01 |
Core logging journey requires no reading of instructions |
8/10 first-time users succeed unaided |
| NFR-USE-02 |
All interactive elements ≥44×44dp |
Design review |
| NFR-USE-03 |
Works at 100% font scaling; no clipped text |
Test on system font-size large |
| NFR-USE-04 |
Colour contrast ≥4.5:1 for text |
Automated audit |
| NFR-USE-05 |
App usable one-handed |
All primary actions in the lower 60% of the screen |
Compatibility
| ID |
Requirement |
Target |
| NFR-COMP-01 |
Android version support |
Android 8.0 (API 26) and above |
| NFR-COMP-02 |
Reference low-end device |
2GB RAM, Android 10, 720×1600 — all NFRs met on this device |
| NFR-COMP-03 |
Garage console browser support |
Chrome for Android (primary), Chrome desktop |
| NFR-COMP-04 |
Offline cold start |
App opens and shows the last-known dashboard with no network |
Maintainability
| ID |
Requirement |
Target |
| NFR-MAINT-01 |
Single-deploy backend |
No microservices in v1 |
| NFR-MAINT-02 |
Automated test coverage |
≥70% on business logic (interval calculation, sync, billing) |
| NFR-MAINT-03 |
Database migrations are versioned and reversible |
Every migration has a down path |
| NFR-MAINT-04 |
Time to restore from backup |
<4 hours (RTO) |
| NFR-MAINT-05 |
Max tolerable data loss |
24 hours (RPO) |
4. Traceability matrix (objectives → requirements)
| Objective |
Requirements that serve it |
| O1 — 300 activated users |
FR-VEH-01/02, FR-REC-01, NFR-PERF-01/02, NFR-USE-01 |
| O2 — 25% 30-day retention |
FR-DUE-05/06, FR-HIS-01, FR-REC-04 |
| O3 — 40% reminder acknowledgment |
FR-DUE-05/06/09, NFR-REL-04 |
| O4 — 8 partner garages with bookings |
FR-GAR-01–06, FR-GRG-01/02, FR-ADM-01 |
| O5 — 5 paying garages |
FR-GRG-05/06, FR-ADM-02, NFR-SEC-05 |
| O6 — US$300 MRR |
FR-GRG-05, FR-PRI-01, FR-PRI-06 |
| O7 — Price index usage |
FR-PRI-01–04, FR-VEH-02 (model for fitment) |
| O8 — 5,000 records |
FR-REC-01/02/03, NFR-REL-01/02 |
5. Assumptions embedded in requirements
| ID |
Assumption |
Impact if wrong |
| RA-1 |
Users will provide an accurate odometer |
FR-DUE-01 silently produces wrong reminders → trust collapse. Mitigated by FR-DUE-06 (show reasoning) and FR-DUE-08 (staleness prompt) |
| RA-2 |
Users will log fill-ups consistently enough for km/l to be meaningful |
FR-REC-04 degrades gracefully to "insufficient data" — no false precision |
| RA-3 |
Garages can be persuaded to submit prices |
FR-PRI-01 becomes dead weight; price index drops from v1 to v2 |
| RA-4 |
Phone OTP is reliable on Zim operators |
FR-VEH-01 is the front door; if OTP fails, nothing works. Must be tested in Gate 0. |
| RA-5 |
Users will share their vehicle record with a garage |
FR-GRG-03 degrades to empty state; garage console loses its predictive value |
6. Out of scope for v1 — with reasons
Explicit exclusion is a requirement. Each item below was considered and rejected, not forgotten.
| Item |
Reason for exclusion |
Revisit when |
| iOS app |
Low share in the target demographic; doubles build and review cost |
2,000 Android users |
| OBD-II hardware integration |
Requires hardware, capital, and support burden |
Never in v1; consider partnership |
| Real-time GPS tracking |
Different product, different buyer (fleet), hardware dependency |
Only with a fleet customer signed |
| Consumer in-app payments |
Consumers won't pay; adds friction to the funnel |
Not planned |
| Marketplace checkout for parts |
Logistics, working capital, returns |
With a parts partner, year 2+ |
| Insurance quote comparison |
Regulatory complexity, commission agreements |
Year 2+, requires insurer partnership |
| Mechanic job cards / workshop management |
Different product for a different buyer; scope explosion |
Only if garages demand it and pay for it |
| Fleet management |
Long sales cycle, different requirements |
After consumer product is proven |
| AI/ML service prediction |
Deterministic intervals are more accurate and explainable at this stage |
5,000+ vehicles with history |
| Social feed / community |
Engines of vanity; no path to revenue; support burden |
Not planned |
| Vehicle valuation |
Needs transaction data we don't have |
Year 3+ |
| USSD interface |
Real need, but a second product surface |
If a garage-only or feature-phone segment proves material |
| Multi-language (Shona/Ndebele) |
v1 English is acceptable for the target segment |
After 2,000 users, based on demand |
| Referral / loyalty programme |
Premature; no retention to reward yet |
After retention is proven |