Product & Technical Blueprint · Idea #5 of the MY opportunity scan

Small 3PL Multi-Client Billing & Inventory

A warehouse operator running storage for 1–15 clients tracks whose stock is whose, and bills each client for space and handling, by hand. This blueprint turns that gap into a buildable product for a one-developer team and a sellable product for a non-technical commercial founder.

Buyer: SME contract warehouse operator
Pricing: RM2,500 setup + RM349/mo ≤5 clients
MVP: 9–11 weeks (assumption, see §9)
Document A — Business & Product Overview, for the commercial founder
A·1

What we're selling, and to whom

What it is: a web app for a small contract warehouse that stores goods for several client businesses. It keeps every client's stock separately counted, lets warehouse staff log stock coming in and going out from a phone, and automatically prints each client a correct monthly bill for storage and handling — with Malaysian SST already applied correctly.

Who should buy it: the owner or operations manager of a small contract warehouse or logistics-park unit storing goods for 1–15 separate client businesses. Today they likely track this in spreadsheets, one tab per client, and calculate each client's bill by hand at month-end.

The problem it solves

Main selling points

How this is different from a generic inventory management system

A plain inventory management system answers one question for one business: how much stock do I have, and where is it? This product answers a different question, because the warehouse operator is storing goods on behalf of other businesses, not their own:

In short: a normal inventory system answers "how much stock do I have." This answers "whose stock is this, and what do I bill them for storing it" — which is why small-3PL billing software (PackemWMS, Fulfillor, GOIS) is already its own category, separate from plain inventory software, and why none of it is localized for Malaysia.

A·1bm

Ringkasan dalam Bahasa Malaysia

Bahagian ini meringkaskan produk dan perbezaannya dengan sistem pengurusan inventori biasa, untuk digunakan semasa pitching kepada pelanggan atau rakan kongsi yang lebih selesa dalam Bahasa Malaysia.

Apa yang kita jual, dan kepada siapa

Apa dia: aplikasi web untuk gudang kontrak kecil yang menyimpan barang bagi beberapa syarikat pelanggan. Sistem ini mengasingkan stok setiap pelanggan secara automatik, membolehkan kakitangan gudang merekod stok masuk dan keluar terus dari telefon, dan secara automatik menjana bil bulanan yang betul untuk setiap pelanggan — lengkap dengan SST yang dikira dengan tepat.

Siapa patut beli: pemilik atau pengurus operasi gudang kontrak kecil atau unit taman logistik yang menyimpan barang bagi 1–15 syarikat pelanggan berasingan. Pada masa ini mereka kemungkinan besar menguruskan ini melalui spreadsheet (satu tab setiap pelanggan) dan mengira bil setiap pelanggan secara manual pada hujung bulan.

Masalah yang diselesaikan

Perbezaan dengan sistem pengurusan inventori biasa

Sistem pengurusan inventori biasa menjawab satu soalan untuk satu perniagaan sahaja: berapa banyak stok yang saya ada, dan di mana ia berada? Produk ini menjawab soalan yang berbeza, kerana operator gudang menyimpan barang bagi pihak perniagaan lain, bukan barang milik sendiri:

Ringkasnya: sistem inventori biasa menjawab "berapa banyak stok yang saya ada." Produk ini menjawab "stok ini milik siapa, dan apa yang perlu saya caj untuk menyimpannya" — sebab itulah perisian pengebilan 3PL kecil (PackemWMS, Fulfillor, GOIS) sudah menjadi kategori tersendiri, berasingan daripada perisian inventori biasa, dan mengapa tiada satu pun daripadanya disesuaikan untuk pasaran Malaysia.

Titik jualan utama

A·2

How it works, in order

Two flows matter most when pitching: how a new warehouse gets started, and the loop they run every single day once they're live.

Getting a new warehouse started

flowchart LR
  A[Owner signs up] --> B[Add each client
and their billing rate] B --> C[Import existing stock
via spreadsheet] C --> D{Stock counts
match a physical count?} D -- yes --> E[Go live] D -- no --> F[Reconcile the mismatch
with warehouse staff] F --> D
Onboarding ends at a physical stock count that matches the system — skipping this step is the #1 cause of billing disputes later.

The daily loop, once live

flowchart LR
  R[Stock arrives
for a client] --> S[Staff scans it in
on phone] S --> T[(Inventory,
per client)] O[Order comes in
from a client] --> P[Staff picks & packs
scanning each item] P --> T T --> M[End of month] M --> N[Invoice auto-built
per client, with SST] N --> X[Owner reviews & sends]
The invoice is a byproduct of the scanning that already happened — nobody re-enters numbers at month-end.
A·3

