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
42 lines
1.5 KiB
Python
42 lines
1.5 KiB
Python
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")
|