Files
resolutionflow/backend/alembic/versions/006_add_folder_hierarchy.py
chihlasm fafdaa50a5 Add tree organization system with categories, tags, and folders
Features:
- Categories: Global and team-specific tree categorization (admin-managed)
- Tags: Flexible tree tagging with autocomplete (author + admin)
- User folders: Personal tree collections with subfolder support
  - Hierarchical structure (max 3 levels deep)
  - Right-click context menu for folder management
  - Cascade delete for subfolders
- Filter trees by category, tags, and folder in library view

Backend:
- New models: Category, Tag, UserFolder with relationships
- New API endpoints for categories, tags, and folders
- Tree organization migrations (005, 006)

Frontend:
- FolderSidebar with hierarchical folder tree
- FolderEditModal for create/edit with color picker
- AddToFolderMenu for quick tree organization
- TagInput with autocomplete and TagBadges display
- Updated TreeMetadataForm and TreeLibraryPage

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 01:31:13 -05:00

55 lines
1.7 KiB
Python

"""Add folder hierarchy support
Revision ID: 006
Revises: 005
Create Date: 2026-02-02
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision: str = '006'
down_revision: Union[str, None] = '005'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# Add parent_id column for folder hierarchy
op.add_column(
'user_folders',
sa.Column(
'parent_id',
postgresql.UUID(as_uuid=True),
sa.ForeignKey('user_folders.id', ondelete='CASCADE'),
nullable=True
)
)
op.create_index('ix_user_folders_parent_id', 'user_folders', ['parent_id'])
# Update unique constraint to allow same name in different parent folders
# Old constraint: (user_id, name) must be unique
# New constraint: (user_id, name, parent_id) must be unique
# This allows folders with same name under different parents
op.drop_constraint('uq_user_folders_user_name', 'user_folders', type_='unique')
op.create_unique_constraint(
'uq_user_folders_user_name_parent',
'user_folders',
['user_id', 'name', 'parent_id']
)
def downgrade() -> None:
# Restore original unique constraint
op.drop_constraint('uq_user_folders_user_name_parent', 'user_folders', type_='unique')
op.create_unique_constraint('uq_user_folders_user_name', 'user_folders', ['user_id', 'name'])
# Remove parent_id column and index
op.drop_index('ix_user_folders_parent_id', table_name='user_folders')
op.drop_column('user_folders', 'parent_id')