What's included in the first release

Included at launch (P0)Added once we have paying customers (P1)Not planned yet (P2)
Per-client stock separation, so one client never sees or touches another's goods. Receiving and picking logged from a phone browser (no app download). Automatic monthly invoice per client with SST line items. One warehouse, one location. A proper installable scanning app for faster barcode capture. Multiple warehouse locations under one account. Client self-service portal to see their own stock live. Smart shelf-slotting recommendations. Optimized pick-path routing for large orders. Integrations beyond QuickBooks-style accounting export.
What this deliberately leaves out: this is not a full WMS — no multi-warehouse routing, no automated reordering, no carrier/shipping integration. It solves exactly one problem well: separating client stock and billing it correctly. That is the whole pitch for a first customer.
A·4

Onboarding, timeline, and limits to be upfront about

Customer onboarding, step by step

  1. Owner signs up and adds each of their clients, with that client's agreed storage/handling rate.
  2. Existing stock is imported from whatever spreadsheet they already keep — we don't ask them to re-type anything.
  3. A physical stock count confirms the imported numbers match what's on the shelf (this is the step most likely to surface disputes or data-entry errors, budget real time for it).
  4. Warehouse staff get a 15-minute walkthrough of scanning stock in/out on their phones.
  5. First monthly invoice is generated and reviewed together with the owner before it goes to their client, to build trust in the numbers.

Expected delivery timeline

9–11 weeks from a confirmed pilot customer to a working MVP in their hands, assuming: the founder works on this full-time, the barcode-scanning flow stays web-based (no native app) for v1, and the pilot customer's stock data is importable from a spreadsheet rather than another system. If any of those assumptions break, add 2–4 weeks.

Limitations to set expectations on, before a pilot starts

Document B — Technical Blueprint, for the technical founder
B·1

Product specification

User roles

RoleWhoCan do
operator_ownerWarehouse operator / account ownerEverything: manage clients, rates, staff, billing, exports
warehouse_staffFloor staff doing receiving/pickingScan stock in/out only; no billing or client-rate access
client_viewerThe operator's own client (P1, not in MVP)Read-only view of their own stock and invoices

Key business rules

Core value proposition (one line)

Stock never gets mixed up between clients, and the bill writes itself from what actually happened — instead of a spreadsheet and an evening of manual math every month.

Minimum Sellable Product

One warehouse operator account, their clients and rates, phone-browser receiving/picking tied to each client, and one correct auto-generated SST-compliant invoice at month-end. If a pilot customer can run one real month through this and trust the invoice, the MSP has done its job.

Feature prioritization

PriorityFeatureWhy this tier
P0Client & rate setupNothing else works without this existing first
P0Per-client inventory segregationThe core promise of the product
P0Web-browser barcode scan in/outCamera-based scanning via browser avoids app-store overhead for v1
P0Auto-generated monthly invoice, SST line itemsThis is the feature a customer pays for
P1Installable PWA for scanningFaster, offline-tolerant scanning once volume justifies it
P1Multi-location per accountOnly matters once a pilot customer actually operates two sites
P1Client self-service read-only portalA trust-building feature, not a day-one blocker
P2Slotting/pick-path optimizationNeeds real usage data to even design correctly — speculative before then
P2Accounting-system integrations beyond CSV exportWait until a customer actually asks which system
B·2

Technical architecture

A modular monolith on managed infrastructure — there is no load or team-size reason to run separate services here, and every extra moving part is extra 2am pages for a solo developer.

flowchart TB
  subgraph Client["Client devices"]
    PWA["Phone browser
(scan in/out)"] Desk["Desktop browser
(owner: billing, setup)"] end subgraph App["Next.js app, deployed on Vercel"] UI[Server-rendered pages + API routes] Auth[Auth.js session layer] Jobs["Monthly invoice job
(Vercel Cron)"] end subgraph Data["Managed Postgres (Supabase/Neon)"] DB[(Relational data:
clients, inventory,
movements, invoices)] Storage[(File storage:
generated invoice PDFs)] end PWA -->|HTTPS| UI Desk -->|HTTPS| UI UI --> Auth UI --> DB Jobs --> DB Jobs --> Storage UI --> Storage
One deployable app, one managed database — no queue, no separate services, nothing to operate beyond what Vercel and the DB host already manage.

Recommended stack

