DOC: WORK-AVIARAICASE STUDY 01
REV 2026.08

Aviarai — poultry operations, built to hold up.

A poultry farming platform running subscriptions, inventory, dispatch, and supply orders as one system instead of spreadsheets. Backend-primary contract, full-stack when it needed to be.

Contract, Jun 2025—Spring BootReactPostgreSQLRBACCI/CD

Approach & Execution

Built RBAC, inventory, dispatch and supply orders, and subscriptions from scratch — staging and production running across admin, services, sales, and UI, with CI/CD wired through all of it. Also owned the offline architecture (backend built, currently in an open PR pending merge) and an authentication architecture overhaul mid-contract — refresh tokens, now merged and live.

Staging came in when the team actually needed a real pre-prod environment to test against — not on day one just because “you're supposed to have one.” Designed and built the subscription and billing system end to end: dual Stripe/Paystack processing behind one abstraction, trial provisioning, upgrades and downgrades, seat-based licensing, and cron-driven renewal and expiration, plus a full billing audit trail.

Key technical patterns

  • Role-based access control spanning 4 roles and 13 feature-level permissions — backend enforcement plus the frontend, permission-gated UI and admin screens for managing admins and invite codes
  • Concurrent stock validation on the inventory system, preventing data discrepancies when parallel writes hit the same records
  • A cross-service supply-order system bridging an external Sales microservice with inventory — invoice auto-population, multi-dispatch tracking, denormalized for fast queries at scale
  • Cron-driven subscription lifecycle schedulers keeping billing state correct without manual intervention

When Auth Started Timing Out

Auth requests started timing out under load. The obvious suspect was traffic. It wasn't.

The real cause was a @Transactional annotation placed too broadly on the auth path — it held a database connection checked out for the entire call, not just the query inside it. HikariCP's pool wasn't overloaded, it was exhausted: every connection was in use, doing nothing. The fix wasn't a bigger pool, it was finding where a connection was held past its need, narrowing the annotation's scope, and retuning the pool to match real usage instead of guessed usage. Full-service outage, all users locked out, resolved in about 1.5 hours — then written up as a postmortem so the next engineer doesn't have to rediscover it at 2am.

A similar pattern showed up in billing: a successful Paystack payment could leave a subscription stuck mid-update, because the code assumed failures would always throw an exception, then caught and retried. Some failures didn't throw — the data just drifted, silently. Fixed by replacing exception-driven control flow with upsert semantics, so the operation became idempotent by construction. Part of a wider sweep that caught 13 billing edge cases, including a double-charge pricing defect fixed by switching to delta-based billing.

Impact & Results

  • Runs Aviarai's production platform today: 30+ registered farms, 70+ platform users, 30+ tracked subscriptions
  • Audited logging coverage across 121 backend services and closed the two biggest observability gaps
  • Built staging and production infrastructure from scratch on DigitalOcean — Apache reverse proxy, isolated databases, Docker, GitHub Actions CI/CD across 4 repositories
  • Diagnosed a Smart Feed (AI recommendation) date bug, then partnered directly with the CEO to fix rounding-policy defects to match the business's real cost model
  • User-reported fixes turned around fast: a table-row edit no longer resets to page one; KPI dashboard load time cut from ~10–12s to ~2s; a bug where successful payments weren't sending confirmation emails

Key Takeaways

A connection pool is a queue with a ceiling — if anything upstream holds a resource longer than it needs to, that ceiling arrives faster than the pool size on paper suggests. And if a bug can only be patched by catching more exceptions, the bug usually isn't the missing catch block, it's the control-flow model underneath it. Both lessons came from watching real usage outgrow assumptions baked in early.

© 2026 HENRY TAIWO