A production-style project management platform for organizing work across projects and tasks, with a Kanban-oriented UI and a modular REST API. Built as a pnpm + Turborepo monorepo so the Next.js (App Router) app and NestJS backend share Prisma and TypeScript types. The API emphasizes maintainability with domain modules, validated DTOs, OpenAPI docs, auth, and sensible operational basics (health, logging, rate limits).
Personal project
Context
A production-style project management platform for organizing work across projects and tasks, with a Kanban-oriented UI and a modular REST API. Built as a pnpm + Turborepo monorepo so the Next.js (App Router) app and NestJS backend share Prisma and TypeScript types. The API emphasizes maintainability with domain modules, validated DTOs, OpenAPI docs, auth, and sensible operational basics (health, logging, rate limits).
This project is a full-stack project management application meant to read like a real product codebase. The frontend uses Next.js (App Router), React, TypeScript, and Tailwind CSS. The backend is a NestJS REST API organized by domain (e.g. projects, tasks, organizations, users, notifications) and backed by Prisma, with SQLite for local development and a path to PostgreSQL in production.
The repo is structured as a monorepo: pnpm workspaces plus Turborepo for builds and caching, with shared @repo/database (schema + client) and @repo/types so the client and server stay aligned. The API layer includes JWT/cookie-based auth, Zod validation, Swagger/OpenAPI, throttling, and structured logging—patterns you’d expect when shipping something beyond a demo.
Containerized with separate Docker images for the web and API apps for consistent deploys.
Process
01
Deciding what lives in shared packages (database, types) versus app-specific code, and avoiding circular dependencies or “everything imports everything” as features grow.
02
Keeping REST shapes, shared TypeScript types, and validation (e.g. Zod) aligned so the frontend and backend don’t silently drift when DTOs or Prisma models change.
03
Cookie/JWT flows, refresh rotation, CORS, and secure defaults when the browser talks to a separate API origin; making “logged in” state consistent for both server and client rendering paths on the Next.js side.
04
Scoping projects, tasks, and users to organizations and ensuring every query and authorization check respects that boundary so data never leaks across tenants.
05
Layering concerns beyond “it works locally”: structured logging, health checks, rate limiting, and clear error handling so failures are observable and abuse is bounded.
06
Evolving a Prisma schema while keeping dev (e.g. SQLite) and production (e.g. PostgreSQL) workflows predictable—migrations, seeds, and generate steps in CI or local scripts.
07
Coordinating Docker (or any host) for web and API: build order in the monorepo, env vars per service, and runtime configuration so builds stay reproducible.
Takeaways
Building a project-management style product as a typed monorepo forced me to think in terms of contracts and boundaries, not just screens and endpoints. Sharing Prisma and types between NestJS and Next.js paid off for consistency, but it required discipline: small, stable shared packages and explicit validation on the API so changes stayed traceable. Implementing org-scoped auth and REST modules showed me how quickly “simple CRUD” becomes authorization and data modeling work—and how much easier that is when logging, throttling, and OpenAPI are part of the design from the start rather than bolted on later. Overall, the project shifted my focus from feature lists to maintainable architecture: how the repo, the API surface, and deployment story stay understandable as the app grows.