LayerChoiceWhy
Frontend + backendNext.js (App Router), one codebaseServer-rendered pages for the desk UI, API routes for the scanning PWA — one deploy, one mental model for a solo dev
DatabasePostgres via Supabase or NeonManaged, generous free tier for the pilot phase, row-level security available if ever needed
ORMDrizzleTyped schema and migrations without an opaque abstraction layer
AuthAuth.js (NextAuth) with email/password or magic linkNo need for social login at this customer segment; keep it boring
ScanningBrowser camera via the BarcodeDetector API / a JS barcode-reading library in a PWA, not a native appShips inside the same web app, no app-store review cycle, works on any staff phone immediately
PDF invoicesServer-side PDF generation (e.g. a Node PDF library) triggered by a scheduled jobRuns inside the same app, no separate rendering service
HostingVercelMatches this founder's existing house stack; zero-ops deploys

Security, monitoring, backups

B·3

Remaining workflows

The customer-facing journey and onboarding flows are in Document A §A·2. These four cover roles, money, and admin.

User roles & permissions

flowchart TD
  U[Incoming request] --> Role{Which role?}
  Role -->|operator_owner| Full[Full access:
clients, rates, staff,
invoices, exports] Role -->|warehouse_staff| Scoped[Scan stock in/out only] Role -->|client_viewer, P1| ReadOnly[Read-only: own stock
+ own invoices] Scoped -.blocked.-> Billing[/Billing & rate endpoints/] ReadOnly -.blocked.-> Billing
Staff and client-viewer roles are blocked from billing endpoints at the API layer, not just hidden from the menu.

Subscription & payment

flowchart LR
  Signup[Operator signs up] --> Setup[One-time RM2,500
setup fee invoiced] Setup --> Active[Account active,
RM349/mo billed] Active --> Grow{Client count
exceeds plan tier?} Grow -- yes --> Upgrade[Move to next
pricing tier] Grow -- no --> Active Active --> Fail{Monthly payment
fails?} Fail -- yes --> Grace[7-day grace period,
email reminder] Grace --> Suspend[Account read-only
if unresolved] Fail -- no --> Active
Payment failure degrades to read-only rather than deleting data — a 3PL operator's inventory records are the one thing that must never silently disappear.

Core operation detail: receive → pick → bill

sequenceDiagram
  participant Staff as Warehouse staff (phone)
  participant App as App
  participant DB as Database
  Staff->>App: Scan incoming item for Client A
  App->>DB: insert movement(type=in, client_id=A)
  Staff->>App: Scan item picked for Client A's order
  App->>DB: insert movement(type=out, client_id=A)
  Note over DB: End of billing period
  App->>DB: aggregate movements + storage-days per client
  App->>App: apply client A's rate card + SST
  App-->>Staff: (owner) reviews draft invoice
    
The invoice is computed from the same movement rows staff created while working — there is no separate manual billing step to get wrong.

Administrative workflow

flowchart LR
  Owner[Operator] --> AddClient[Add new client
+ rate card] Owner --> AddStaff[Add staff account] Owner --> ReviewInv[Review draft invoice
before sending] ReviewInv --> Edit{Dispute or
correction needed?} Edit -- yes --> Adjust[Add a manual
adjustment line, logged] Edit -- no --> Send[Mark sent, export PDF] Adjust --> Send
Manual adjustments are an explicit, logged line item — never a silent edit to the computed total — so the invoice stays auditable.
B·4

Data & API design

Multi-tenancy here is two levels deep: the operator is the paying tenant, and each operator's clients are a second, nested scope. Every inventory and billing row must carry both IDs, and every query must filter by both.

