Overview
Sakena is a management platform for residential complexes, built as a team project for Sharif's Analysis and Software Design course. The premise is ordinary — apartment buildings need someone to log a leak, a manager needs to know which units still owe this month's shared costs, a resident wants to know whether the elevator repair got scheduled — but the system underneath had to hold up three different users with three different jobs against the same data.
Architecture as the actual deliverable
Where most course projects optimize for finishing features, this one treated
the architecture itself as the graded artifact. The Kotlin backend is
organized by bounded context first, then by layer inside each: domain,
application, and infrastructure, with a dependency rule that only points
inward — the domain layer cannot import Spring, JPA, or Jackson, full stop.
Business rules live on the aggregate itself, enforced at construction and
through behavior methods, rather than scattered across services that merely
orchestrate. A small task module ships as the deliberate reference
implementation: new bounded contexts are expected to copy its shape rather
than invent a new one, which is what let four people add units, service
requests, payments, announcements, chat, and more without the codebase
drifting into four different styles.
Three roles, one API
Residents, building managers, and service staff all work through the same backend with role-scoped permissions rather than separate apps. A manager manages buildings and units, publishes announcements, and reviews payment history; a resident files service requests and reads what the manager posted; a service worker picks up tasks, reports on completed work with cost and notes attached, and can look back at everything they have finished. That shared surface is also why the auth layer got early, deliberate attention — role has to come from the backend's own record of who a user is, never from a client-side selection, or the three-roles model collapses into "whatever the frontend claims."
Frontend
The client is a Next.js app on the same stack I use across these projects — TanStack Query for server state, Zustand for what is genuinely client state, Zod schemas driving React Hook Form — because keeping that boundary consistent is what makes a fast-moving four-person frontend stay readable instead of accumulating four ad hoc patterns for the same problem.
What is deliberately not built
Not every backend endpoint has a UI, and that gap is documented rather than hidden: a generic task CRUD module exists only as the architecture's reference implementation, not a product feature, so the Tasks screen is wired to service requests instead. Treating "no UI for this" as a tracked, intentional decision — not an oversight to quietly leave unfinished — kept the team's actual scope legible as the project grew.








































