Skip to content
Merged

Dev #20

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 92 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ With CommitFlow, you can **plan, track, and analyze your projects** — all in o

---

## ![CommitFlow Preview](./images/commitflow.jpg)

| Chat 1 | Chat 2 |
| ---------------------------------- | ---------------------------------- |
| ![](./images/commitflow-chat1.jpg) | ![](./images/commitflow-chat2.jpg) |

---

## 📁 Folder Structure

```
Expand All @@ -31,7 +39,15 @@ With CommitFlow, you can **plan, track, and analyze your projects** — all in o

## ✨ Features

### 🔧 Project Management
### 🤖 AI-Powered Insights

- 💡 **AI Recommendations** – Get automatic suggestions for prioritization and sprint planning.
- 🧠 **Smart Summaries** – Let AI summarize repository activity and project status.
- 🗣️ **Insight Chatbot** – Ask questions like “which tasks are in progress??” or “who contributed the most to the commitflow repo?”

---

### 🧭 Project Management

A beautiful, AI-assisted workspace for managing your projects and tasks:

Expand All @@ -45,14 +61,38 @@ A beautiful, AI-assisted workspace for managing your projects and tasks:
- **Inline comments** with author, timestamp, and preview links
- 🎨 **Smart Selectors** –
- Assignee and Priority fields powered by **React Select**, dynamically colored per user or priority level
- 🧍 **Team Management** –
Add or remove team members using modern UI components, with color-coded avatars automatically generated.
- 🗃️ **Workspace Management** –
Add workspace.
- 🧱 **Project Management Sidebar** –
- Create or delete projects easily
- Integrated **SweetAlert2** confirmations for safe deletions
- 🧍 **Team Management** –
Add or remove team members using modern UI components, with color-coded avatars automatically generated.
- **Toast notifications** (`react-toastify`) for success actions (e.g., project or member added)
- 🌙 **Dark/Light Mode Aware** –
Smooth color transitions and well-tuned contrast for both themes.
- Due date labels: **Due Today** & **Overdue**
- Filter **Assigned to Me**

---

### 💬 Team Coordination

- **Follow up tasks via WhatsApp**
- Generates dynamic `wa.me` link (manual click — no API yet)
- Pre-filled message with task title & status
- Real-time collaboration coming soon
- **Follow up tasks via WhatsApp**
- **Automatic email notifications** sent to team members when tasks are updated
- **Invite team members via email** with secure join links

---

### 🔄 Offline‑First Sync

- Works seamlessly **without internet**
- Local storage caching (offline‑first approach)
- Auto‑synchronization when back online

---

Expand All @@ -64,19 +104,60 @@ A beautiful, AI-assisted workspace for managing your projects and tasks:

---

### 🤖 AI-Powered Insights
### 🎨 Interactive UI

- 💡 **AI Recommendations** – Get automatic suggestions for prioritization and sprint planning.
- 🧠 **Smart Summaries** – Let AI summarize repository activity and project status.
- 🗣️ **Insight Chatbot** – Ask questions like “Who’s most active this week?” or “Which repo grew fastest?”
- Smooth animations
- Responsive layout
- Clean, minimalist UX with focus on productivity

---

### 🐳 Infrastructure & Security
## 🛠️ Tech Stack

### Frontend

- React + Vite
- TypeScript
- TailwindCSS
- Zustand (State Management)
- LocalStorage / IndexedDB (Offline Sync)
- React Query (Data Fetching & Sync Management)
- Socket.IO Client (Real-time updates)
- React Quill (Rich Text Editor)
- SweetAlert2 (Dialogs)
- React Toastify (Notifications)
- Framer Motion / GSAP (Animations & interactive UI)
- XLSX (Export Excel)

### Backend

- Nest.js
- TypeScript
- Prisma ORM
- PostgreSQL
- Socket.IO Gateway (Real-time events)
- Nodemailer (Email Delivery via SMTP)
- Multer (File upload middleware)
- Class Validator / Class Transformer
- Swagger (API documentation)
- Google TTS API
- AWS SDK for S3 Storage
- JWT Authentication (Access & Refresh Tokens)
- OpenAI API Integration (AI features / content generation)

---

- 🧩 **PostgreSQL Storage** – Store structured task and analytics data.
- 🔐 **Environment Management** – Secure credentials via `.env` file.
- ⚙️ **Docker Ready** – Run everything locally or in production with one command.
## 🐳 Infrastructure & Security (Updated)

- 🗄️ **PostgreSQL Database** – Structured project and task data.
- ☁️ **AWS S3 Storage** – Media & attachments.
- ✉️ **SMTP Email (Nodemailer)** – Invitations & notifications.
- 🔐 **Environment Variables (.env)** – Secure credential management.
- 📡 **WebSocket Gateway** – Realtime updates via Socket.IO.
- 🔑 **JWT Authentication** – Secure login, workspace access, and API protection.
- 🤖 **OpenAI Integration** – AI-driven generation (text, automation, suggestions).
- 📁 **LocalStorage + IndexedDB** – Offline-first data with auto-sync.
- 📘 **Swagger UI** – API documentation.

---

Expand Down
42 changes: 25 additions & 17 deletions backend/src/ai-agent/ask.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class AskService {
if (socket) {
socket.emit("ai_thinking", {
type: "tool_call",
message: `🤖 CommitFlow memproses permintaan tool: ${tool}`,
message: `🤖 CommitFlow is processing the tool request: ${tool}`,
tool,
args,
});
Expand All @@ -51,7 +51,7 @@ export class AskService {
if (socket) {
socket.emit("ai_thinking", {
type: "tool_result",
message: `📊 Hasil tool ${tool} siap.`,
message: `📊 Tool result for ${tool} is ready.`,
tool,
result,
});
Expand All @@ -62,7 +62,7 @@ export class AskService {
if (socket) {
socket.emit("ai_thinking", {
type: "done",
message: `✅ Semua proses selesai.`,
message: `✅ All processes completed.`,
});
}
}
Expand All @@ -71,32 +71,32 @@ export class AskService {
* Helper: execute a tool by name (serial)
* Returns the raw tool result (JS object/array) or { error: ... }
*/
private async execToolByName(fn: string, args: any, userId: string) {
private async execToolByName(fn: string, args: any) {
try {
if (fn === "getRepos") {
return await getRepos();
} else if (fn === "getContributors") {
return await getContributors(args.repo);
} else if (fn === "getProjects") {
return await getProjects(userId);
return await getProjects(args.workspaceId);
} else if (fn === "getMembers") {
return await getMembers(userId);
return await getMembers(args.workspaceId);
} else if (fn === "getAllTasks") {
return await getAllTasks(args?.projectId || "", userId);
return await getAllTasks(args?.projectId);
} else if (fn === "getTodoTasks") {
return await getTodoTasks(args?.projectId || "", userId);
return await getTodoTasks(args?.projectId);
} else if (fn === "getInProgressTasks") {
return await getInProgressTasks(args?.projectId || "", userId);
return await getInProgressTasks(args?.projectId);
} else if (fn === "getDoneTasks") {
return await getDoneTasks(args?.projectId || "", userId);
return await getDoneTasks(args?.projectId);
} else if (fn === "getUnassignedTasks") {
return await getUnassignedTasks(args?.projectId || "", userId);
return await getUnassignedTasks(args?.projectId);
} else if (fn === "getUrgentTasks") {
return await getUrgentTasks(args?.projectId || "", userId);
return await getUrgentTasks(args?.projectId);
} else if (fn === "getLowTasks") {
return await getLowTasks(args?.projectId || "", userId);
return await getLowTasks(args?.projectId);
} else if (fn === "getMediumTasks") {
return await getMediumTasks(args?.projectId || "", userId);
return await getMediumTasks(args?.projectId);
} else {
return { error: `Unknown tool: ${fn}` };
}
Expand Down Expand Up @@ -132,6 +132,14 @@ export class AskService {
content: SYSTEM_MESSAGE,
},
...userMessages.map((msg) => ({ role: msg.role, content: msg.content })),
{
role: "system",
content: `User Selected Workspace ID: ${data.workspaceId}`,
},
{
role: "system",
content: `User Selected Project ID: ${data.projectId}`,
},
...data.messages,
];

Expand Down Expand Up @@ -223,7 +231,7 @@ export class AskService {
} else {
// Execute actual tool
this.emitToolCall(socket, fn, args);
toolResult = await this.execToolByName(fn, args, userId ?? "");
toolResult = await this.execToolByName(fn, args);
this.emitToolResult(socket, fn, toolResult);

// push tool result into conversation
Expand Down Expand Up @@ -289,7 +297,7 @@ export class AskService {

messages.push({
role: "system",
content: "buatkan summary dari hasil tools call jika ada",
content: "generate a summary of the tool call results if available",
});
// === At this point, modelMessage does NOT request tools anymore ===
// Start SSE streaming final answer. Ensure we include tools & tool_choice
Expand Down Expand Up @@ -379,7 +387,7 @@ export class AskService {
choices: [
{
delta: {
content: `Terjadi kesalahan: ${
content: `An error occurred: ${
error?.message || String(error)
}`,
},
Expand Down
1 change: 0 additions & 1 deletion backend/src/ai-agent/messages/messages.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export class MessagesController {

@Delete(":id")
delete(@Req() req: any, @Param("id") id: string) {
console.log("delete message id: ", id);
const userId = req.user.userId; // <-- ambil userId dari JWT
return this.messagesService.delete(userId, id);
}
Expand Down
Loading