Implement complete nested todo tree web app MVP

This commit implements a fully functional self-hosted task decomposition engine with:

Backend (FastAPI + SQLite):
- RESTful API with full CRUD operations for projects and tasks
- Arbitrary-depth hierarchical task structure using self-referencing parent_task_id
- JSON import endpoint for seeding projects from LLM-generated breakdowns
- SQLAlchemy models with proper relationships and cascade deletes
- Status tracking (backlog, in_progress, blocked, done)
- Auto-generated OpenAPI documentation

Frontend (React + Vite + Tailwind):
- Dark cyberpunk theme with orange accents
- Project list page with create/import/delete functionality
- Dual view modes:
  * Tree View: Collapsible hierarchical display with inline editing
  * Kanban Board: Drag-and-drop status management
- Real-time CRUD operations for tasks and subtasks
- JSON import modal with validation
- Responsive design optimized for desktop

Infrastructure:
- Docker setup with multi-stage builds
- docker-compose for orchestration
- Nginx reverse proxy for production frontend
- Named volume for SQLite persistence
- CORS configuration for local development

Documentation:
- Comprehensive README with setup instructions
- Example JSON import file demonstrating nested structure
- API endpoint documentation
- Data model diagrams
This commit is contained in:
Claude
2025-11-19 22:51:42 +00:00
parent bac534ce94
commit 441f62023e
28 changed files with 1977 additions and 0 deletions

41
backend/app/models.py Normal file
View File

@@ -0,0 +1,41 @@
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum
from sqlalchemy.orm import relationship
from datetime import datetime
import enum
from .database import Base
class TaskStatus(str, enum.Enum):
BACKLOG = "backlog"
IN_PROGRESS = "in_progress"
BLOCKED = "blocked"
DONE = "done"
class Project(Base):
__tablename__ = "projects"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), nullable=False)
description = Column(Text, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
tasks = relationship("Task", back_populates="project", cascade="all, delete-orphan")
class Task(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), nullable=False)
parent_task_id = Column(Integer, ForeignKey("tasks.id"), nullable=True)
title = Column(String(500), nullable=False)
description = Column(Text, nullable=True)
status = Column(Enum(TaskStatus), default=TaskStatus.BACKLOG, nullable=False)
sort_order = Column(Integer, default=0)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
project = relationship("Project", back_populates="tasks")
parent = relationship("Task", remote_side=[id], backref="subtasks")