erDiagram
  OPERATOR ||--o{ STAFF_USER : employs
  OPERATOR ||--o{ CLIENT : stores_for
  CLIENT ||--o{ RATE_CARD : has
  CLIENT ||--o{ SKU : owns
  SKU ||--o{ MOVEMENT : tracked_by
  CLIENT ||--o{ INVOICE : billed
  INVOICE ||--o{ INVOICE_LINE : contains
  RATE_CARD ||--o{ INVOICE_LINE : priced_by

  OPERATOR {
    uuid id PK
    text company_name
    text subscription_tier
  }
  STAFF_USER {
    uuid id PK
    uuid operator_id FK
    text role
  }
  CLIENT {
    uuid id PK
    uuid operator_id FK
    text name
  }
  RATE_CARD {
    uuid id PK
    uuid client_id FK
    numeric storage_rate_per_pallet_day
    numeric handling_rate_per_order
  }
  SKU {
    uuid id PK
    uuid client_id FK
    text sku_code
    text description
  }
  MOVEMENT {
    uuid id PK
    uuid sku_id FK
    text type
    int quantity
    timestamp occurred_at
  }
  INVOICE {
    uuid id PK
    uuid client_id FK
    date period_start
    date period_end
    text status
  }
  INVOICE_LINE {
    uuid id PK
    uuid invoice_id FK
    uuid rate_card_id FK
    text description
    numeric amount
    numeric sst_amount
  }
    
Every table below CLIENT carries client_id; every table below OPERATOR carries operator_id (denormalized onto CLIENT and below) so a single indexed compare enforces the tenant boundary on every query.

Key constraints

Core API endpoints

EndpointMethodAuthRequest / response
/api/clientsPOSToperator_ownerreq: {name, rate_card}. res: {client_id}
/api/clients/:id/skusGEToperator_owner, warehouse_staffres: [{sku_code, description, on_hand_qty}]
/api/movementsPOSTwarehouse_staff, operator_ownerreq: {sku_id, type, quantity}. res: {movement_id}. Rejects if type=out and on_hand_qty < quantity
/api/clients/:id/invoices/draftPOSToperator_owner onlyTriggers aggregation for a period; res: {invoice_id, lines[]}
/api/invoices/:id/sendPOSToperator_owner onlyLocks the invoice, generates PDF, res: {pdf_url}
/api/invoices/:id/adjustmentsPOSToperator_owner onlyreq: {description, amount}. Appends a logged line, never edits existing ones
B·5

UI/UX plan

Two distinct contexts: the warehouse floor (phone, thumbs, gloves, moving) and the back office (desktop, billing, setup). Design for both, don't force one UI to serve both badly.

Sitemap

Mobile — floor staff

  • Login (simple PIN or short code, not a full email/password flow on a warehouse floor)
  • Scan screen — single large camera viewfinder, client selector up top
  • In / Out toggle, quantity entry
  • Recent scans list (undo last scan)

Desktop — operator/owner

  • Dashboard — stock summary per client, this month's activity
  • Clients — list, add/edit, rate card editor
  • Inventory — per-client stock table, search by SKU
  • Invoices — draft review, send, history, adjustments
  • Staff — add/remove accounts
  • Settings — company info, subscription/billing

Empty & error states worth designing deliberately

Responsive requirements

The scan screen is mobile-first and should work one-handed in portrait orientation. The back-office screens are desktop-first but must degrade to usable (not broken) on a tablet, since an owner will likely check things from a phone between warehouse visits.

B·6

Development roadmap

Sized for one developer, sequenced to get a pilot warehouse live as early as possible rather than building the full spec before anyone uses it.

PhaseObjectiveKey deliverablesCompletion criteria
1 · 2 wks Foundation Auth, operator/client/SKU data model, client CRUD, rate card editor Operator can log in and set up their client list with rates
2 · 3 wks Inventory core Movement logging API, stock-level aggregation, per-client segregation enforced end-to-end A movement for Client A never appears in Client B's counts, verified with a real test, not just by inspection
3 · 2 wks Scanning UI Mobile scan screen, browser barcode detection, in/out flow, manual-entry fallback A real phone, on real warehouse wifi, can log an in-scan and an out-scan end to end
4 · 2 wks Billing engine Period aggregation job, rate-card application, SST line calculation, draft invoice review screen A full month of test movements produces an invoice the operator agrees is correct
5 · 1–2 wks Pilot hardening PDF export, CSV spreadsheet import for existing stock, basic error monitoring, backup verification One pilot warehouse's real historical stock is imported and matches a physical count
Timeline assumption: 9–11 weeks total assumes full-time solo focus and that the pilot customer's existing stock data is spreadsheet-importable. A pilot customer coming from another WMS with incompatible exports, or a part-time build schedule, extends this — state that explicitly to the commercial founder rather than quietly slipping the date.
B·7

Founder execution split & what needs validating first

StageTechnical founderCommercial founder
DiscoveryConfirm browser barcode scanning is reliable enough on common staff phones (test before committing to the approach)Confirm a real warehouse operator feels the billing pain badly enough to want a pilot — not just agrees it "sounds useful"
PlanningFinalize the data model and SST calculation rules with an accountant's sign-offConfirm the RM2,500 + RM349/mo pricing against what a pilot operator will actually pay
DevelopmentBuild phases 1–5 aboveLine up 1–2 pilot warehouses willing to run real stock through the MVP
TestingFix issues surfaced by the pilot's real stock import and first live monthSit with the pilot through their first invoice review, collect what felt wrong or unclear
LaunchDeploy, monitor the first live billing cycle closelyConvert the pilot to paying, start outreach to the next 2–3 prospects

Commercial assumptions that must be validated before full development starts