Applies ai-worker's data model discipline. Use for any task touching app/models/**, db/migrate/**, or db/schema.rb — adding/changing fields on Project, Workflow, Stage, StageRun, PromptTemplate, JiraSync or BugsnagSync, their enums, validations, or associations.
Instal·la
npx skillscat add hoang-phan/ai-worker/ai-worker-domain Instal·la des del registre de SkillsCat.
SKILL.md
ai-worker-domain
Scope: app/models/**, db/migrate/**, db/schema.rb. Do not read app/jobs, app/services, app/controllers, or app/views for this work — the model layer has no dependency on them, except where a model calls Prompts::Renderer / AiCli::Output (noted below). db/schema.rb is the source of truth for columns; this file does not repeat them.
File map (the whole scope)
app/models/project.rb— a local checkout plus, forjiraprojects, its GitHub repo.enum :kind, { jira: 0, personal: 1 }(jira = GitHub/PR flow driven by tickets; personal = local-only, one task description per workflow, no PR).has_many :workflows, :jira_syncs, :bugsnag_syncs(alldependent: :destroy). Holds per-project settings, grouped: defaults for new workflows (skills, reviewers), Jira (site URL, assignee, tester), Slack PR review and review pings (enable flag, mention, channels, GitHub→Slack user map), UAT testing (enable flag, URL, login, delay), local pre-review testing (same shape), shared test/CI instructions, and brainstorming (goal, limits, auto-start, last-run bookkeeping). UAT and local passwords are Active Recordencryptscolumns. Validations are conditional on kind or on the feature's enable flag. It also refuses alocal_directorythat is this app's own live checkout (agents branch, merge and migrate inside the clone).app/models/workflow.rb— one unit of automated work for a project.belongs_to :project,has_many :stages(ordered byposition, id).enum :statushas 12 values (pending, implementing, reviewing, done, errored, merged, jira_updated, waiting, uat_waiting, uat_testing, uat_tested, local_testing); the integers are persisted.enum :kindisdevelopment/pr_review/runbook.current_stageis the stage the scheduler should act on. Fordevelopmentworkflows on jira projects it maps status → stage type throughSTAGE_TYPE_BY_STATUS; personal projects and PR-review workflows use their own single-stage maps (SIMPLE_…,PR_REVIEW_…); runbooks usecurrent_stage_id. Stages for post-merge Jira update, UAT test and local test are created lazily the first time they're needed.after_createseeds stages by kind/project type: jira development → implementation + pr_check; personal → task; pr_review → pr_review; runbook → copies of another runbook's stages (copy_stages_from_id) or none.- Runbook state machine lives here:
start_runbook!,advance!(the Next button /auto_advance), next/previous stage helpers,awaiting_next,auto_run, andvariables(JSON; edited asNAME=valuelines viavariables_text;input_variablesvs stage-emittedoutput_variable_names). - Other responsibilities: agent-run tracking columns (pid, log path, start time, log offset,
processing); reference images stored as plain files undertmp/workflow_images/<id>(not Active Storage) and exposed to prompts via{IMAGES};resume_status(where an errored workflow goes back to);label/briefdisplay text;skill_list;tracks_jira_after_merge?;QUEUED_STATUSES/queuedscope used by brainstorming; UAT schedule (uat_test_at) and local-test feedback text. - Validations depend on kind and project kind (ticket/branch/reviewer for jira development, task description for personal, a github.com PR URL for pr_review, placeholder-safe variable names).
app/models/stage.rb— one step of a workflow.enum :stage_typehas 8 values (implementation, pr_check, task, pr_review, jira_update, runbook_step, uat_test, local_test). There is no stage status column: progress is tracked onWorkflow#statusand inStageRunrows.enum :run_mode, { agent, message }(prefixrun_) and thename/channel/auto_advance/wait_for_workflowcolumns are for runbook stages only.promptis a per-stage text override that wins over any template, for any stage type.effective_templateis the explicitly assignedprompt_template, else the firstPromptTemplateof the samestage_type(lowest id) — there is no "active" flag.app/models/stage_run.rb— one audit-log row per action taken on a stage (starts, completions, failures, merge/review/test outcomes, manual resume/rollback, runbook Next…).ACTIONSis the closed set of validactionvalues, enforced by an inclusion validation — add new values there, not ad hoc strings elsewhere.app/models/prompt_template.rb— a reusable prompt body for astage_type(same enum asStage).PLACEHOLDERSlists the{TOKEN}s the UI offers;Prompts::Rendereris what actually substitutes them (including per-workflow custom variables).Prompts::Defaultsholds the built-in fallback bodies for pr_review, jira_update, uat_test and local_test stages when no template exists (Prompts::StagePromptapplies them).has_many :stages, dependent: :nullify.app/models/jira_sync.rb— one Jira query (project and/or parent ticket) for a project, withauto_syncand last-run bookkeeping.app/models/bugsnag_sync.rb— one Bugsnag-project → Jira-project triage with thresholds and aledger(JSON map of already-ticketed errors → Jira keys). Both have anautoscope.app/models/application_record.rb,concerns/— Rails defaults.
Conventions
status/stage_type/kind/run_mode/actionare always closed, enumerable sets (Railsenumor the frozenACTIONSarray) — never a free-text column. Add new states to the existing enum/array rather than a parallel field. Enum integers are persisted: append, never renumber or reorder.StageandPromptTemplateshare the samestage_typemapping — change both together.- Every migration needs an explicit
null: false, default:for anything that drives control flow (status, kind, position,processing, enable flags). The scheduler polls these columns, so an unexpectedNULLbreaks it silently. Follow recent migrations such asdb/migrate/*_add_uat_testing.rb. Data-moving migrations should only touch narrowly selected rows. Workflow#skill_listis the only place that parses theskillstext column; if the format changes, updatePrompts::Renderer's{SKILLS}substitution too (owned byai-worker-orchestration).- New placeholders need both an entry in
PromptTemplate::PLACEHOLDERSand a value inPrompts::Renderer; newStageRun::ACTIONSvalues must be added before any code logs them (an unknown action fails validation). - Describe model behaviour in specs, not by poking the real database. Write RSpec specs under
spec/models/(orspec/services/for service objects) and run them withRAILS_ENV=test bundle exec rspec. Never run scratch scripts,bin/rails runneror console commands against the development database — it holds the user's real projects and workflows. Migrations on the development DB need a backup first and the user's say-so; for tests,RAILS_ENV=testloadsdb/schema.rb.