LTT Engine Room · Internal

LER Payroll App Standard

PrimaHQ payroll build standard.
v1
24-Jun-26
LERPayrollStandard-App.HTML
LTT Outsourced CFO Sdn. Bhd.

PrimaHQ Payroll — LTT Build Standard & Reproduction Guide

LTT Outsourced CFO Sdn. Bhd. · v1 · 2026-06-24

The single reference for building a PrimaHQ Payroll app for any client, consistently. Hand this whole document to the next chat, together with the client's data, and it can reproduce the app to the same standard.


0. How to use this document

  1. Read Sections 1–9 to understand what the app is and the fixed conventions.
  2. Collect the client inputs listed in Section 10.
  3. Paste Section 11 (the build prompt) into the new chat, fill in the client name, and attach the inputs.
  4. The app is only "done" when the acceptance tests in Section 9 pass — statutory figures must reproduce the client's real payslips to the sen.

1. What PrimaHQ Payroll is

A single self-contained HTML file — a browser-based, offline-capable payroll workspace that LTT (the appointed accountant / outsourced CFO) runs on behalf of client companies. One file per client group; it can hold multiple related entities and switch between them. Data persists in the browser (localStorage). No server, no install — the client or LTT double-clicks the file to open it.

Core jobs it does: - Store company + employee master data and monthly payroll records. - Compute Malaysian statutory contributions (EPF, SOCSO, EIS, PCB) exactly. - Produce itemised payslips (Talenox-style), payroll summary reports, an annual view, and a Salary P&L in Bukku GL format. - Export to Excel and PDF, generate a Bukku accounting import, and produce LHDN tax forms (EA, CP8D, Form E).


2. LTT visual identity (house style — fixed)

Follow the LTT Visual Identity & Application Guidelines. Key rules as applied to PrimaHQ Payroll:

Colour - Primary = Charcoal #323232 for every company, by default. It does not change when switching entity. (This is deliberate — professional and consistent.) - Graphite #3D424A for dark surfaces (table headers), never pure black. - Secondary = the client's brand accent (e.g. orange #F7941E), used on charts and small accents. - Steel blue #5392C5 for links/info only. - LTT crimson #C62F58 is available as an optional theme (a picker in Company Details) but is not the default. - Supporting greys: Soft Grey #7B818A, Line #E3E5E9, light fill #F1EFE8 / #EDEDEA, white canvas. - Keep the accent scarce (~5% of inked area).

Typography - Latin: Poppins (400/500/600/700). Chinese: KaiTi. - All figures use font-variant-numeric: tabular-nums so columns align. - Headings 500–700, labels 500 uppercase with letter-spacing, sentence case elsewhere.

Logos - Each company shows its own brand logo in the top bar and on its payslips (switches with the entity). - The LTTcfo full logo (with the "ltt" text) sits in the footer on every page, stacked (logo above the caption "Accountant / Outsourced CFO"), plus on the payslip footer. Keep it on a white/transparent background — no coloured fill behind a logo. - Embed all logos as base64 data URIs so the file stays self-contained. Resize to ~120–140px tall and optimise (<60 KB each).

Layout: clean editorial — hairline rules #E3E5E9, generous whitespace, no heavy fills, no gradients.

Naming: LTTcfo_<AppName>-v<N>-<yymmdd>.html (whole version number, no leading zero) — e.g. PrimaHQ_Payroll-v20-260623.html. Bump the version and date on every change.


3. Technical constraints (fixed)


4. Malaysian statutory engine (2026 rates — the compliance core)

Build a pure JS engine and verify it against the client's real payslips. Methods:

EPF (KWSP Third Schedule) — for monthly wage ≤ RM20,000: snap wage up to the next RM20 band ceiling, then Employee = 11% × ceiling, Employer = 13% × ceiling (12% if ceiling > 5,000), each rounded up to the next whole ringgit. Age 60+: EE 5.5% / ER 6.5%(≤5000)/6%. Non-citizen (registered from Aug 1998): 2%/2% flat. Anchor: wage 2,250 → EE 249 / ER 294; wage 3,300 → EE 363 / ER 429.

SOCSO (PERKESO Act 4) — banded table, RM6,000 ceiling (since 1 Oct 2024). Cat 1 (under 60): employer 1.75% / employee 0.5% per band midpoint (use the legislated table values). Cat 2 (60+): employer only. Anchor: wage 3,300 → EE 16.25 / ER 56.85.

EIS (SIP, Act 800) — banded, 0.2% employee + 0.2% employer, RM6,000 ceiling. Anchor: wage 3,300 → 6.50 / 6.50.

