𝗕𝘂𝗶𝗹𝗱𝗶𝗻𝗴 𝗮 𝗣𝗿𝗼𝗷𝗲𝗰𝘁 𝗠𝗮𝗻𝗮𝗴𝗲𝗺𝗲𝗻𝘁 𝗧𝗼𝗼𝗹 𝘄𝗶𝘁𝗵 𝗣𝗿𝗶𝘀𝗺𝗮
I am building a collaborative project management tool like Trello.
I am using React, Express.js, PostgreSQL, and Socket.io. Before I write any backend routes, I must design the database schema.
The schema is the foundation. If the schema is wrong, the whole app fails. Here is my breakdown of the Prisma schema design.
𝗧𝗵𝗲 𝗠𝗼𝗱𝗲𝗹𝘀
• User: Stores names, emails, and passwords. I use cuid() for IDs. This creates long, unique strings. It is better than numbers because it does not leak your user count in the URL.
• Project: Holds the project name and description. I made the description optional using a question mark.
• ProjectMember: This is a junction table. It links Users to Projects. Since one user can join many projects, and one project has many users, you need this middle table to manage the many-to-many relationship. I added a unique constraint to prevent the same user from joining a project twice.
• Board: Tasks live inside boards. Boards live inside projects. This hierarchy makes drag-and-drop easy. Moving a task between columns is just a single field update.
• Task: This is the core model. It has two different relations to the User model:
- An assigned user (this is optional).
- A creator (this is required). I had to name these relations explicitly so Prisma knows which is which.
• Comment: Users can leave comments on tasks. I named the relation "author" instead of "user" to keep the code readable.
• Notification: A simple model to track messages for users.
𝗧𝗲𝗰𝗵𝗻𝗶𝗰𝗮𝗹 𝗟𝗲𝘀𝘀𝗼𝗻𝘀 𝗟𝗲𝗮𝗿𝗻𝘁
I ran into several errors while building this. Watch out for these:
- Relation Names: If two fields point to the same model, you must name the relations. If you do not, Prisma will throw an error.
- Nullable Fields: If a relation is optional, you must put a question mark on both the relation field and the foreign key field.
- Syntax Errors: Prisma requires double quotes for string defaults. Single quotes will fail.
- Relation Syntax: Always use the correct syntax: @relation(fields: [localField], references: [remoteField]).
The schema is now migrated. Next, I will build the Express backend and Socket.io setup for real-time updates.
Membangun Alat Manajemen Proyek dari Nol: Dimulai dengan Skema Prisma
Membangun alat manajemen proyek adalah cara yang luar biasa untuk mempelajari berbagai konsep pengembangan perangkat lunak, mulai dari desain database hingga implementasi frontend yang kompleks. Dalam seri ini, kita akan membangun alat manajemen proyek full-stack dari awal.
Kita akan menggunakan teknologi modern seperti:
- Next.js untuk framework frontend dan backend.
- Prisma sebagai ORM (Object-Relational Mapper).
- PostgreSQL sebagai database relasional.
- Tailwind CSS untuk styling.
Langkah pertama dalam membangun aplikasi apa pun adalah menentukan struktur datanya. Di sinilah Prisma Schema memainkan peran penting. Skema ini akan menjadi sumber kebenaran tunggal (single source of truth) untuk model data kita dan hubungan antar entitas.
Menentukan Skema Prisma
Mari kita mulai dengan mendefinisikan model-model utama yang kita butuhkan: User, Project, Task, Comment, dan Attachment.
Berikut adalah skema awal kita:
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
name String?
email String @unique
password String
image String?
projects Project[]
tasks Task[]
comments Comment[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Project {
id String @id @default(cuid())
name String
description String?
status ProjectStatus @default(PLANNING)
ownerId String
owner User @relation(fields: [ownerId], references: [id])
tasks Task[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum ProjectStatus {
PLANNING
ACTIVE
COMPLETED
ARCHIVED
}
model Task {
id String @id @default(cuid())
title String
description String?
status TaskStatus @default(TODO)
priority Priority @default(MEDIUM)
projectId String
project Project @relation(fields: [projectId], references: [id])
assigneeId String?
assignee User? @relation(fields: [assigneeId], references: [id])
comments Comment[]
attachments Attachment[]
dueDate DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum TaskStatus {
TODO
IN_PROGRESS
DONE
}
enum Priority {
LOW
MEDIUM
HIGH
}
model Comment {
id String @id @default(cuid())
content String
taskId String
task Task @relation(fields: [taskId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Attachment {
id String @id @default(cuid())
url String
name String
taskId String
task Task @relation(fields: [taskId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Penjelasan Model
Mari kita bedah model-model yang telah kita buat:
1. Model User
Model ini mewakili pengguna yang akan menggunakan aplikasi kita. Setiap pengguna memiliki email yang unik untuk autentikasi. Pengguna dapat memiliki banyak Project, Task, dan Comment.
2. Model Project
Proyek adalah wadah besar untuk tugas-tugas. Setiap proyek dimiliki oleh seorang User (sebagai owner). Kita juga menggunakan enum untuk ProjectStatus guna membatasi status proyek hanya pada nilai tertentu seperti PLANNING, ACTIVE, COMPLETED, atau ARCHIVED.
3. Model Task
Tugas adalah unit kerja terkecil dalam proyek kita. Sebuah tugas terikat pada satu Project dan dapat ditugaskan kepada satu User (assignee). Kita menggunakan enum untuk TaskStatus dan Priority untuk memberikan struktur pada manajemen tugas.
4. Model Comment
Untuk kolaborasi, kita memerlukan fitur komentar. Pengguna dapat memberikan komentar pada tugas tertentu. Setiap komentar terhubung ke satu Task dan satu User.
5. Model Attachment
Tugas sering kali membutuhkan dokumen atau gambar pendukung. Model Attachment memungkinkan kita menyimpan URL file yang terkait dengan tugas tertentu.
Hubungan (Relationships)
Dalam skema di atas, kita telah menerapkan beberapa jenis relasi:
- One-to-Many (Satu-ke-Banyak): Contohnya, satu
Userdapat memiliki banyakProject. SatuProjectdapat memiliki banyakTask. - One-to-One (Satu-ke-Satu): Meskipun tidak secara eksplisit dalam contoh sederhana ini, kita bisa mengimplementasikannya jika diperlukan (misalnya,
UserProfile).
Dengan skema ini, kita telah membangun fondasi yang kuat untuk aplikasi manajemen proyek kita. Pada artikel berikutnya, kita akan mulai mengatur lingkungan pengembangan dan melakukan migrasi database pertama kita menggunakan Prisma.