Initial commit: Clean DSS implementation

Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm

Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)

Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability

Migration completed: $(date)
🤖 Clean migration with full functionality preserved
This commit is contained in:
Digital Production Factory
2025-12-09 18:45:48 -03:00
commit 276ed71f31
884 changed files with 373737 additions and 0 deletions

View File

@@ -0,0 +1,295 @@
#!/usr/bin/env python3
"""
DSS Database Migration Runner
This script runs SQL migrations in the correct order, with proper error handling
and transaction safety.
Usage:
python run_migrations.py # Run all pending migrations
python run_migrations.py --check # Show pending migrations only
python run_migrations.py --rollback 0001 # Rollback specific migration (CAREFUL!)
"""
import os
import sys
import sqlite3
import argparse
from pathlib import Path
from datetime import datetime
import json
# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))
class MigrationRunner:
"""Manages database migrations with version tracking and rollback support"""
def __init__(self, db_path: Path = None):
"""
Initialize migration runner
Args:
db_path: Path to database file. If None, uses default DSS location.
"""
if db_path is None:
# Default DSS database location
db_path = Path.cwd() / ".dss" / "dss.db"
self.db_path = Path(db_path)
self.migrations_dir = Path(__file__).parent.parent / "dss" / "storage" / "migrations"
self.migrations_table = "_dss_migrations"
def _ensure_migrations_table(self, conn: sqlite3.Connection):
"""Create migrations tracking table if it doesn't exist"""
conn.execute(f"""
CREATE TABLE IF NOT EXISTS {self.migrations_table} (
id TEXT PRIMARY KEY,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
description TEXT,
checksum TEXT,
status TEXT DEFAULT 'applied'
)
""")
conn.commit()
def _get_migration_checksum(self, migration_file: Path) -> str:
"""Calculate checksum of migration file for integrity verification"""
import hashlib
content = migration_file.read_text()
return hashlib.sha256(content.encode()).hexdigest()
def _get_applied_migrations(self, conn: sqlite3.Connection) -> dict:
"""Get dictionary of applied migrations"""
cursor = conn.execute(f"SELECT id, checksum FROM {self.migrations_table}")
return {row[0]: row[1] for row in cursor.fetchall()}
def _get_pending_migrations(self) -> list:
"""Get list of pending migrations in order"""
applied = {}
try:
conn = sqlite3.connect(self.db_path)
self._ensure_migrations_table(conn)
applied = self._get_applied_migrations(conn)
conn.close()
except Exception as e:
print(f"Warning: Could not read migration history: {e}")
pending = []
if self.migrations_dir.exists():
for migration_file in sorted(self.migrations_dir.glob("*.sql")):
migration_id = migration_file.stem # e.g., "0002_add_uuid_columns"
if migration_id not in applied:
pending.append({
'id': migration_id,
'file': migration_file,
'checksum': self._get_migration_checksum(migration_file),
'status': 'pending'
})
return pending
def check(self) -> bool:
"""Check for pending migrations without applying them"""
pending = self._get_pending_migrations()
if not pending:
print("✓ No pending migrations - database is up to date")
return True
print(f"Found {len(pending)} pending migration(s):\n")
for migration in pending:
print(f" - {migration['id']}")
print(f" File: {migration['file'].name}")
print(f" Checksum: {migration['checksum'][:16]}...")
return False
def run(self, dry_run: bool = False) -> bool:
"""
Run all pending migrations
Args:
dry_run: If True, show migrations but don't apply them
Returns:
True if successful, False if any migration failed
"""
pending = self._get_pending_migrations()
if not pending:
print("✓ No pending migrations - database is up to date")
return True
print(f"Found {len(pending)} pending migration(s)")
if dry_run:
print("\nDRY RUN - No changes will be applied\n")
else:
print("Running migrations...\n")
# Backup database before running migrations
if not dry_run:
backup_path = self.db_path.with_suffix(f".backup-{datetime.now().strftime('%Y%m%d-%H%M%S')}")
import shutil
try:
shutil.copy2(self.db_path, backup_path)
print(f"✓ Database backed up to: {backup_path}\n")
except Exception as e:
print(f"✗ Failed to create backup: {e}")
print(" Aborting migration")
return False
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
self._ensure_migrations_table(conn)
try:
for migration in pending:
migration_id = migration['id']
migration_file = migration['file']
print(f"Running: {migration_id}")
# Read migration SQL
sql_content = migration_file.read_text()
if not dry_run:
try:
# Execute migration with transaction
conn.executescript(sql_content)
# Record migration as applied
conn.execute(f"""
INSERT INTO {self.migrations_table}
(id, description, checksum, status)
VALUES (?, ?, ?, 'applied')
""", (migration_id, migration_file.name, migration['checksum']))
conn.commit()
print(f" ✓ Migration applied successfully\n")
except sqlite3.Error as e:
conn.rollback()
print(f" ✗ Migration failed: {e}")
print(f" ✗ Changes rolled back")
return False
else:
# Dry run: just show what would happen
print(" (DRY RUN - Would execute)")
lines = sql_content.split('\n')[:5] # Show first 5 lines
for line in lines:
if line.strip() and not line.strip().startswith('--'):
print(f" {line[:70]}")
if len(sql_content.split('\n')) > 5:
print(f" ... ({len(sql_content.split(chr(10)))} lines total)")
print()
if not dry_run:
print("\n✓ All migrations applied successfully")
return True
else:
print("✓ Dry run complete - no changes made")
return True
finally:
conn.close()
def status(self) -> None:
"""Show migration status"""
try:
conn = sqlite3.connect(self.db_path)
self._ensure_migrations_table(conn)
cursor = conn.execute(f"""
SELECT id, applied_at, status FROM {self.migrations_table}
ORDER BY applied_at
""")
applied = cursor.fetchall()
print(f"Applied migrations ({len(applied)}):\n")
if applied:
for row in applied:
print(f"{row[0]}")
print(f" Applied at: {row[1]}")
else:
print(" (none)")
pending = self._get_pending_migrations()
print(f"\nPending migrations ({len(pending)}):\n")
if pending:
for migration in pending:
print(f"{migration['id']}")
else:
print(" (none)")
conn.close()
except Exception as e:
print(f"Error reading migration status: {e}")
def main():
parser = argparse.ArgumentParser(
description="DSS Database Migration Runner",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python run_migrations.py # Run all pending migrations
python run_migrations.py --check # Check for pending migrations
python run_migrations.py --dry-run # Show what would be applied
python run_migrations.py --status # Show migration status
"""
)
parser.add_argument(
'--check',
action='store_true',
help='Check for pending migrations without applying them'
)
parser.add_argument(
'--dry-run',
action='store_true',
help='Show migrations that would be applied without applying them'
)
parser.add_argument(
'--status',
action='store_true',
help='Show migration status (applied and pending)'
)
parser.add_argument(
'--db',
type=Path,
help='Path to database file (default: .dss/dss.db)'
)
args = parser.parse_args()
runner = MigrationRunner(db_path=args.db)
try:
if args.status:
runner.status()
return 0
elif args.check:
success = runner.check()
return 0 if success else 1
elif args.dry_run:
success = runner.run(dry_run=True)
return 0 if success else 1
else:
# Run migrations
success = runner.run(dry_run=False)
return 0 if success else 1
except KeyboardInterrupt:
print("\nMigration cancelled by user")
return 1
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
return 1
if __name__ == '__main__':
sys.exit(main())