7e47e4aca7
Migrations 037 (workflow tables + 3 seed definitions) + 038 (output_types.workflow_definition_id). WorkflowDefinition/Run/NodeResult SQLAlchemy models in domains/rendering/models.py. workflow_builder.py: dispatch_workflow() with Celery Canvas for still/turntable/multi_angle. workflow_router.py: CRUD endpoints at /api/workflows (admin/PM guards). dispatch_service.py: dispatch_render_with_workflow() prefers workflow path when OutputType.workflow_definition_id is set, falls back to legacy dispatch otherwise. main.py: registers workflows_router. models/__init__.py: re-exports WorkflowDefinition, WorkflowRun, WorkflowNodeResult. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
65 lines
3.3 KiB
Python
65 lines
3.3 KiB
Python
"""Add workflow_definitions, workflow_runs, workflow_node_results tables.
|
|
|
|
Revision ID: 037
|
|
Revises: 036
|
|
"""
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
|
|
|
revision = '037'
|
|
down_revision = '036'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
op.create_table('workflow_definitions',
|
|
sa.Column('id', UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')),
|
|
sa.Column('name', sa.String(200), nullable=False),
|
|
sa.Column('output_type_id', UUID(as_uuid=True), sa.ForeignKey('output_types.id', ondelete='SET NULL'), nullable=True),
|
|
sa.Column('config', JSONB, nullable=False, server_default='{}'),
|
|
sa.Column('is_active', sa.Boolean, nullable=False, server_default='true'),
|
|
sa.Column('created_at', sa.DateTime, nullable=False, server_default=sa.text('NOW()')),
|
|
)
|
|
|
|
op.create_table('workflow_runs',
|
|
sa.Column('id', UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')),
|
|
sa.Column('workflow_def_id', UUID(as_uuid=True), sa.ForeignKey('workflow_definitions.id', ondelete='SET NULL'), nullable=True),
|
|
sa.Column('order_line_id', UUID(as_uuid=True), sa.ForeignKey('order_lines.id', ondelete='CASCADE'), nullable=True),
|
|
sa.Column('celery_task_id', sa.String(500), nullable=True),
|
|
sa.Column('status', sa.String(50), nullable=False, server_default='pending'),
|
|
sa.Column('started_at', sa.DateTime, nullable=True),
|
|
sa.Column('completed_at', sa.DateTime, nullable=True),
|
|
sa.Column('error_message', sa.Text, nullable=True),
|
|
sa.Column('created_at', sa.DateTime, nullable=False, server_default=sa.text('NOW()')),
|
|
)
|
|
op.create_index('ix_workflow_runs_order_line', 'workflow_runs', ['order_line_id'])
|
|
op.create_index('ix_workflow_runs_status', 'workflow_runs', ['status'])
|
|
|
|
op.create_table('workflow_node_results',
|
|
sa.Column('id', UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')),
|
|
sa.Column('run_id', UUID(as_uuid=True), sa.ForeignKey('workflow_runs.id', ondelete='CASCADE'), nullable=False),
|
|
sa.Column('node_name', sa.String(200), nullable=False),
|
|
sa.Column('status', sa.String(50), nullable=False, server_default='pending'),
|
|
sa.Column('output', JSONB, nullable=True),
|
|
sa.Column('log', sa.Text, nullable=True),
|
|
sa.Column('duration_s', sa.Float, nullable=True),
|
|
sa.Column('created_at', sa.DateTime, nullable=False, server_default=sa.text('NOW()')),
|
|
)
|
|
op.create_index('ix_workflow_node_results_run', 'workflow_node_results', ['run_id'])
|
|
|
|
# Seed standard workflow definitions
|
|
op.execute("""
|
|
INSERT INTO workflow_definitions (name, config, is_active) VALUES
|
|
('Still-Render', '{"type": "still", "params": {"render_engine": "cycles", "samples": 256, "resolution": [2048, 2048]}}', true),
|
|
('Turntable-Animation', '{"type": "turntable", "params": {"render_engine": "cycles", "samples": 64, "fps": 24, "duration_s": 5}}', true),
|
|
('Multi-Angle', '{"type": "multi_angle", "params": {"render_engine": "cycles", "samples": 128, "angles": [0, 45, 90, 135, 180]}}', true)
|
|
""")
|
|
|
|
|
|
def downgrade():
|
|
op.drop_table('workflow_node_results')
|
|
op.drop_table('workflow_runs')
|
|
op.drop_table('workflow_definitions')
|