PCB / MTD (LHDN Computerised Calculation Method) — the [(P−M)R + B − (Z+X)] / (n+1) formula with the YA2025/2026 rate table and standard reliefs (individual 9,000; EPF capped 4,000; spouse 4,000; child 2,000 each). Use the representative-month method (assume the month repeats for the year). Low-wage staff correctly yield RM0.

Per-pay-item statutory flags: every pay item carries flags (subject to EPF / SOCSO / EIS / PCB). Statutory is computed on the sum of flagged items only — this is how allowances/OT are correctly excluded when the client configures them that way.

Acceptance: the engine must reproduce each employee's EPF/SOCSO/EIS/PCB/net on their actual payslips exactly. Encode the full SOCSO/EIS band tables from KWSP/PERKESO/LHDN; do not approximate.


5. Data model (fixed shape)

DB = { companies: [ Company ], activeCompanyId, ... }

Company = {
  id, name, type, regNo, eNumber, cNumber (prefix "IG"), epfNo, socsoNo, zakatNo,
  email, phone, address, state, postcode, bank, bankHolder, bankAcct,
  costCentres[], logo (key), logoData (uploaded override), themeChoice ('client'|'ltt'),
  themeSwap, gl { prefixes, clearing accounts, directorTitle }, employees: [ Employee ]
}

Employee = {
  id, name, ic, pcbNo (income-tax no / TIN), epfNo, gender, taxCategory (1/2/3), children,
  jobTitle, costCentre, rateType (Monthly/Hourly/Daily), basicSalary, hiredDate, resignDate,
  epfContributing, epfCategory ('local'|'noncitizen'|'none'), socsoCategory (0/1/2),
  eisEnabled, bukkuSuffix, paymentMethod, bank, bankAcct,
  records: { 'YYYY-MM': MonthRecord },      // historical, authoritative stored figures
  payruns: { 'YYYY-MM': [ PayItem ] }       // editable current-period items
}

MonthRecord = { items:[{label,amount,type}], earnings, payments,
  epf:{employee,employer}, socso:{employee,employer}, eis:{employee,employer},
  pcb, totalEPF, totalDeductions, net }

6. Tabs & features (fixed order and behaviour)

  1. Dashboard — period range (From/To month + Year quick-pick); metric cards (Gross, Net, Statutory, headcount) and 3 stacked full-width charts: Gross vs Net, statutory (EPF/SOCSO/EIS), headcount (bars + overlay line with counts). Bar fills light/translucent, lines solid; dark data labels (never white); charts lead with the secondary colour.
  2. Payroll Summary Report — Month/Year toggle. Combined payroll and statutory per employee: Cost Centre | Basic | Allowance | Others | Gross | EPF ee/er | SOCSO ee/er | EIS ee/er | PCB | Total Deductions | Net, with a TOTAL row. Excel and PDF export. Year dropdown descending.
  3. Salary P&L — Bukku Profit & Loss format: GL account code in front, per-employee lines grouped by account (Basic 91901, OT 91902, Allowance 91903, Incentive 91905, EPF-ER 91907, SOCSO-EII 919081, SOCSO-SIP 919082…), per-account TOTAL + GRAND TOTAL, months earliest-left / latest-right, a YTD total column, an interactive category chart on top. Default range = 1 Jan of current year → latest month. LTT-grey formatting (crimson only on grand total). Excel + PDF export.
  4. Payslips — Talenox itemised format: Earnings (A), Payments (B), Deductions (C: EPF/EIS/SOCSO/PCB), Statutory Funds (employer), Net = A+B−C; plus a Monthly / YTD switch with year selector. Prints one A4 page (no stray leading page — remove the body left-spine border in @media print).
  5. Employees — ordered Director → Manager → Admin cum Teacher → Staff → Part-time; within each rank (except Director) by most-recent gross descending. Shows Cost Centre, Job Title, and the GL Account Code (editable field).
  6. Company Details — all statutory numbers; logo display + upload; colour-theme picker (Client / LTT / swap). Hide fields the client doesn't use (e.g. NMCE EPF No.).
  7. Exports — Payroll Schedule (.xlsx) and Payroll YTD at the top; Export to Bukku (double-entry journal, year-to-date) in its own section at the bottom.
  8. Tax Forms — Form EA, CP8D, Form E for a selected year (see Section 8).

Month dropdowns: single continuous list, newest first (e.g. May 2026 … January 2024). Switching entity preserves the current tab/period — only the company changes.


7. Bukku / GL account-code conventions (fixed)

