Defining Project Scope
Defining Project Scope
Before writing a single line of code, you need to define exactly what you are building, who it is for, and what constraints apply. A well-defined scope prevents feature creep, aligns stakeholders, and gives your team a clear target.
MoSCoW Prioritization
MoSCoW separates features into four priority tiers so you know what must ship in the MVP and what can wait.
Must Have (MVP - ship without these the product is broken)
- User registration and login with email/password
- CRUD operations for core domain (tasks, projects, etc.)
- Responsive UI that works on mobile and desktop
- Error handling with user-friendly messages
- Input validation on both client and server
Should Have (important but not blocking launch)
- Search and filter functionality
- Pagination for list views
- File upload for avatars and attachments
- Email notifications for key events
- Dark mode toggle
Could Have (nice-to-haves that add polish)
- Real-time updates via WebSockets
- Social login (Google, GitHub)
- Activity feed / audit trail
- Dashboard with charts and analytics
Won't Have (explicitly out of scope for now)
- Native mobile apps
- Payment processing
- Multi-language internationalization
- Offline-first architecture
Writing User Stories with Acceptance Criteria
Each feature should be expressed as a user story with clear acceptance criteria. This turns vague ideas into testable requirements.
Story: As a registered user, I want to create a new project
so that I can organize my tasks into logical groups.
Acceptance Criteria:
GIVEN I am logged in
WHEN I click "New Project" and fill in name + description
THEN a project is created and I see it in my project list
GIVEN I am logged in
WHEN I submit a project with no name
THEN I see a validation error "Project name is required"
GIVEN I submit a project name over 100 characters
THEN the input is rejected with "Name must be 100 characters or fewer"
Effort Estimation with Story Points
Use Fibonacci story points (1, 2, 3, 5, 8, 13) to estimate relative complexity, not time. This accounts for uncertainty better than hour-based estimates.
Feature Points Reasoning
─────────────────────────────────────────────
Auth (register/login) 5 Standard flow, JWT, bcrypt, validation
Project CRUD 5 CRUD + ownership checks + pagination
Task management 8 Nested under projects, status workflow, assignment
Team invitations 5 Email flow, role-based access, invite tokens
Search & filter 3 Full-text search, filter by status/assignee
File uploads 3 S3 integration, multer, image processing
Comments on tasks 2 Simple nested CRUD, no threading
─────────────────────────────────────────────
Total 31
At a team velocity of 8 points per 2-week sprint:
31 / 8 ≈ 4 sprints (8 weeks)
Technical Requirements Document
Document non-functional requirements alongside features:
Performance:
- LCP < 2.5 seconds on 3G connection
- API response time < 200ms (p95)
- Support 1000 concurrent users
Security:
- HTTPS everywhere
- JWT with 15-minute access tokens
- Rate limiting: 100 requests per 15 minutes
- Input sanitization against XSS and SQL injection
Reliability:
- 99.9% uptime target
- Automated backups daily
- Graceful degradation when external services fail
System Architecture
System Architecture
System architecture defines how components communicate, where data lives, and how the system scales. Designing this on paper first saves weeks of refactoring later.
High-Level Architecture
┌─────────────────────────────────────────────────────┐
│ CLIENTS │
│ Browser (React SPA) Mobile (future) │
└──────────────┬──────────────────┬───────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────┐
│ CDN (Cloudflare) │
│ Static assets, caching, DDoS protection │
└──────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ LOAD BALANCER (Cloudflare / AWS ALB) │
└──────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ API SERVER (Express + Node.js) │
│ Auth middleware, rate limiting, CORS, logging │
│ Business logic in service layer │
│ Validation with Zod schemas │
└──────┬──────────────┬──────────────┬────────────────┘
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌──────────────┐
│ PostgreSQL │ │ Redis │ │ S3 Bucket │
│ Primary DB │ │ Cache │ │ File uploads │
│ + replicas │ │ Sessions │ │ Avatars │
└────────────┘ └────────────┘ └──────────────┘
Database Schema with Migrations
Use Prisma for type-safe database access and automatic migrations:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique
name String
passwordHash String @map("password_hash")
role Role @default(MEMBER)
avatarUrl String? @map("avatar_url")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
ownedProjects Project[]
memberships Membership[]
assignedTasks Task[] @relation("TaskAssignee")
comments Comment[]
@@map("users")
}
model Project {
id String @id @default(uuid())
name String
description String?
ownerId String @map("owner_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
memberships Membership[]
tasks Task[]
@@index([ownerId])
@@map("projects")
}
model Task {
id String @id @default(uuid())
projectId String @map("project_id")
title String
description String?
status TaskStatus @default(TODO)
priority Priority @default(MEDIUM)
assigneeId String? @map("assignee_id")
dueDate DateTime? @map("due_date")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
assignee User? @relation("TaskAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
comments Comment[]
@@index([projectId])
@@index([assigneeId])
@@index([status])
@@map("tasks")
}
enum Role {
ADMIN
MEMBER
}
enum TaskStatus {
TODO
IN_PROGRESS
IN_REVIEW
DONE
}
enum Priority {
LOW
MEDIUM
HIGH
URGENT
}
API Route Design
Organize routes by resource. Every endpoint follows RESTful conventions:
Auth:
POST /api/auth/register Create account
POST /api/auth/login Get tokens
POST /api/auth/refresh Refresh access token
POST /api/auth/logout Revoke refresh token
Users:
GET /api/users/me Get current user profile
PATCH /api/users/me Update profile
Projects:
GET /api/projects List user's projects (paginated)
POST /api/projects Create project
GET /api/projects/:id Get project details
PATCH /api/projects/:id Update project
DELETE /api/projects/:id Delete project
POST /api/projects/:id/members Add member
DELETE /api/projects/:id/members/:userId Remove member
Tasks:
GET /api/projects/:projectId/tasks List tasks (filterable)
POST /api/projects/:projectId/tasks Create task
GET /api/tasks/:id Get task
PATCH /api/tasks/:id Update task
DELETE /api/tasks/:id Delete task
Comments:
GET /api/tasks/:taskId/comments List comments
POST /api/tasks/:taskId/comments Add comment
DELETE /api/comments/:id Delete comment
Development Workflow
Development Workflow
A disciplined development workflow ensures code quality, enables parallel work, and makes deployments predictable. This section covers branching, sprint planning, and quality gates.
Git Branch Strategy
Use a simplified Git flow that keeps main always deployable:
main ← production-ready code, protected branch
│
├── develop ← integration branch, all features merge here first
│ │
│ ├── feature/auth ← feature branches
│ ├── feature/task-crud
│ └── feature/search
│
├── release/v1.0 ← release stabilization
│
└── hotfix/critical-bug ← urgent production fixes
Branch naming conventions:
feature/short-description
bugfix/issue-number-description
hotfix/critical-description
release/vX.Y.Z
Sprint Planning Template
Sprint 1 (Weeks 1-2): Foundation
─ Project scaffolding (Vite + React, Express + TypeScript)
─ Database setup with Prisma, initial migration
─ Auth system: register, login, JWT middleware
─ User profile page
─ Shared UI shell (layout, nav, routing)
Definition of Done: auth flow works end-to-end, CI pipeline green
Sprint 2 (Weeks 3-4): Core Features
─ Project CRUD with ownership validation
─ Task CRUD with status transitions
─ Dashboard showing project list and task counts
─ Form validation on all inputs (Zod schemas)
Definition of Done: all CRUD operations tested, no console errors
Sprint 3 (Weeks 5-6): Collaboration
─ Team member invitations with email
─ Role-based access control (admin vs member)
─ Comments on tasks
─ Search and filter for tasks
Definition of Done: RBAC enforced, search returns relevant results
Sprint 4 (Weeks 7-8): Polish & Deploy
─ Unit tests (80%+ coverage on services)
─ Integration tests for API endpoints
─ Performance audit (Lighthouse, API benchmarks)
─ Security review (OWASP checklist)
─ Production deployment with health checks
─ README and API documentation
Definition of Done: deployed to production, all tests passing
Definition of Done Checklist
Every story must meet ALL of these before it is considered complete:
Code Quality:
☐ Code reviewed and approved by at least one team member
☐ No TypeScript errors or ESLint warnings
☐ Follows project naming conventions and code style
☐ No hardcoded values—all config from environment variables
Testing:
☐ Unit tests written for business logic (services, utils)
☐ Integration tests for API endpoints
☐ Test coverage ≥ 80% on changed files
☐ Manual testing on Chrome, Firefox, and mobile viewport
Security:
☐ Input validated on both client and server
☐ Authentication required on protected routes
☐ Authorization checked (user can only access own resources)
☐ No secrets committed (checked with git-secrets or similar)
Documentation:
☐ API endpoints documented (request/response examples)
☐ Complex algorithms or business rules commented
☐ README updated if setup steps changed
Deployment:
☐ Feature works on staging environment
☐ Database migration is reversible
☐ No breaking changes to existing API contracts
Tech Stack Decision Framework
Tech Stack Decision Framework
Choosing a tech stack is one of the most consequential decisions in a project. Use a structured decision matrix instead of picking based on hype or personal preference.
Frontend Decision Matrix
Criteria React Vue Svelte Angular
──────────────────────────────────────────────────
Ecosystem 5 4 3 4
Learning curve 3 4 4 2
Performance 3 3 5 3
Job market 5 3 2 4
TypeScript support 4 4 4 5
Community size 5 4 3 4
──────────────────────────────────────────────────
Total 25 22 21 22
Winner: React (largest ecosystem, best job market, proven at scale)
Backend Decision Matrix
Criteria Express Fastify NestJS Hono
──────────────────────────────────────────────────
Performance 3 5 3 5
Learning curve 5 4 2 4
Ecosystem 5 3 4 2
Flexibility 5 4 2 4
TypeScript native 3 5 5 5
──────────────────────────────────────────────────
Total 21 21 16 20
Winner: Express for learning and flexibility, Fastify for performance
Database Decision Matrix
Criteria PostgreSQL MongoDB SQLite
───────────────────────────────────────────────
ACID compliance 5 3 5
Scalability 5 5 2
Query power 5 3 4
Schema evolution 4 5 2
Hosting options 5 4 3
───────────────────────────────────────────────
Total 24 20 16
Winner: PostgreSQL for structured data, add Redis for caching
Recommended Stack and Rationale
// The stack for a production-ready full stack app:
const recommendedStack = {
frontend: {
framework: 'React 18 + TypeScript',
buildTool: 'Vite',
styling: 'Tailwind CSS',
stateManagement: 'React Query (server state) + Zustand (client state)',
forms: 'React Hook Form + Zod validation',
reason: 'React has the largest ecosystem. Vite is fastest build tool. Tailwind eliminates CSS boilerplate.',
},
backend: {
runtime: 'Node.js 20 LTS',
framework: 'Express + TypeScript',
validation: 'Zod (shared schemas with frontend)',
auth: 'JWT (access + refresh tokens)',
logging: 'Pino (structured JSON logs)',
reason: 'Express is battle-tested. Zod gives end-to-end type safety. Pino is fastest Node logger.',
},
database: {
primary: 'PostgreSQL 16',
orm: 'Prisma (type-safe queries, auto migrations)',
cache: 'Redis (session store, query cache, rate limiting)',
search: 'PostgreSQL full-text search (pg_trgm + tsvector)',
reason: 'PostgreSQL handles relational data, full-text search, and JSON. Redis adds caching layer.',
},
infrastructure: {
hosting: 'Vercel (frontend) + Railway (backend + DB)',
cdn: 'Cloudflare (static assets, DDoS protection)',
storage: 'AWS S3 (file uploads)',
monitoring: 'Sentry (errors) + Pino logs',
ci: 'GitHub Actions (test, lint, deploy)',
reason: 'Vercel and Railway have generous free tiers and simple deployment. Cloudflare for edge caching.',
},
};
When to Deviate from the Stack
Scenario Alternative Why
──────────────────────────────────────────────────────────────────────
Need real-time features Add Socket.IO Native WebSocket support
High-write data (logs, events) Switch to MongoDB Schema flexibility, write perf
Need full-text search at scale Add Elasticsearch Better search features
Team knows Vue better than React Use Vue Developer velocity matters most
Simple CRUD with no complexity Use SQLite Zero infrastructure overhead
Need server-side rendering Use Next.js instead Built-in SSR and SSG
Quiz
1. In MoSCoW prioritization, what distinguishes a 'Must Have' from a 'Should Have' feature?
2. Why should you use story points instead of hour-based estimates for sprint planning?
3. What is the primary purpose of a Definition of Done checklist in sprint planning?
Flashcards
Question
What is the difference between MoSCoW Must Haves and Could Haves?
Click to reveal answer
Answer
Must Haves are mandatory for the MVP—the product is broken or non-compliant without them. Could Haves are desirable enhancements that add polish but are the first to be cut when deadlines approach. Must Haves define the minimum shippable product; Could Haves define the ideal product.
Question
What are the three layers of a typical full stack architecture and what does each handle?
Click to reveal answer
Answer
1) Presentation layer (React SPA) handles UI rendering, user interaction, and client-side routing. 2) Application layer (Express API) handles business logic, authentication, validation, and data transformation. 3) Data layer (PostgreSQL + Redis) handles persistent storage, caching, and session management. Each layer communicates through well-defined interfaces (HTTP routes, ORM queries).
Question
Why should database indexes be defined during schema design rather than added reactively?
Click to reveal answer
Answer
Indexes defined during schema design are based on known query patterns from the API route design. Adding them later means you are optimizing reactively after performance problems appear. Designing indexes upfront (e.g., indexing foreign keys, status columns, and frequently filtered fields) prevents slow queries in production. It also forces you to think about query patterns before building the data access layer.
Revision Notes
Key Takeaways
- 1. Define scope with MoSCoW before coding—Must Haves form the MVP, everything else is negotiable
- 2. Write user stories with acceptance criteria to turn vague ideas into testable requirements
- 3. Design system architecture and API contracts on paper first to avoid costly refactors
- 4. Use story points for estimation and track velocity across sprints for accurate forecasting
- 5. A strong Definition of Done prevents technical debt by making quality standards explicit and enforceable
- 6. Choose tech stack based on a structured decision matrix, not hype or personal preference
Interview Tips
- • Walk through how you would scope a project from a one-paragraph product brief—interviewers want to see structured thinking
- • Explain MoSCoW prioritization with a concrete example and justify why certain features are Must Haves vs Should Haves
- • Describe your system architecture from memory—draw the diagram showing client, API, database, and cache layers
- • Discuss tradeoffs when choosing between PostgreSQL and MongoDB for a given use case—show you understand both
- • Explain why you would use story points instead of hour estimates and how velocity tracking works over multiple sprints
- • Be ready to describe your Definition of Done and why each item on the checklist matters for production readiness
Cheat Sheet
Scope: MoSCoW → Must (MVP), Should (important), Could (nice), Won't (out). User stories: As a [role], I want [feature], so that [benefit]. Architecture: Client (React) → API (Express) → DB (PostgreSQL) + Cache (Redis). Schema: design indexes during migration, not after slow queries. Estimation: Fibonacci story points (1,2,3,5,8,13), track velocity over sprints. Sprint plan: Foundation → Core → Collaboration → Polish. Definition of Done: code reviewed, tests passing, no TS errors, docs updated, deployed to staging. Tech stack decision: score each option 1-5 on ecosystem, performance, learning curve, team familiarity—highest total wins.