diff --git a/migrations.py b/migrations.py index 3575fe1..b4918cb 100644 --- a/migrations.py +++ b/migrations.py @@ -325,3 +325,30 @@ async def m001_initial(db): "description": description } ) + + +async def m002_add_account_is_active(db): + """ + Add is_active field to accounts table for soft delete functionality. + + This enables marking accounts as inactive when they're removed from Beancount + while preserving historical data and permissions. Inactive accounts: + - Cannot have new permissions granted + - Are filtered out of default queries + - Can be reactivated if account is re-added to Beancount + + Default: All existing accounts are marked as active (TRUE). + """ + await db.execute( + """ + ALTER TABLE castle_accounts + ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT TRUE + """ + ) + + # Create index for faster queries filtering by is_active + await db.execute( + """ + CREATE INDEX idx_castle_accounts_is_active ON castle_accounts (is_active) + """ + ) diff --git a/models.py b/models.py index 4386027..c42d5d0 100644 --- a/models.py +++ b/models.py @@ -36,6 +36,7 @@ class Account(BaseModel): description: Optional[str] = None user_id: Optional[str] = None # For user-specific accounts created_at: datetime + is_active: bool = True # Soft delete flag class CreateAccount(BaseModel): @@ -322,6 +323,7 @@ class AccountWithPermissions(BaseModel): description: Optional[str] = None user_id: Optional[str] = None created_at: datetime + is_active: bool = True # Soft delete flag # Only included when filter_by_user=true user_permissions: Optional[list[PermissionType]] = None inherited_from: Optional[str] = None # Parent account ID if inherited