Skip to content

Commit bb323a5

Browse files
authored
Merge pull request #30 from asepindrak/dev
Dev
2 parents 485a5e8 + c799127 commit bb323a5

19 files changed

+510
-85
lines changed

.changeset/nice-crabs-find.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"commitflow": patch
3+
---
4+
5+
feat: notification

backend/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "commitflow-api",
3-
"version": "1.1.9",
3+
"version": "1.2.1",
44
"description": "Backend CommitFlow",
55
"author": "asepindrak",
66
"private": false,

backend/prisma/schema.prisma

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -64,26 +64,31 @@ model User {
6464
}
6565

6666
model TeamMember {
67-
id String @id @default(uuid()) // pilih uuid supaya beda style dari user.id
68-
clientId String? @unique
69-
userId String
70-
workspaceId String
71-
name String
72-
role String?
73-
email String?
74-
photo String?
75-
phone String?
76-
isTrash Boolean @default(false)
77-
isAdmin Boolean @default(false)
78-
createdAt DateTime @default(now())
79-
updatedAt DateTime?
80-
Task Task[] @relation("TaskMembers")
81-
TaskCreatedBy Task[] @relation("TaskCreatedBy")
82-
83-
// FK ke Workspace
84-
workspace Workspace? @relation("WorkspaceMembers", fields: [workspaceId], references: [id])
85-
user User? @relation("UserMembers", fields: [userId], references: [id])
67+
id String @id @default(uuid())
68+
clientId String? @unique
69+
userId String
70+
workspaceId String
71+
72+
name String
73+
role String?
74+
email String?
75+
photo String?
76+
phone String?
77+
78+
isTrash Boolean @default(false)
79+
isAdmin Boolean @default(false)
80+
81+
createdAt DateTime @default(now())
82+
updatedAt DateTime?
83+
84+
// 🔗 RELATIONS (HARUS SESUAI NAMA)
85+
assignedTasks Task[] @relation("TaskAssignee")
86+
8687
taskAssignees TaskAssignee[]
88+
89+
// FK
90+
workspace Workspace? @relation("WorkspaceMembers", fields: [workspaceId], references: [id])
91+
user User? @relation("UserMembers", fields: [userId], references: [id])
8792
}
8893

