diff --git a/ARCHIVE_FEATURE_README.md b/ARCHIVE_FEATURE_README.md new file mode 100644 index 0000000..274d121 --- /dev/null +++ b/ARCHIVE_FEATURE_README.md @@ -0,0 +1,160 @@ +# Project Archive Feature + +## Overview + +The Break It Down (BIT) application now supports archiving projects! This helps you organize your workspace by hiding completed or inactive projects from the main view while keeping them accessible. + +## Features Added + +### 1. **Archive Status** +- Projects can be marked as archived or active +- Archived projects are kept in the database but hidden from the default view +- All tasks and data are preserved when archiving + +### 2. **Tab Navigation** +The main Projects page now has three tabs: +- **Active** (default) - Shows only non-archived projects +- **Archived** - Shows only archived projects +- **All** - Shows all projects regardless of archive status + +### 3. **Quick Actions** +Each project card now has two action buttons: +- **Archive/Unarchive** (đĻ/âŠī¸) - Toggle archive status +- **Delete** (đī¸) - Permanently delete the project + +### 4. **Visual Indicators** +- Archived projects appear with reduced opacity and gray border +- "(archived)" label appears next to archived project names +- Context-aware empty state messages + +## Database Changes + +A new column has been added to the `projects` table: +- `is_archived` (BOOLEAN) - Defaults to `False` for new projects + +## Installation & Migration + +### For New Installations +No action needed! The database will be created with the correct schema automatically. + +### For Existing Databases + +If you have an existing Break It Down database, run the migration script: + +```bash +cd backend +python3 migrate_add_is_archived.py +``` + +This will add the `is_archived` column to your existing projects table and set all existing projects to `is_archived=False`. + +### Restart the Backend + +After migration, restart the backend server to load the updated models: + +```bash +# Stop the current backend process +pkill -f "uvicorn.*backend.main:app" + +# Start the backend again +cd /path/to/break-it-down +uvicorn backend.main:app --host 0.0.0.0 --port 8001 +``` + +Or if using Docker: +```bash +docker-compose restart backend +``` + +## API Changes + +### Updated Endpoint: GET /api/projects + +New optional query parameter: +- `archived` (boolean, optional) - Filter projects by archive status + - `archived=false` - Returns only active projects + - `archived=true` - Returns only archived projects + - No parameter - Returns all projects + +Examples: +```bash +# Get active projects +GET /api/projects?archived=false + +# Get archived projects +GET /api/projects?archived=true + +# Get all projects +GET /api/projects +``` + +### Updated Endpoint: PUT /api/projects/{id} + +New field in request body: +```json +{ + "name": "Project Name", // optional + "description": "Description", // optional + "statuses": [...], // optional + "is_archived": true // optional - new! +} +``` + +### New API Helper Functions + +The frontend API client now includes: +- `archiveProject(id)` - Archive a project +- `unarchiveProject(id)` - Unarchive a project + +## File Changes Summary + +### Backend +- `backend/app/models.py` - Added `is_archived` Boolean column to Project model +- `backend/app/schemas.py` - Updated ProjectUpdate and Project schemas +- `backend/app/main.py` - Added `archived` query parameter to list_projects endpoint +- `backend/app/crud.py` - Updated get_projects to support archive filtering +- `backend/migrate_add_is_archived.py` - Migration script (new file) + +### Frontend +- `frontend/src/pages/ProjectList.jsx` - Added tabs, archive buttons, and filtering logic +- `frontend/src/utils/api.js` - Added archive/unarchive functions and updated getProjects + +## Usage Examples + +### Archive a Project +1. Go to the Projects page +2. Click the archive icon (đĻ) on any project card +3. The project disappears from the Active view +4. Switch to the "Archived" tab to see it + +### Unarchive a Project +1. Switch to the "Archived" tab +2. Click the unarchive icon (âŠī¸) on the project card +3. The project returns to the Active view + +### View All Projects +Click the "All" tab to see both active and archived projects together. + +## Status vs Archive + +**Important distinction:** +- **Task Status** (backlog, in_progress, on_hold, done) - Applied to individual tasks within a project +- **Project Archive** - Applied to entire projects to organize your workspace + +The existing task status "on_hold" is still useful for pausing work on specific tasks, while archiving is for entire projects you want to hide from your main view. + +## Backward Compatibility + +All changes are backward compatible: +- Existing projects will default to `is_archived=false` (active) +- Old API calls without the `archived` parameter still work (returns all projects) +- The frontend gracefully handles projects with or without the archive field + +## Future Enhancements + +Potential additions: +- Archive date tracking +- Bulk archive operations +- Archive projects from the ProjectSettings modal +- Auto-archive projects after X days of inactivity +- Project status badges (active, archived, on-hold, completed) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30f9e5f..f5350e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ # Changelog -All notable changes to TESSERACT will be documented in this file. +All notable changes to Break It Down (BIT) will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.1.6] - 2025-01-25 +## [0.1.6] - 2025-11-25 ### Added - **Dynamic Status Management System** @@ -69,7 +69,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Helper functions for status formatting and color coding - Prop drilling of projectStatuses through component hierarchy -## [0.1.5] - 2025-01-XX +## [0.1.5] - 2025-11-22 ### Added - **Nested Kanban View** - Major feature implementation @@ -238,9 +238,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Project Information -**TESSERACT** - Task Decomposition Engine +**Break It Down (BIT)** - Task Decomposition Engine A self-hosted web application for managing deeply nested todo trees with advanced time tracking and project planning capabilities. -**Repository**: https://github.com/serversdwn/tesseract +**Repository**: https://github.com/serversdwn/break-it-down **License**: MIT **Author**: serversdwn diff --git a/README.md b/README.md index 9599190..68a41f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TESSERACT +# Break It Down - BIT **Task Decomposition Engine** - A self-hosted web application for managing deeply nested todo trees with advanced time tracking and project planning capabilities. @@ -7,7 +7,7 @@ ## Overview -TESSERACT is designed for complex project management where tasks naturally decompose into hierarchical structures. Whether you're breaking down software projects, research tasks, or multi-phase initiatives, TESSERACT helps you visualize, track, and manage work at any level of granularity. +Break It Down is designed for complex project management where tasks naturally decompose into hierarchical structures. Whether you're breaking down software projects, research tasks, or multi-phase initiatives, BIT helps you visualize, track, and manage work at any level of granularity. ### Key Features @@ -33,7 +33,6 @@ TESSERACT is designed for complex project management where tasks naturally decom - **LLM Integration**: Import JSON task trees generated by AI assistants - **Real-Time Search**: Find tasks across projects with filtering - **Self-Hosted**: Full data ownership and privacy -- **Dark Cyberpunk UI**: Orange-accented dark theme optimized for focus ## Tech Stack @@ -55,8 +54,8 @@ TESSERACT is designed for complex project management where tasks naturally decom 1. **Clone the repository** ```bash - git clone https://github.com/serversdwn/tesseract.git - cd tesseract + git clone https://github.com/serversdwn/break-it-down.git + cd break-it-down ``` 2. **Start the application** @@ -166,7 +165,7 @@ The Kanban board displays tasks in a nested hierarchy while maintaining status-b ### Understanding Time Estimates -TESSERACT uses **leaf-based time calculation** for accurate project planning: +Break It Down uses **leaf-based time calculation** for accurate project planning: - **Leaf Tasks** (no subtasks): Display shows their own time estimate - **Parent Tasks** (have subtasks): Display shows sum of ALL descendant leaf tasks @@ -202,7 +201,7 @@ Remaining work: 3h 30m (not 10h!) ### JSON Import -TESSERACT can import task hierarchies from JSON files, making it perfect for LLM-generated project breakdowns. +Break It Down can import task hierarchies from JSON files, making it perfect for LLM-generated project breakdowns. 1. Click "Import JSON" on a project 2. Upload a file matching this structure: @@ -307,7 +306,7 @@ tasks ### Project Structure ``` -tesseract/ +break-it-down/ ââ backend/ â ââ app/ â â ââ main.py # FastAPI application @@ -370,10 +369,10 @@ Frontend will be available at `http://localhost:5173` (Vite default) **Backup:** ```bash # Docker -docker cp tesseract-backend:/app/tesseract.db ./backup.db +docker cp bit-backend:/app/bit.db ./backup.db # Local -cp backend/tesseract.db ./backup.db +cp backend/bit.db ./backup.db ``` **Schema Changes:** @@ -456,8 +455,8 @@ MIT License - see LICENSE file for details ## Support -- **Issues**: https://github.com/serversdwn/tesseract/issues -- **Discussions**: https://github.com/serversdwn/tesseract/discussions +- **Issues**: https://github.com/serversdwn/break-it-down/issues +- **Discussions**: https://github.com/serversdwn/break-it-down/discussions ## Acknowledgments @@ -467,4 +466,4 @@ MIT License - see LICENSE file for details --- -**TESSERACT** - Decompose complexity, achieve clarity. +**Break It Down (BIT)** - Decompose complexity, achieve clarity. diff --git a/backend/.env.example b/backend/.env.example index e7dd4cc..912826a 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,8 +1,8 @@ # Database Configuration -DATABASE_URL=sqlite:///./tesseract.db +DATABASE_URL=sqlite:///./bit.db # API Configuration -API_TITLE=Tesseract - Nested Todo Tree API +API_TITLE=Break It Down (BIT) - Nested Todo Tree API API_DESCRIPTION=API for managing deeply nested todo trees API_VERSION=1.0.0 diff --git a/backend/app/crud.py b/backend/app/crud.py index 9e2e7ca..d3d183a 100644 --- a/backend/app/crud.py +++ b/backend/app/crud.py @@ -21,8 +21,14 @@ def get_project(db: Session, project_id: int) -> Optional[models.Project]: return db.query(models.Project).filter(models.Project.id == project_id).first() -def get_projects(db: Session, skip: int = 0, limit: int = 100) -> List[models.Project]: - return db.query(models.Project).offset(skip).limit(limit).all() +def get_projects(db: Session, skip: int = 0, limit: int = 100, archived: Optional[bool] = None) -> List[models.Project]: + query = db.query(models.Project) + + # Filter by archive status if specified + if archived is not None: + query = query.filter(models.Project.is_archived == archived) + + return query.offset(skip).limit(limit).all() def update_project( diff --git a/backend/app/main.py b/backend/app/main.py index 4505401..ba9dbca 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -30,9 +30,14 @@ app.add_middleware( # ========== PROJECT ENDPOINTS ========== @app.get("/api/projects", response_model=List[schemas.Project]) -def list_projects(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): - """List all projects""" - return crud.get_projects(db, skip=skip, limit=limit) +def list_projects( + skip: int = 0, + limit: int = 100, + archived: Optional[bool] = None, + db: Session = Depends(get_db) +): + """List all projects with optional archive filter""" + return crud.get_projects(db, skip=skip, limit=limit, archived=archived) @app.post("/api/projects", response_model=schemas.Project, status_code=201) @@ -314,6 +319,6 @@ def root(): """API health check""" return { "status": "online", - "message": "Tesseract API - Nested Todo Tree Manager", + "message": "Break It Down (BIT) API - Nested Todo Tree Manager", "docs": "/docs" } diff --git a/backend/app/models.py b/backend/app/models.py index d7eb379..a472d3d 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, JSON +from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, JSON, Boolean from sqlalchemy.orm import relationship from datetime import datetime from .database import Base @@ -15,6 +15,7 @@ class Project(Base): name = Column(String(255), nullable=False) description = Column(Text, nullable=True) statuses = Column(JSON, nullable=False, default=DEFAULT_STATUSES) + is_archived = Column(Boolean, default=False, nullable=False) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 1fce06f..417f0a0 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -60,11 +60,13 @@ class ProjectUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None statuses: Optional[List[str]] = None + is_archived: Optional[bool] = None class Project(ProjectBase): id: int statuses: List[str] + is_archived: bool created_at: datetime updated_at: datetime diff --git a/backend/app/settings.py b/backend/app/settings.py index 631c72b..ec9229e 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -6,10 +6,10 @@ class Settings(BaseSettings): """Application settings loaded from environment variables""" # Database Configuration - database_url: str = "sqlite:///./tesseract.db" + database_url: str = "sqlite:///./bit.db" # API Configuration - api_title: str = "Tesseract - Nested Todo Tree API" + api_title: str = "Break It Down (BIT) - Nested Todo Tree API" api_description: str = "API for managing deeply nested todo trees" api_version: str = "1.0.0" diff --git a/backend/migrate_add_is_archived.py b/backend/migrate_add_is_archived.py new file mode 100644 index 0000000..c0bb9de --- /dev/null +++ b/backend/migrate_add_is_archived.py @@ -0,0 +1,37 @@ +""" +Migration script to add is_archived column to existing projects. +Run this once if you have an existing database. +""" +import sqlite3 +import os + +# Get the database path +db_path = os.path.join(os.path.dirname(__file__), 'bit.db') + +if not os.path.exists(db_path): + print(f"Database not found at {db_path}") + print("No migration needed - new database will be created with the correct schema.") + exit(0) + +# Connect to the database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() + +try: + # Check if the column already exists + cursor.execute("PRAGMA table_info(projects)") + columns = [column[1] for column in cursor.fetchall()] + + if 'is_archived' in columns: + print("Column 'is_archived' already exists. Migration not needed.") + else: + # Add the is_archived column + cursor.execute("ALTER TABLE projects ADD COLUMN is_archived BOOLEAN NOT NULL DEFAULT 0") + conn.commit() + print("Successfully added 'is_archived' column to projects table.") + print("All existing projects have been set to is_archived=False (0).") +except Exception as e: + print(f"Error during migration: {e}") + conn.rollback() +finally: + conn.close() diff --git a/backend/migrate_add_statuses.py b/backend/migrate_add_statuses.py index 8be7a37..802339b 100644 --- a/backend/migrate_add_statuses.py +++ b/backend/migrate_add_statuses.py @@ -10,7 +10,7 @@ DEFAULT_STATUSES = ["backlog", "in_progress", "on_hold", "done"] def migrate(): # Connect to the database - conn = sqlite3.connect('tesseract.db') + conn = sqlite3.connect('bit.db') cursor = conn.cursor() try: diff --git a/docker-compose.yml b/docker-compose.yml index dc9b7e1..2edb874 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,12 +3,12 @@ services: build: context: ./backend dockerfile: Dockerfile - container_name: tesseract-backend + container_name: bit-backend ports: - "8002:8002" volumes: - ./backend/app:/app/app - - tesseract-db:/app + - bit-db:/app env_file: - ./backend/.env environment: @@ -19,7 +19,7 @@ services: build: context: ./frontend dockerfile: Dockerfile - container_name: tesseract-frontend + container_name: bit-frontend ports: - "3002:80" env_file: @@ -29,4 +29,4 @@ services: restart: unless-stopped volumes: - tesseract-db: + bit-db: diff --git a/frontend/index.html b/frontend/index.html index 2418f35..0041ecf 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ -
No projects yet
-Create a new project or import from JSON
++ {activeTab === 'archived' ? 'No archived projects' : 'No projects yet'} +
++ {activeTab === 'archived' + ? 'Archive projects to keep them out of your active workspace' + : 'Create a new project or import from JSON'} +
{project.description}
diff --git a/frontend/src/utils/api.js b/frontend/src/utils/api.js index 2e94812..5589ee2 100644 --- a/frontend/src/utils/api.js +++ b/frontend/src/utils/api.js @@ -22,7 +22,14 @@ async function fetchAPI(endpoint, options = {}) { } // Projects -export const getProjects = () => fetchAPI('/projects'); +export const getProjects = (archived = null) => { + const params = new URLSearchParams(); + if (archived !== null) { + params.append('archived', archived); + } + const queryString = params.toString(); + return fetchAPI(`/projects${queryString ? `?${queryString}` : ''}`); +}; export const getProject = (id) => fetchAPI(`/projects/${id}`); export const createProject = (data) => fetchAPI('/projects', { method: 'POST', @@ -33,6 +40,8 @@ export const updateProject = (id, data) => fetchAPI(`/projects/${id}`, { body: JSON.stringify(data), }); export const deleteProject = (id) => fetchAPI(`/projects/${id}`, { method: 'DELETE' }); +export const archiveProject = (id) => updateProject(id, { is_archived: true }); +export const unarchiveProject = (id) => updateProject(id, { is_archived: false }); // Tasks export const getProjectTasks = (projectId) => fetchAPI(`/projects/${projectId}/tasks`);