The Bukku import is a double-entry journal: debit the expense lines (basic, OT, allowance, incentive, employer EPF/SOCSO/EIS) and credit the clearing lines (net salary payable + total EPF/SOCSO/EIS); each month balances (debits = credits). Verify byte-for-byte against the client's existing Bukku import if one exists.


8. LHDN tax forms (fixed)

Build all three from the same annual aggregation so they reconcile (Form E total = Σ CP8D rows = Σ EA gross): - Form EA (C.P.8A) — clean, full-page, per-employee statement in Parts A–F: A particulars (name, TIN, IC, EPF/SOCSO no., designation, children, commencement/cessation), B gross with component sub-lines (BIK/VOLA/ESOS = 0), C pension, D MTD/CP38/Zakat, E EPF/SOCSO/EIS employee, F tax-exempt. "View EA" + "Print all EA". (Do not try to pixel-copy the official form in HTML — if an exact-format EA is required, fill LHDN's official fillable PDF from the app data instead.) - CP8D — employee listing with the official column set; export .xlsx and pipe-delimited .txt named CP8D_<Enumber>_<year>.txt; sortable headers; TOTAL row. - Form E — employer return summary (headcount, totals, MTD) matching the official masthead/sections.

Always flag: BIK/VOLA/ESOS are 0 (payroll doesn't capture them — add manually) and the CP8D .txt must be validated against the official e-CP8D / e-Data Praisi template before submission.


9. Verification & acceptance (mandatory)

Before delivering any version: 1. Statutory to the sen — engine reproduces every real payslip's EPF/SOCSO/EIS/PCB/net. 2. Bukku byte-for-byte — generated journal matches the client's existing Bukku import (ignoring the internal # id). 3. Reconciliation — Salary P&L grand total = sum of Bukku debit lines; Form E = Σ CP8D = Σ EA. 4. Smoke test — Node + vm DOM shim: all tabs render for all companies, 0 errors; anchor figures assert true. 5. File ends with </html>, is self-contained, and opens cleanly.


10. Client onboarding inputs to collect

Read these from the client's Google Drive where possible (via the connected Drive), rather than re-uploading. Ingest full history from the annual master sheet(s) — one per company/year replaces a whole folder of payslips.


11. Copy-paste build prompt for the next chat

Build a single self-contained HTML payroll app called PrimaHQ Payroll for the client , strictly following the LTT PrimaHQ Payroll Build Standard v1 (attached). Requirements:

  • LTT house style: charcoal #323232 primary for all entities (fixed, does not change on entity switch), client brand accent as secondary, Poppins, tabular numerals, clean editorial layout, client logo per company in the top bar/payslip, LTTcfo full logo in the footer as "Accountant / Outsourced CFO". Self-contained file; allowed CDNs only: SheetJS, Chart.js + datalabels, jsPDF + autotable. localStorage persistence with a versioned key. Naming PrimaHQ_Payroll-v<N>-<yymmdd>.html.
  • Build the 2026 Malaysian statutory engine (EPF Third Schedule, SOCSO & EIS band tables to the RM6,000 ceiling, PCB/MTD) with per-pay-item statutory flags, and verify it reproduces the client's real payslips to the sen.
  • Data model, tabs, and behaviours exactly as in the standard: Dashboard (period charts), Payroll Summary Report (month/year, combined payroll+statutory, xlsx+PDF), Salary P&L (Bukku GL format with YTD column + category chart, xlsx+PDF), Payslips (Talenox format, monthly+YTD, one-page print), Employees (role-ordered, editable GL code), Company Details (logo upload + theme picker), Exports (Payroll Schedule + Export-to-Bukku YTD), Tax Forms (EA Parts A–F, CP8D, Form E — reconciling).
  • GL/Bukku account codes per the standard's prefix table; suffix = client code else E+id; account names proper-case with (Employer)/(Employee) and SOCSO=EII, EIS=SIP.
  • Load full history from the client's master payroll sheet(s); store historical months as authoritative records (don't recompute).
  • Verify with a Node + vm DOM-shim smoke test (0 errors, anchors hold) before delivering. Deliver the versioned single file plus a GL classification export (account × month and by-employee) for Finance reconciliation.

Client inputs are attached: [company details, employee master, monthly payslips or master sheet, Bukku GL codes, client logo].


12. Reusable assets from the Tadika/JC build (optional to reuse)

Keep these in the LTT template library so each new client build starts from proven, verified code.


Prepared by LTT Outsourced CFO Sdn. Bhd. — internal build standard for PrimaHQ Payroll. Update the version and date when the standard changes.

Source: LTTcfo_PrimaHQ-Payroll-Build-Standard-v1-260624.md · ler.lttcfo.ai/apppayroll