8994
model Workspace {
@@ -112,26 +117,38 @@ model Project {
112117
}
113118

114119
model Task {
115-
id String @id @default(uuid())
116-
title String
117-
description String?
118-
status String @default("todo")
119-
projectId String?
120-
project Project? @relation("ProjectTasks", fields: [projectId], references: [id])
121-
assigneeId String?
122-
startDate String?
123-
dueDate String?
124-
finishDate DateTime?
125-
priority String?
126-
assignee TeamMember? @relation("TaskMembers", fields: [assigneeId], references: [id])
127-
isTrash Boolean @default(false)
128-
comments Comment[] @relation("TaskComments")
129-
clientId String? @unique
130-
createdAt DateTime @default(now())
131-
createdById String?
132-
createdBy TeamMember? @relation("TaskCreatedBy", fields: [createdById], references: [id])
133-
updatedAt DateTime?
120+
id String @id @default(uuid())
121+
title String
122+
description String?
123+
status String @default("todo")
124+
125+
projectId String?
126+
project Project? @relation("ProjectTasks", fields: [projectId], references: [id])
127+
128+
// 👤 ASSIGNEE (legacy single)
129+
assigneeId String?
130+
assignee TeamMember? @relation("TaskAssignee", fields: [assigneeId], references: [id])
131+
132+
// 👥 MULTI ASSIGNEE
134133
taskAssignees TaskAssignee[]
134+
135+
startDate String?
136+
dueDate String?
137+
finishDate DateTime?
138+
priority String?
139+
140+
comments Comment[] @relation("TaskComments")
141+
142+
clientId String? @unique
143+
144+
createdAt DateTime @default(now())
145+
updatedAt DateTime?
146+
147+
// 👤 AUDIT FIELDS (Team Member ID)
148+
createdById String?
149+
updatedById String?
150+
151+
isTrash Boolean @default(false)
135152
}
136153

137154
model TaskAssignee {
@@ -151,6 +168,7 @@ model Comment {
151168
id String @id @default(uuid())
152169
taskId String
153170
task Task @relation("TaskComments", fields: [taskId], references: [id])
171+
memberId String?
154172
author String
155173
body String
156174
attachments Json? // optional JSON array of attachments metadata

backend/src/ai-agent/project.service.ts

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,23 @@ export async function getMembers(workspaceId: string) {
255255
const results = await prisma.teamMember.findMany({
256256
where: { isTrash: false, workspaceId },
257257
include: {
258-
Task: {
259-
where: { isTrash: false },
260-
select: {
261-
id: true,
262-
title: true,
263-
status: true,
264-
projectId: true,
265-
project: {
258+
taskAssignees: {
259+
where: {
260+
task: { isTrash: false }
261+
},
262+
include: {
263+
task: {
266264
select: {
267265
id: true,
268-
name: true,
266+
title: true,
267+
status: true,
268+
projectId: true,
269+
project: {
270+
select: {
271+
id: true,
272+
name: true,
273+
},
274+
},
269275
},
270276
},
271277
},
@@ -274,24 +280,35 @@ export async function getMembers(workspaceId: string) {
274280
orderBy: { name: "asc" },
275281
});
276282

277-
const enriched = results.map((member) => ({
278-
id: member.id,
279-
clientId: member.clientId,
280-
name: member.name,
281-
role: member.role,
282-
email: member.email,
283-
phone: member.phone,
284-
photo: member.photo,
285-
stats: {
286-
total: member.Task.length,
287-
todo: member.Task.filter((t) => t.status === "todo").length,
288-
inprogress: member.Task.filter((t) => t.status === "inprogress").length,
289-
qa: member.Task.filter((t) => t.status === "qa").length,
290-
deploy: member.Task.filter((t) => t.status === "deploy").length,
291-
done: member.Task.filter((t) => t.status === "done").length,
292-
},
293-
tasks: member.Task,
294-
}));
283+
284+
const enriched = results.map((member) => {
285+
// ambil task dari pivot
286+
const tasks = member.taskAssignees
287+
.map((ta) => ta.task)
288+
.filter(Boolean); // safety
289+
290+
return {
291+
id: member.id,
292+
clientId: member.clientId,
293+
name: member.name,
294+
role: member.role,
295+
email: member.email,
296+
phone: member.phone,
297+
photo: member.photo,
298+
299+
stats: {
300+
total: tasks.length,
301+
todo: tasks.filter((t) => t.status === "todo").length,
302+
inprogress: tasks.filter((t) => t.status === "inprogress").length,
303+
qa: tasks.filter((t) => t.status === "qa").length,
304+
deploy: tasks.filter((t) => t.status === "deploy").length,
305+
done: tasks.filter((t) => t.status === "done").length,
306+
},
307+
308+
tasks,
309+
};
310+
});
311+
295312

296313
return enriched;
297314
} catch (error) {

backend/src/app.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import { Injectable } from "@nestjs/common";
33
@Injectable()
44
export class AppService {
55
getHello(): string {
6-
return `CommitFlow API (1.2.0) is running!`;
6+
return `CommitFlow API (1.2.1) is running!`;
77
}
88
}

backend/src/project-management/dto/comment.dto.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export class CreateCommentDto {
77
@IsString()
88
body: string;
99

10+
@IsString()
11+
memberId: string;
12+
1013
@IsOptional()
1114
@IsArray()
1215
attachments?: any[];

backend/src/project-management/dto/task.dto.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ export class CreateTaskDto {
4848
@IsOptional()
4949
@IsString()
5050
clientId?: string | null;
51+
52+
@IsOptional()
53+
@IsString()
54+
createdById?: string | null;
55+
56+
@IsOptional()
57+
@IsString()
58+
updatedById?: string | null;
5159
}
5260

5361
export class UpdateTaskDto {
@@ -84,6 +92,14 @@ export class UpdateTaskDto {
8492
@IsOptional()
8593
@IsString()
8694
dueDate?: string | null;
95+
96+
@IsOptional()
97+
@IsString()
98+
createdById?: string | null;
99+
100+
@IsOptional()
101+
@IsString()
102+
updatedById?: string | null;
87103
}
88104

89105
export class PatchTaskDto {
@@ -120,5 +136,13 @@ export class PatchTaskDto {
120136
@IsOptional()
121137
@IsString()
122138
dueDate?: string | null;
139+
140+
@IsOptional()
141+
@IsString()
142+
createdById?: string | null;
143+
144+
@IsOptional()
145+
@IsString()
146+
updatedById?: string | null;
123147
}
124148

backend/src/project-management/project-management.service.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,8 @@ export class ProjectManagementService {
633633
startDate?: string | null
634634
dueDate?: string | null
635635
clientId?: string | null
636+
createdById?: string | null
637+
updatedById?: string | null
636638
}>
637639
) {
638640
// --------------------------------
@@ -697,6 +699,7 @@ export class ProjectManagementService {
697699
dueDate:
698700
payload.dueDate !== undefined ? payload.dueDate : null,
699701
clientId: payload.clientId ?? null,
702+
createdById: payload.createdById ?? null
700703
},
701704
})
702705

@@ -735,6 +738,8 @@ export class ProjectManagementService {
735738
taskAssignees?: { memberId: string }[]
736739
startDate?: string | null
737740
dueDate?: string | null
741+
createdById?: string | null
742+
updatedById?: string | null
738743
}>,
739744
userId: string
740745
) {
@@ -826,6 +831,8 @@ export class ProjectManagementService {
826831
: existing.dueDate,
827832

828833
updatedAt: new Date(),
834+
835+
updatedById: payload.updatedById,
829836
},
830837
});
831838

@@ -951,6 +958,8 @@ Due Date: ${format(updated.dueDate)}
951958
taskAssignees?: { memberId: string; role?: string }[]
952959
startDate?: string | null;
953960
dueDate?: string | null;
961+
createdById?: string | null;
962+
updatedById?: string | null;
954963
}>,
955964
userId: string
956965
) {
@@ -990,7 +999,7 @@ Due Date: ${format(updated.dueDate)}
990999

9911000
async createComment(
9921001
taskId: string,
993-
payload: { author: string; body: string; attachments?: any[] }
1002+
payload: { author: string; body: string; memberId: string, attachments?: any[] }
9941003
) {
9951004
// -----------------------------
9961005
// GET TASK + ASSIGNEES
@@ -1012,11 +1021,20 @@ Due Date: ${format(updated.dueDate)}
10121021
data: {
10131022
taskId,
10141023
author: payload.author,
1024+
memberId: payload.memberId,
10151025
body: payload.body,
10161026
attachments: payload.attachments ?? undefined,
10171027
},
10181028
})
10191029

1030+
//update task
1031+
const updateTask = await prisma.task.update({
1032+
where: { id: taskId },
1033+
data: {
1034+
updatedById: payload.memberId,
1035+
updatedAt: new Date()
1036+
}
1037+
})
10201038
// -----------------------------
10211039
// GET PROJECT
10221040
// -----------------------------

frontend/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)