Appearance
Introduction
Planner is a full-featured project management platform built with a modern TypeScript stack. It supports multi-tenant organizations, teams, projects, tasks with a rich lifecycle, real-time chat, WebSocket notifications, and granular role-based access control.
Architecture
Monorepo Structure
The project uses pnpm workspaces with Turborepo for build orchestration:
planner/
├── apps/
│ ├── backend/ # NestJS API (port 4000)
│ ├── frontend/ # Vue 3 SPA (port 3000)
│ ├── website/ # Nuxt 4 marketing site (port 8080)
│ └── docs/ # VitePress docs (port 8081)
├── packages/
│ ├── shared-types/ # @planner/shared-types
│ ├── shared-utils/ # @planner/shared-utils
│ └── ui-kit/ # @planner/ui-kit
├── docker/ # Dockerfiles for each app
├── docker-compose.yml # Development compose
├── docker-compose.prod.yml # Production compose
├── turbo.json # Turborepo pipeline config
├── pnpm-workspace.yaml
└── package.jsonFrontend Architecture (Vue 3)
- Routing: Vue Router with lazy-loaded views, nested layouts (AdminLayout, OrgLayout, TeamLayout)
- State: Pinia setup stores with
storeToRefsfor reactive bindings - UI: PrimeVue 4 with Aura theme (emerald primary, slate surface)
- Real-time: Socket.IO client connects on auth, joins user-specific rooms
- i18n: vue-i18n@9 with Composition API, EN/RU locales persisted to localStorage
Backend Architecture (NestJS)
- Modules: Feature-based modules (Auth, Users, Organizations, Teams, Projects, Tasks, Comments, Chat, Notifications, TaskHistory)
- Auth: JWT access tokens (15min) + refresh tokens (7d) with passport-jwt strategy
- Permissions: Custom
@Permissions()decorator +PermissionsGuard— checksrequiredPermissionsagainst user's effective permissions - Real-time:
NotificationsGateway(namespace/notifications) — emits touser:<id>rooms - Database: PostgreSQL with Prisma ORM, migrations via
prisma db push
Key Design Decisions
Notifications Module
@Global()— all services injectNotificationsServicedirectlyNotificationsService.create()is fire-and-forget (not awaited) to avoid slowing main operations- WebSocket gateway (
/notificationsnamespace) authenticates viahandshake.auth.tokenusingJwtService
Tasks — Project-scoped
projectIdonTaskmodel is required with cascade delete from Project- CRUD via
ProjectTasksControllerat/projects/:id/tasks(PROJECT scope permissions) - Task comments via
ProjectTaskCommentsControllerat/projects/:id/tasks/:taskId/comments - Task history logged automatically on create/update/status change/assign/delete
Permissions System
- 30+ granular permissions across 6 scopes: GLOBAL, ORGANIZATION, TEAM, PROJECT, TASK, CHAT
- Custom roles can combine any permission set
- User groups for bulk role assignment
- Computed permissions aggregate from user's roles at global, org, team, and project levels