SmartTaxApp
An SST compliance platform for Sarawak's business community — it tells you exactly what tax to charge and why, and it gets smarter every Monday without a developer touching it.
First, what is SST?
SST (Sales and Services Tax) is Malaysia's consumption tax — comparable to VAT in Europe or GST in Australia. Businesses above a revenue threshold must register for it and charge it on qualifying transactions.
Here's where it gets complicated: the rate you apply depends on three things at once — what you're selling, what kind of business you are (your MSIC code), and whether your revenue crosses the registration threshold. MSIC is the government's industrial classification: a cafe, a software company, a law firm, and a clothing retailer all hold different codes, and the same item can be taxed differently under each.
A newly incorporated company, or a cafe crossing RM500k revenue for the first time, navigates this by cross-referencing government PDFs, calling an accountant — or guessing. Most guess. Most get it wrong.
The problem
Startups don't know what tax to charge on their invoices. Cafes don't know whether their items qualify. Established SMEs reclassify products inconsistently across invoices. And when someone typed an item nobody had classified before, the old workflow had no process — the item simply went unresolved.
Underneath the confusion sat a data problem: the product depends on a reference database of items and MSIC codes that was never going to be complete on day one. Every unrecognized item was a data gap — and unhandled gaps accumulate until the system stops being useful.
What I built
Database & access control
- Designed the full PostgreSQL schema from scratch —
profiles,purchases,invoices,msic_codes,items,sst_rules— structured for multi-tenant isolation. - Implemented Supabase Row-Level Security: owner-only access on user-scoped tables, read-only on shared reference tables. The constraint is enforced inside PostgreSQL itself — it holds no matter what the frontend or any API client sends.
SST resolution engine
- A database-driven query chain: item lookup, then MSIC match, then MSIC category fallback, then the SST outcome.
- Zero hardcoded tax rates anywhere in application code. When a tax rule changes, it's a database update — no redeployment.
- Validated against a 12-case acceptance checklist covering different combinations of item type, MSIC code, and expected outcome — with screenshot evidence per case.
The self-improving classification pipeline
This is my favorite part. When a business owner keys in an invoice item that doesn't exist in the database yet, the system doesn't error — it quietly captures and queues it. Then, every Monday:
The admin is a tax specialist, not a developer. They work in a spreadsheet in a shared folder — territory they already know. No database access, no developer involvement, and the reference data improves automatically every week.
Authentication
Email login, password reset, and session handling — with redirect URLs configured correctly across development and production. A reset flow that breaks in production pushes users toward duplicate accounts and weak passwords, so getting this right wasn't optional.
Why I built it this way
RLS at the database layer, not the application layer
Application-level checks depend on the frontend sending the correct user ID and the API trusting it — an assumption that breaks with one bug, one misconfigured client, or one direct database connection. Row-Level Security enforces isolation inside PostgreSQL, at the row level, against the authenticated role, before data ever leaves the database. Least privilege, applied practically.
Database-driven rules, not hardcoded logic
Tax rules in Malaysia change — new categories, adjusted rates. Hardcoded outcomes would make every change a code review, a deployment, and a risk. As structured database rows, an update is a data change: auditable, reversible, deployable without touching code. The MSIC fallback was written as a sequential query chain so each step could be tested in isolation.
A pipeline designed around a non-technical admin
The person with the tax knowledge is not the person with database access — and it shouldn't be the other way around. The shared-folder workflow keeps the admin in a spreadsheet, keeps database writes server-side and automated, and creates a weekly audit trail of what was classified and when.
Outcome
A production-deployed SST compliance platform for Sarawak businesses. Tax classification resolves from database rules with no hardcoded logic. Multi-tenant isolation enforced at the row level. Fresh MSIC data ships every Monday with zero developer intervention.
Supervisor feedback noted proactive problem-solving and consistent delivery under a remote-first arrangement.