Fiscplus
A production, multi-tenant SaaS that replaces the email-and-spreadsheet chaos of a Belgian accounting practice with a single source of truth — three role-scoped portals, real-time collaboration, and a full Belgian anti-money-laundering compliance module.
- Type
- SaaS · Web App
- Role
- Solo Full-Stack Build
- Built
- 2026
- Client
- Confidential — Belgian accounting firm
Why I built it
A Belgian accounting practice ran its fiscal periods on a patchwork of email threads, shared drives, spreadsheets, and manual chases. Client onboarding, document collection, VAT/tax cycles, and anti-money-laundering compliance lived in disconnected tools with no single source of truth.
Regulated work raises the stakes: ITAA professional norms and the Belgian Anti-Witwaswet (AWW / AML) demand auditable identification, screening, and record-keeping that ad-hoc tooling simply cannot guarantee.
The three portals
One codebase, three role-scoped portals: Admin (firm operations and oversight), Assistant (delegated work and task management), and Client (multi-company self-service for the accounting firm's clients).
Each portal exposes only the modules and actions its role requires. A single shared type-safe API layer keeps everything consistent without duplicating logic or drifting out of sync.
The AML (AWW) compliance module
The most complex piece: a complete Belgian AWW (Anti-Witwaswet / AML) compliance lifecycle. It covers client identification, KBO and VIES business registry validation, UBO (Ultimate Beneficial Owner) declaration, PEP / sanctions / adverse-media screening, and a four-pillar risk scoring model.
The module generates engagement letters, schedules periodic rechecks, runs vigilance monitoring, and stores an investigation-file vault with configurable retention — fully auditable at every step.
Architecture
React 19 + Vite SPA (TanStack Query for server state, Zustand for session state) talking to a modular NestJS 11 API over REST + WebSocket. PostgreSQL via Prisma 7, Redis for cache/queues/pub-sub, BullMQ for background jobs, and 20+ scheduled cron tasks.
Event-driven cross-portal sync: every mutation emits a domain event, the gateway broadcasts to interested rooms, and subscribers invalidate the right query keys — with own-action de-duplication to prevent echo re-renders. Type-safe end to end: TypeScript strict, Prisma-generated types, Zod + class-validator at the boundary.
Key decisions
Four architectural choices that shaped the entire system.
Real-time, event-driven sync
80+ domain events drive optimistic UI and cross-portal cache invalidation. Every mutation emits an event; the WebSocket gateway broadcasts to interested rooms; subscribers invalidate only the affected query keys — with own-action de-duplication to prevent echo re-renders.
Granular RBAC
92+ permissions with per-user overrides on top of role defaults. The permission engine checks both role-level grants and explicit per-user allow/deny entries, so firm administrators can delegate precisely without creating new roles.
Type-safe boundary
Zod schemas on the API boundary and class-validator decorators on NestJS DTOs enforce the same shape at both runtime and compile time. Prisma-generated types flow from the database through the service layer to the React Query hooks — no manual casting.
Auditability by default
Every sensitive mutation (client records, AML decisions, document uploads, permission changes) is logged to an append-only audit trail. The log captures actor, timestamp, before/after state, and the originating request — making compliance reviews straightforward.
The outcome
One accountable engineer delivered an agency-scale, regulated SaaS — three portals, a full AML compliance module, and real-time collaboration — to production. The firm replaced its spreadsheet-and-email workflow with a single, auditable system it owns outright.
From concept to creation let's make it happen.
I'm available for full-time roles & freelance projects.
I thrive on crafting dynamic web applications, and delivering seamless user experiences.