- Full IDE with terminal integration using xterm.js - Session management with local and web sessions - HTML preview functionality - Multi-terminal support with session picker Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
7.3 KiB
7.3 KiB
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
{
_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)
{
...
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:
- User selects project →
projectIdstored - Session added to project's
sessionIdsarray - Project
lastActivityupdated
Smart Suggestions
Calculated when moving sessions:
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:
// 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:
await db.projects.updateOne({ _id }, { $set: { deletedAt: null } });
await db.sessions.updateMany({ projectId }, { $set: { deletedAt: null } });
Permanent Delete:
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
// 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