Bikans: Payroll & Tax SaaS
The clients of an accounting and payroll advisory firm ran payroll and tax withholding in two separate tools, and entered the same company and employee data twice.
What it does: One platform where employee data is entered once and feeds both payroll and tax withholding, with a mandatory second factor and per-tool access.
Overview
Bikans brings payroll and tax withholding for Bikans Asesores' clients into one platform. They used to be two tools, and the same data was typed into both: data entered twice can drift apart, and both calculations depend on it.
Today there is a single employee registry, a period's payroll is imported from Excel, and withholding is calculated from the DIAN (Colombian tax authority) catalogs. I built the whole system, backend and frontend, and it is in production at app.bikans.com.
The need
The firm's clients ran payroll in one tool and tax withholding in another, and typed the same company and employee data into both. Data entered twice can drift apart, and both calculations depend on it.
Constraints
- It is third-party payroll and tax data: each account sees only its own, and a password alone is not enough to sign in.
- Each client uses only the tools it pays for, and the firm assigns them, not the user.
- Peso amounts and percentages come from DIAN rules and cannot lose precision to rounding.
- Payroll already lived in Excel: it had to come in without being typed again.
The solution
A single employee registry, keyed by national ID number, shared by both modules. Each period's payroll is imported from Excel or entered with its adjustments, and withholding is calculated from the DIAN catalogs: concepts with their minimum base in UVT (the tax value unit) and their rate, and economic activities with their ICA (municipal business tax) rate. Users sign in with a password and a TOTP code, and the firm decides from the admin panel which tools each account sees.
How it works
A single-page app in React and TypeScript on a Django REST Framework API, with PostgreSQL as the single database. Each tool is a Django app, and every view checks the tool and the data's owner.
- Sign-in: the password returns a signed challenge token that expires in 5 minutes, not a session
- Mandatory TOTP second factor: users without one set it up before getting in; the secret is stored encrypted with Fernet
- Session as JWT in httpOnly cookies, not in localStorage
- Every view requires access to the tool (
HasProductAccess) and filters by the data's owner - Payroll: periods, per-employee detail, adjustments and Excel import
- Tax withholding from the DIAN concept and economic activity catalogs
- PostgreSQL: one employee registry for both modules
Technical decisions
- An employee is identified by national ID within each account: re-importing a payroll updates the employee instead of duplicating it (
update_or_create). - Tokens travel in httpOnly cookies so a script injected into the page cannot read them.
- Money and percentages as
Decimal, neverfloat. - Records are deactivated, not deleted: the history of payrolls already calculated is kept.
- Accounts the firm creates start without a password: the person gets an activation email and sets their own.
How it's validated
- 105 automated backend tests (Django test runner): sign-in, second factor, per-tool permissions, payroll, import and withholding.
- After five failed attempts, django-axes locks sign-in for one hour.
- The second-factor challenge expires after 5 minutes and keeps no state on the server.
Results
- In production at app.bikans.com: both modules work on the same data, behind a single sign-in.
Limits & next steps
- It is a client's private product: the code is not public and I don't publish usage or customer data.
My part
I built the whole system as a Full Stack Developer at Coordenadas.co for Bikans, an accounting and payroll advisory firm: the Django backend, the React frontend, two-factor authentication and the admin panel.
Stack
Interested in this kind of work?
I'm looking for remote work as a Full Stack Engineer. If you'd like to talk about this project or your team, get in touch.