
$50,000+ Stripe volume in the first 3 months with a complex multi-role wallet system.
Dwulx connects parents with childcare providers for bookings, wallets, and payouts — the wallet had to survive real Stripe volume, not a demo ledger. The stack migrated from an early React/Node app to Next.js for SEO and performance while preserving money-movement correctness.
Next.js dashboards with Stripe Connect, PostgreSQL double-entry ledger tables, idempotent webhooks, and admin tooling to freeze payouts when disputes open — parents, providers, and ops each see scoped ledgers.
Commission splits, cancellation-triggered withdrawal holds, automatic monthly disbursements, and blocked payments during disputes — all visible to three roles with different mental models of “balance available.”

RBAC with separate Next.js route groups and server-side enforcement on API routes.
Postgres schema for accounts, postings, and balances with invariant checks in transactions.
Onboarding, PaymentIntents, transfers, and webhook-driven reconciliation with idempotency keys.
State machine ties cancellations and tickets to withdrawal locks visible in UI.
Next.js migration preserved URLs and improved TTFB for provider discovery pages.
Processed in the first three months after launch — enough real traffic to flush rounding bugs, timezone edge cases on disbursement cron, and Stripe Connect onboarding friction before scaling marketing spend.
Processed in the first three months after launch — enough real traffic to flush rounding bugs, timezone edge cases on disbursement cron, and Stripe Connect onboarding friction before scaling marketing spend.
Parents, providers, and admin each interact with the same underlying ledger through different lenses — parents see spend and receipts, providers see earnings and holds, admin sees exceptions and manual overrides.
Splits, holds, scheduled disbursements, and dispute blocks — implemented as explicit ledger states so support could answer “where is my money?” from rows, not inferred balances.




Never store a single floating “balance” column without postings — support and audits require explainability.
Stripe webhooks were idempotent keyed by event ID to survive retries safely.
Server components and routing improved SEO for parent acquisition without a separate marketing site.
Three dashboards shared components but not data loaders to avoid accidental data leaks.
We take on a small number of projects at a time. If the problem is hard, we're interested.