All articles
17 · Engineering · 2026.05 · 5 min

Shared identity, separate rules: notes from the OYS & TYS monorepo

In OYS & TYS, students, instructors, candidates and administrators share the same identity infrastructure, but each domain has its own data and business rules. In this note I gather my thoughts on keeping domain boundaries clear while sharing common packages inside Turborepo.

01Two systems, one repository

OYS & TYS are systems that handle student and course management and Turkish Proficiency Exam workflows within a shared platform structure. They focus on student, course, examination and administration processes and are developed in a monorepo. The interfaces are written with Next.js and the services with NestJS; the data side uses PostgreSQL, Prisma and Redis. Turborepo manages the repository structure. I am actively involved in frontend and backend development of these web-based management systems, and work on student, course and examination management is ongoing.

In this note I want to talk less about a specific feature and more about a tension I keep running into in this kind of structure: the tension between sharing what is common and keeping separate what is separate.

02What is shared

The needs of students, instructors, candidates and administrators are connected. The same person may enter the system in different roles at different times; things like sign-in, sessions and basic user information should not be rewritten in each domain. That is why shared identity sits at the center of the structure. Turborepo is useful exactly here: it lets shared packages and separate application domains be managed in one repository.

The benefit of sharing is clear. A rule is written once, a type definition means the same thing everywhere, and a fix reaches every application at once. But sharing has a cost too, and in my view that cost is often noticed late.

responsibilities
Turborepo
  shared packages        : identity infrastructure, shared types and tools
  student and course area : Next.js interface  ->  NestJS service
  examination area        : Next.js interface  ->  NestJS service
  data                    : PostgreSQL + Prisma, Redis

03What must stay separate

Each domain has different data and business rules. The lifecycle of a course is not the same as the lifecycle of an examination process; a student's enrollment status and a candidate's exam status do not answer the same questions. Moving these rules into a “shared” package may look tidy at first, but over time that package becomes a place carrying the exceptions of both domains.

My approach here is that only what is genuinely shared goes into a shared package. Identity, common types and general tools can be shared. A domain's business rule does not become shared just because another domain needs something similar. The difference between similar and identical is where people most often go wrong in a monorepo. Making a package shared is easy, separating it later is much harder; so when I am not sure, I prefer to keep things separate.

Shared identity, clear responsibilities.

04User journeys and service boundaries

In this work I focus on considering user journeys alongside data and service boundaries. Something that looks smooth to the user on one screen may touch more than one domain behind the scenes. In those cases the easy path is for one service to reach directly into another domain's data. But that means quietly breaking the boundary.

Working on both frontend and backend has an advantage here: since I see both ends of a journey, I can choose more deliberately where to draw the boundary. Rather than widening a service's responsibility to meet a need in the interface, tying the conversation between two domains to an explicit contract looks healthier in the long run.

05A monorepo needs discipline

A monorepo makes it easy to keep everything in one place; for the same reason, it makes it easy for everything to become connected. Being in the same repository does not mean being the same module. Keeping the direction of dependencies deliberate, making sure one domain does not reach into another's internals and questioning what goes into shared packages are, in my view, the real work of this structure. The rule looks simple, but it is also the easiest thing to forget at the pace of daily work.

A shared piece of infrastructure such as Redis raises the same question. Shared infrastructure does not mean that what it holds can be ownerless. Each domain owning its own data is a principle that needs to hold even when resources are shared.

06An ongoing balance

Because development is ongoing, I am not describing this balance as something finished. With every new need, the question “is this shared, or only similar?” gets asked again. Keeping each domain's rules intact while building a shared foundation is not a decision made once and forgotten; it is a habit that needs constant maintenance. Asking this question out loud is a useful habit in code reviews as well.

Related articles
  1. 18End-to-end responsibility: how layers affect each other in BGBEngineering2026.045 min
  2. 19Same data, four users: notes on the Turkish Art PlatformEngineering2026.035 min