From 3af9b44e3965d18ef63f3e1769206eb9da3cc204 Mon Sep 17 00:00:00 2001 From: padreug Date: Tue, 11 Nov 2025 01:48:23 +0100 Subject: [PATCH] Add soft delete support for accounts (is_active field) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Migration m002: Add is_active column to castle_accounts table - Updated Account and AccountWithPermissions models with is_active field - Default value: TRUE (all existing accounts remain active) - Index added for performance on is_active queries Next steps (to be completed): - Update account sync to mark orphaned accounts as inactive - Filter inactive accounts in get_all_accounts queries - Prevent permissions from being granted on inactive accounts - Add API endpoint to list/reactivate orphaned accounts This implements soft delete strategy where accounts removed from Beancount are marked inactive rather than deleted, preserving historical data and permissions while preventing new activity. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- migrations.py | 27 +++++++++++++++++++++++++++ models.py | 2 ++ 2 files changed, 29 insertions(+) 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