Integrate account sync with API, background tasks, and user creation

Integration Components:
1. Manual API Endpoints (admin-only):
   - POST /api/v1/admin/accounts/sync (full sync)
   - POST /api/v1/admin/accounts/sync/{account_name} (single account)

2. Scheduled Background Sync:
   - Hourly background task (wait_for_account_sync)
   - Registered in castle_start() lifecycle
   - Automatically syncs new accounts from Beancount to Castle DB

3. Auto-sync on User Account Creation:
   - Updated get_or_create_user_account() in crud.py
   - Uses sync_single_account_from_beancount() for consistency
   - Ensures receivable/payable accounts are synced when users register

Flow:
- User associates wallet → creates receivable/payable in Beancount
  → syncs to Castle DB → permissions can be granted
- Admin manually syncs → all Beancount accounts added to Castle DB
- Hourly task → catches any accounts created directly in Beancount

This ensures Beancount remains the source of truth while Castle DB
maintains metadata for permissions and user associations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
padreug 2025-11-11 01:28:59 +01:00
parent cbdd5f3779
commit 4a3922895e
4 changed files with 173 additions and 10 deletions

View file

@ -95,6 +95,59 @@ async def scheduled_daily_reconciliation():
raise
async def scheduled_account_sync():
"""
Scheduled task that runs hourly to sync accounts from Beancount to Castle DB.
This ensures Castle DB stays in sync with Beancount (source of truth) by
automatically adding any new accounts created in Beancount to Castle's
metadata database for permission tracking.
"""
from .account_sync import sync_accounts_from_beancount
logger.info(f"[CASTLE] Running scheduled account sync at {datetime.now()}")
try:
stats = await sync_accounts_from_beancount(force_full_sync=False)
if stats["accounts_added"] > 0:
logger.info(
f"[CASTLE] Account sync: Added {stats['accounts_added']} new accounts"
)
if stats["errors"]:
logger.warning(
f"[CASTLE] Account sync: {len(stats['errors'])} errors encountered"
)
for error in stats["errors"][:5]: # Log first 5 errors
logger.error(f" - {error}")
return stats
except Exception as e:
logger.error(f"[CASTLE] Error in scheduled account sync: {e}")
raise
async def wait_for_account_sync():
"""
Background task that periodically syncs accounts from Beancount to Castle DB.
Runs hourly to ensure Castle DB stays in sync with Beancount.
"""
logger.info("[CASTLE] Account sync background task started")
while True:
try:
# Run sync
await scheduled_account_sync()
except Exception as e:
logger.error(f"[CASTLE] Account sync error: {e}")
# Wait 1 hour before next sync
await asyncio.sleep(3600) # 3600 seconds = 1 hour
def start_daily_reconciliation_task():
"""
Initialize the daily reconciliation task.