# Project and Session Organization Design **Date:** 2025-01-19 **Status:** Approved **Author:** Claude (with user collaboration) ## Overview Introduce persistent projects as first-class entities that contain multiple sessions, with intelligent assignment, reorganization, and soft-delete capabilities. ## Architecture ### Data Model **Projects Collection** ```javascript { _id: ObjectId, name: "My API Project", description: "REST API development", icon: "🚀", color: "#4a9eff", path: "/home/uroma/api", sessionIds: [ObjectId, ...], createdAt: Date, lastActivity: Date, deletedAt: Date | null // null = active, Date = in recycle bin } ``` **Sessions Collection (Updated)** ```javascript { ... projectId: ObjectId | null, // null = unassigned deletedAt: Date | null } ``` ### API Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/projects` | List active projects | | POST | `/api/projects` | Create project | | PUT | `/api/projects/:id` | Update project | | DELETE | `/api/projects/:id` | Soft delete (move to recycle bin) | | POST | `/api/projects/:id/restore` | Restore from bin | | DELETE | `/api/projects/:id/permanent` | Permanent delete | | GET | `/api/recycle-bin` | List deleted items | | POST | `/api/sessions/:id/move` | Move session to different project | ## UI Components ### Projects Page (`/projects`) - **Header**: Title, "+ New Project" button, search bar - **Project Grid**: Cards with icon, name, description, path, session count, last activity - **Context Menu**: Edit, move to recycle bin - **Empty State**: "No projects yet" with CTA ### Enhanced Landing Page (`/claude/`) Projects as top-level, sessions nested inside: - Collapsible project sections - "Unassigned Sessions" section at bottom - Session cards show project badge - Right-click for context menu ### Session Context Menu ``` ┌─────────────────────────┐ │ Open in IDE │ │ ─────────────────────── │ │ Move to Project ▶ │ │ ├── 🚀 My API (🎯 95%)│ │ ├── 📱 Mobile App │ │ ├── ──────────────────│ │ └── Show All Projects │ │ ─────────────────────── │ │ Duplicate │ │ Delete │ └─────────────────────────┘ ``` ### Recycle Bin - Accessible from projects page header - Shows deleted projects with faded sessions - "Restore" and "Delete Permanently" buttons per item ## Smart Assignment Algorithm ### Auto-Assignment When creating a session from the IDE project selector: 1. User selects project → `projectId` stored 2. Session added to project's `sessionIds` array 3. Project `lastActivity` updated ### Smart Suggestions Calculated when moving sessions: ```javascript function getSuggestions(session, allProjects) { const suggestions = []; for (const project of allProjects) { let score = 0; let reasons = []; // Directory matching (high weight) if (session.workingDir === project.path) { score += 90; reasons.push('Same directory'); } else if (session.workingDir?.startsWith(project.path)) { score += 50; reasons.push('Subdirectory'); } // Recency (medium weight) const daysSinceActivity = (Date.now() - project.lastActivity) / (1000 * 60 * 60 * 24); if (daysSinceActivity < 1) { score += 20; reasons.push('Used today'); } else if (daysSinceActivity < 7) { score += 10; reasons.push(`Used ${Math.floor(daysSinceActivity)} days ago`); } // Name similarity (low weight) if (session.name?.includes(project.name) || project.name.includes(session.name)) { score += 15; reasons.push('Similar name'); } if (score > 0) { suggestions.push({ project, score, reasons }); } } return suggestions.sort((a, b) => b.score - a.score).slice(0, 3); } ``` **Visual Indicators:** - 🎯 90%+ match → Same directory - 📂 50-89% match → Subdirectory or recent use - 💡 10-49% match → Similar name or recently used ## Recycle Bin System ### Soft Delete Flow **Delete:** ```javascript // Mark project as deleted await db.projects.updateOne( { _id: projectId }, { $set: { deletedAt: new Date() } } ); // Soft delete all sessions in project await db.sessions.updateMany( { projectId }, { $set: { deletedAt: new Date() } } ); ``` **Restore:** ```javascript await db.projects.updateOne({ _id }, { $set: { deletedAt: null } }); await db.sessions.updateMany({ projectId }, { $set: { deletedAt: null } }); ``` **Permanent Delete:** ```javascript await db.projects.deleteOne({ _id }); await db.sessions.deleteMany({ projectId }); ``` ## Edge Cases | Scenario | Behavior | |----------|----------| | Reassigning from deleted project | Session becomes unassigned (projectId = null) | | Deleting last session in project | Project persists with 0 sessions | | Two projects with same path | Both shown as suggestions with equal score | | Local CLI sessions | Can be assigned, path read from info.json | | Moving to deleted project | Blocked - deleted projects excluded from menu | | Concurrent edits | Last write wins (MongoDB atomic updates) | ## Implementation ### File Structure ``` server.js (add endpoints) public/claude-ide/ ├── projects.html (new) ├── projects.js (new) ├── projects.css (new) └── sessions-landing.js (modify) context-menu.js (new shared component) ``` ### Migration Script ```javascript // 1. Create projects collection db.createCollection('projects'); // 2. Find unique project names from existing sessions const uniqueProjects = await db.sessions.distinct('metadata.project'); // 3. Create project for each unique name for (const name of uniqueProjects) { const projectSessions = await db.sessions.find({ 'metadata.project': name }).toArray(); const paths = [...new Set(projectSessions.map(s => s.workingDir).filter(Boolean))]; await db.projects.insertOne({ name, description: '', icon: getRandomIcon(), color: getRandomColor(), path: paths[0] || '', sessionIds: projectSessions.map(s => s._id), createdAt: projectSessions[0].createdAt, lastActivity: Math.max(...projectSessions.map(s => s.lastActivity)), deletedAt: null }); } // 4. Update sessions with projectId for (const project of await db.projects.find().toArray()) { await db.sessions.updateMany( { 'metadata.project': project.name }, { $set: { projectId: project._id } } ); } ``` ## Testing Checklist - [ ] Create project via inline form - [ ] Auto-assign session on creation - [ ] Smart suggestions calculate correctly - [ ] Move session via context menu - [ ] Delete project → goes to recycle bin - [ ] Restore project from bin - [ ] Permanent delete works - [ ] Unassigned sessions display correctly - [ ] Migration backfills existing data - [ ] Icon/color randomization works - [ ] Path validation on project creation