@atlashub/smartstack-cli 1.17.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/templates/agents/efcore/db-deploy.md +5 -0
  3. package/templates/agents/efcore/db-reset.md +5 -0
  4. package/templates/agents/efcore/db-seed.md +5 -0
  5. package/templates/agents/efcore/db-status.md +5 -0
  6. package/templates/agents/efcore/migration.md +8 -0
  7. package/templates/agents/efcore/rebase-snapshot.md +9 -0
  8. package/templates/agents/efcore/squash.md +50 -20
  9. package/templates/commands/efcore/squash.md +24 -12
  10. package/templates/skills/efcore/SKILL.md +162 -0
  11. package/templates/skills/efcore/steps/db/step-deploy.md +208 -0
  12. package/templates/skills/efcore/steps/db/step-reset.md +259 -0
  13. package/templates/skills/efcore/steps/db/step-seed.md +244 -0
  14. package/templates/skills/efcore/steps/db/step-status.md +198 -0
  15. package/templates/skills/efcore/steps/migration/step-00-init.md +102 -0
  16. package/templates/skills/efcore/steps/migration/step-01-check.md +138 -0
  17. package/templates/skills/efcore/steps/migration/step-02-create.md +144 -0
  18. package/templates/skills/efcore/steps/migration/step-03-validate.md +203 -0
  19. package/templates/skills/efcore/steps/rebase-snapshot/step-00-init.md +173 -0
  20. package/templates/skills/efcore/steps/rebase-snapshot/step-01-backup.md +100 -0
  21. package/templates/skills/efcore/steps/rebase-snapshot/step-02-fetch.md +115 -0
  22. package/templates/skills/efcore/steps/rebase-snapshot/step-03-create.md +108 -0
  23. package/templates/skills/efcore/steps/rebase-snapshot/step-04-validate.md +157 -0
  24. package/templates/skills/efcore/steps/shared/step-00-init.md +266 -0
  25. package/templates/skills/efcore/steps/squash/step-00-init.md +141 -0
  26. package/templates/skills/efcore/steps/squash/step-01-backup.md +120 -0
  27. package/templates/skills/efcore/steps/squash/step-02-fetch.md +168 -0
  28. package/templates/skills/efcore/steps/squash/step-03-create.md +178 -0
  29. package/templates/skills/efcore/steps/squash/step-04-validate.md +174 -0
  30. package/templates/skills/gitflow/steps/step-commit.md +14 -2
  31. package/templates/skills/gitflow/steps/step-finish.md +26 -0
  32. package/templates/skills/gitflow/steps/step-merge.md +8 -3
  33. package/templates/skills/gitflow/steps/step-pr.md +10 -0
  34. package/templates/skills/gitflow/steps/step-start.md +12 -1
  35. package/templates/skills/gitflow/steps/step-sync.md +24 -0
@@ -0,0 +1,157 @@
1
+ ---
2
+ name: step-04-validate
3
+ description: Validate rebase-snapshot - build and test
4
+ next_step: null
5
+ ---
6
+
7
+ # Step 4: Validate
8
+
9
+ ## YOUR TASK:
10
+
11
+ Validate the rebased migration by building and generating a script.
12
+
13
+ **Previous step:** `step-03-create.md`
14
+
15
+ ---
16
+
17
+ ## EXECUTION SEQUENCE:
18
+
19
+ ### 1. Build Project
20
+
21
+ ```bash
22
+ echo "Building project..."
23
+
24
+ dotnet build "$INFRA_PROJECT" --no-restore
25
+
26
+ if [ $? -ne 0 ]; then
27
+ echo ""
28
+ echo "ERROR: Build failed"
29
+ echo "Restoring from backup..."
30
+ cp "$BACKUP_DIR"/*.cs "$MIGRATIONS_DIR/"
31
+ exit 1
32
+ fi
33
+
34
+ echo "Build: OK"
35
+ ```
36
+
37
+ ### 2. Generate Script
38
+
39
+ ```bash
40
+ echo ""
41
+ echo "Generating migration script..."
42
+
43
+ SCRIPT_FILE="$BACKUP_DIR/migration_script.sql"
44
+
45
+ dotnet ef migrations script \
46
+ --context "$DBCONTEXT" \
47
+ --project "$INFRA_PROJECT" \
48
+ --startup-project "$STARTUP_PROJECT" \
49
+ --idempotent \
50
+ --no-build \
51
+ -o "$SCRIPT_FILE"
52
+
53
+ if [ $? -ne 0 ]; then
54
+ echo ""
55
+ echo "ERROR: Script generation failed"
56
+ echo "Restoring from backup..."
57
+ cp "$BACKUP_DIR"/*.cs "$MIGRATIONS_DIR/"
58
+ exit 1
59
+ fi
60
+
61
+ echo "Script: $SCRIPT_FILE"
62
+ ```
63
+
64
+ ### 3. List Migrations
65
+
66
+ ```bash
67
+ echo ""
68
+ echo "Migration list:"
69
+
70
+ dotnet ef migrations list \
71
+ --context "$DBCONTEXT" \
72
+ --project "$INFRA_PROJECT" \
73
+ --startup-project "$STARTUP_PROJECT" \
74
+ --no-build
75
+ ```
76
+
77
+ ### 4. Final Summary
78
+
79
+ ```bash
80
+ FINAL_COUNT=$(find "$MIGRATIONS_DIR" -name "*.cs" 2>/dev/null | grep -v "Designer\|Snapshot" | wc -l)
81
+
82
+ echo ""
83
+ echo "==========================================="
84
+ echo "REBASE-SNAPSHOT COMPLETE"
85
+ echo "==========================================="
86
+ echo ""
87
+ echo "Branch: $CURRENT_BRANCH"
88
+ echo "Parent: $BASE_BRANCH"
89
+ echo "DbContext: $DBCONTEXT ($DBCONTEXT_TYPE)"
90
+ echo ""
91
+ echo "Changes:"
92
+ echo " - Snapshot reset to $BASE_BRANCH"
93
+ echo " - Removed: ${#BRANCH_MIGRATIONS[@]} branch migrations"
94
+ echo " - Created: 1 consolidated migration"
95
+ echo ""
96
+ echo "Result:"
97
+ echo " Migration: $MIGRATION_NAME"
98
+ echo " Total: $FINAL_COUNT migrations"
99
+ echo ""
100
+ echo "Backup: $BACKUP_DIR"
101
+ echo "Script: $SCRIPT_FILE"
102
+ echo ""
103
+ echo "==========================================="
104
+ echo ""
105
+ echo "Next steps:"
106
+ echo " /efcore db-reset # Reset local database"
107
+ echo " /efcore db-deploy # Apply migrations"
108
+ echo " /gitflow commit # Commit changes"
109
+ echo ""
110
+ ```
111
+
112
+ ---
113
+
114
+ ## OUTPUT FORMAT:
115
+
116
+ ```
117
+ REBASE-SNAPSHOT COMPLETE
118
+ ========================
119
+ Branch: {current_branch}
120
+ Parent: {base_branch}
121
+ DbContext: {dbcontext} ({dbcontext_type})
122
+
123
+ Changes:
124
+ - Snapshot reset to {base_branch}
125
+ - Removed: {count} branch migrations
126
+ - Created: 1 consolidated migration
127
+
128
+ Result:
129
+ Migration: {migration_name}
130
+ Total: {final_count} migrations
131
+
132
+ Backup: {backup_dir}
133
+ Script: {backup_dir}/migration_script.sql
134
+
135
+ Next: /efcore db-reset, /efcore db-deploy, /gitflow commit
136
+ ```
137
+
138
+ ---
139
+
140
+ ## ERROR HANDLING:
141
+
142
+ | Error | Action |
143
+ |-------|--------|
144
+ | Build fails | Restore backup |
145
+ | Script fails | Restore backup |
146
+
147
+ ---
148
+
149
+ ## SUCCESS CRITERIA:
150
+
151
+ - Build passes
152
+ - Script generates
153
+ - Summary displayed
154
+
155
+ ## COMPLETION:
156
+
157
+ Rebase-snapshot complete. Use `/efcore db-reset` then `/efcore db-deploy` to apply.
@@ -0,0 +1,266 @@
1
+ ---
2
+ name: step-00-init
3
+ description: Initialize EF Core context - detect project, DbContext, and environment
4
+ next_step: null
5
+ ---
6
+
7
+ # Step 0: Initialize EF Core Context
8
+
9
+ ## YOUR TASK:
10
+
11
+ Detect EF Core project structure, identify DbContext (Core vs Extensions), and load environment configuration.
12
+
13
+ **This step runs first for ALL EF Core commands.**
14
+
15
+ ---
16
+
17
+ ## EXECUTION SEQUENCE:
18
+
19
+ ### 1. Detect EF Core Project
20
+
21
+ ```bash
22
+ detect_efcore_project() {
23
+ # Find project with EF Core reference
24
+ CSPROJ=$(find . -name "*.csproj" -exec grep -l "Microsoft.EntityFrameworkCore" {} \; | head -1)
25
+
26
+ if [ -z "$CSPROJ" ]; then
27
+ echo "ERROR: No EF Core project found"
28
+ exit 1
29
+ fi
30
+
31
+ PROJECT_DIR=$(dirname "$CSPROJ")
32
+ PROJECT_NAME=$(basename "$CSPROJ" .csproj)
33
+ MIGRATIONS_DIR="$PROJECT_DIR/Persistence/Migrations"
34
+
35
+ # Find startup and infrastructure projects
36
+ STARTUP_PROJECT=$(find . -name "*.Api.csproj" -o -name "*Web.csproj" | head -1)
37
+ INFRA_PROJECT=$(find . -name "*Infrastructure.csproj" | head -1)
38
+ [ -z "$INFRA_PROJECT" ] && INFRA_PROJECT="$CSPROJ"
39
+
40
+ echo "Project: $PROJECT_NAME"
41
+ echo "Migrations: $MIGRATIONS_DIR"
42
+ }
43
+ ```
44
+
45
+ ### 2. Detect DbContext (Core vs Extensions)
46
+
47
+ ```bash
48
+ detect_dbcontext() {
49
+ # Priority 1: SmartStack.Domain exists → CoreDbContext
50
+ if find . -type d -name "SmartStack.Domain" | grep -q .; then
51
+ DBCONTEXT="CoreDbContext"
52
+ DBCONTEXT_TYPE="core"
53
+ SCHEMA="core"
54
+ echo "DbContext: CoreDbContext (SmartStack.Domain found)"
55
+ return
56
+ fi
57
+
58
+ # Priority 2: Client with SmartStack NuGet → ExtensionsDbContext
59
+ if find . -name "*.csproj" -exec grep -l "SmartStack\." {} \; | grep -qv "SmartStack\."; then
60
+ DBCONTEXT="ExtensionsDbContext"
61
+ DBCONTEXT_TYPE="extensions"
62
+ SCHEMA="extensions"
63
+ echo "DbContext: ExtensionsDbContext (SmartStack NuGet reference)"
64
+ return
65
+ fi
66
+
67
+ # Priority 3: Scan for DbContext in code
68
+ CORE_CTX=$(find . -name "*.cs" -exec grep -l "CoreDbContext" {} \; 2>/dev/null | head -1)
69
+ EXT_CTX=$(find . -name "*.cs" -exec grep -l "ExtensionsDbContext" {} \; 2>/dev/null | head -1)
70
+
71
+ if [ -n "$CORE_CTX" ] && [ -z "$EXT_CTX" ]; then
72
+ DBCONTEXT="CoreDbContext"
73
+ DBCONTEXT_TYPE="core"
74
+ SCHEMA="core"
75
+ elif [ -z "$CORE_CTX" ] && [ -n "$EXT_CTX" ]; then
76
+ DBCONTEXT="ExtensionsDbContext"
77
+ DBCONTEXT_TYPE="extensions"
78
+ SCHEMA="extensions"
79
+ else
80
+ # Priority 4: Ask user
81
+ DBCONTEXT=""
82
+ DBCONTEXT_TYPE=""
83
+ SCHEMA=""
84
+ fi
85
+ }
86
+ ```
87
+
88
+ ### 3. Ask User if DbContext Unknown
89
+
90
+ **If `{dbcontext}` is empty after detection:**
91
+
92
+ ```yaml
93
+ AskUserQuestion:
94
+ header: "DbContext"
95
+ question: "Which DbContext to use?"
96
+ options:
97
+ - label: "CoreDbContext"
98
+ description: "SmartStack entities (User, Role, Navigation...)"
99
+ - label: "ExtensionsDbContext"
100
+ description: "Client-specific entities"
101
+ - label: "Both"
102
+ description: "Run for both contexts"
103
+ multiSelect: false
104
+ ```
105
+
106
+ **Set variables based on response:**
107
+ ```javascript
108
+ if (answer === "CoreDbContext") {
109
+ DBCONTEXT = "CoreDbContext";
110
+ DBCONTEXT_TYPE = "core";
111
+ SCHEMA = "core";
112
+ } else if (answer === "ExtensionsDbContext") {
113
+ DBCONTEXT = "ExtensionsDbContext";
114
+ DBCONTEXT_TYPE = "extensions";
115
+ SCHEMA = "extensions";
116
+ } else {
117
+ // Both - will run commands twice
118
+ RUN_BOTH = true;
119
+ }
120
+ ```
121
+
122
+ ### 4. Detect Environment
123
+
124
+ ```bash
125
+ detect_environment() {
126
+ API_DIR=$(find . -type d -name "*.Api" | head -1)
127
+ [ -z "$API_DIR" ] && API_DIR="src/SmartStack.Api"
128
+
129
+ # Priority: --env flag > appsettings.Local.json > error
130
+ if [ -n "$ENV_FLAG" ]; then
131
+ CONFIG_FILE="$API_DIR/appsettings.${ENV_FLAG}.json"
132
+ elif [ -f "$API_DIR/appsettings.Local.json" ]; then
133
+ CONFIG_FILE="$API_DIR/appsettings.Local.json"
134
+ SELECTED_ENV="Local"
135
+ else
136
+ echo "ERROR: No appsettings.Local.json found"
137
+ echo "Create one or use --env flag"
138
+ exit 1
139
+ fi
140
+
141
+ echo "Environment: $SELECTED_ENV"
142
+ echo "Config: $CONFIG_FILE"
143
+ }
144
+ ```
145
+
146
+ ### 5. Determine Base Branch (for squash/rebase)
147
+
148
+ ```bash
149
+ determine_base_branch() {
150
+ CURRENT_BRANCH=$(git branch --show-current)
151
+
152
+ case "$CURRENT_BRANCH" in
153
+ feature/*)
154
+ BASE_BRANCH="develop"
155
+ BRANCH_TYPE="feature"
156
+ ;;
157
+ release/*)
158
+ BASE_BRANCH="main"
159
+ BRANCH_TYPE="release"
160
+ ;;
161
+ hotfix/*)
162
+ BASE_BRANCH="main"
163
+ BRANCH_TYPE="hotfix"
164
+ ;;
165
+ develop)
166
+ BASE_BRANCH="main"
167
+ BRANCH_TYPE="develop"
168
+ ;;
169
+ main|master)
170
+ echo "ERROR: Cannot run on main/master branch"
171
+ exit 1
172
+ ;;
173
+ *)
174
+ BASE_BRANCH="develop"
175
+ BRANCH_TYPE="unknown"
176
+ ;;
177
+ esac
178
+
179
+ echo "Branch: $CURRENT_BRANCH ($BRANCH_TYPE)"
180
+ echo "Base: $BASE_BRANCH"
181
+ }
182
+ ```
183
+
184
+ ### 6. Block Production
185
+
186
+ ```bash
187
+ block_production() {
188
+ # Check for production indicators
189
+ if grep -q '"Production"' "$CONFIG_FILE" 2>/dev/null; then
190
+ echo "BLOCKED: Production environment detected"
191
+ exit 1
192
+ fi
193
+
194
+ if [[ "$DATABASE_NAME" == *"prod"* ]] || [[ "$DATABASE_NAME" == *"production"* ]]; then
195
+ echo "BLOCKED: Production database detected"
196
+ exit 1
197
+ fi
198
+ }
199
+ ```
200
+
201
+ ### 7. Display Summary
202
+
203
+ ```
204
+ EF CORE CONTEXT
205
+ ├── Project: {PROJECT_NAME}
206
+ ├── DbContext: {DBCONTEXT} ({DBCONTEXT_TYPE})
207
+ ├── Schema: {SCHEMA}
208
+ ├── Migrations: {MIGRATIONS_DIR}
209
+ ├── Environment:{SELECTED_ENV}
210
+ └── Branch: {CURRENT_BRANCH} → {BASE_BRANCH}
211
+ ```
212
+
213
+ ---
214
+
215
+ ## STATE OUTPUT:
216
+
217
+ After this step, these variables are available:
218
+
219
+ | Variable | Example Value |
220
+ |----------|---------------|
221
+ | `{project_name}` | SmartStack.Infrastructure |
222
+ | `{dbcontext}` | CoreDbContext |
223
+ | `{dbcontext_type}` | core |
224
+ | `{schema}` | core |
225
+ | `{migrations_dir}` | src/SmartStack.Infrastructure/Persistence/Migrations |
226
+ | `{infra_project}` | src/SmartStack.Infrastructure/SmartStack.Infrastructure.csproj |
227
+ | `{startup_project}` | src/SmartStack.Api/SmartStack.Api.csproj |
228
+ | `{base_branch}` | develop |
229
+ | `{branch_type}` | feature |
230
+ | `{current_branch}` | feature/multitenant |
231
+ | `{selected_env}` | Local |
232
+
233
+ ---
234
+
235
+ ## SUCCESS CRITERIA:
236
+
237
+ - EF Core project detected
238
+ - DbContext identified (or user prompted)
239
+ - Environment loaded
240
+ - No production environment
241
+ - All paths validated
242
+
243
+ ## FAILURE MODES:
244
+
245
+ | Error | Resolution |
246
+ |-------|------------|
247
+ | No EF Core project | Check Microsoft.EntityFrameworkCore reference |
248
+ | No appsettings.Local.json | Create file or use --env flag |
249
+ | Production detected | Use different environment |
250
+ | Both DbContexts found | User will be prompted |
251
+
252
+ ---
253
+
254
+ ## NEXT STEP:
255
+
256
+ Route to command-specific step based on `{command}`:
257
+
258
+ | Command | Next Step |
259
+ |---------|-----------|
260
+ | `db-status` | `../db/step-status.md` |
261
+ | `db-deploy` | `../db/step-deploy.md` |
262
+ | `db-reset` | `../db/step-reset.md` |
263
+ | `db-seed` | `../db/step-seed.md` |
264
+ | `migration` | `../migration/step-01-check.md` |
265
+ | `squash` | `../squash/step-01-backup.md` |
266
+ | `rebase-snapshot` | `../rebase-snapshot/step-01-backup.md` |
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: step-00-init
3
+ description: Initialize squash - verify prerequisites and get confirmation
4
+ next_step: step-01-backup.md
5
+ ---
6
+
7
+ # Step 0: Initialize Squash
8
+
9
+ ## YOUR TASK:
10
+
11
+ Verify prerequisites for squash operation and get user confirmation.
12
+
13
+ **Requires:** `steps/shared/step-00-init.md` completed (provides {dbcontext}, {base_branch}, etc.)
14
+
15
+ ---
16
+
17
+ ## EXECUTION SEQUENCE:
18
+
19
+ ### 1. Verify Clean Working Directory
20
+
21
+ ```bash
22
+ [ -n "$(git status --porcelain)" ] && {
23
+ echo "ERROR: Working directory not clean"
24
+ git status --short
25
+ exit 1
26
+ }
27
+ ```
28
+
29
+ ### 2. Identify Branch-Only Migrations
30
+
31
+ ```bash
32
+ # Fetch parent branch
33
+ git fetch origin "$BASE_BRANCH" --quiet
34
+
35
+ # Get migrations from parent branch
36
+ BASE_MIGRATIONS=$(git ls-tree -r --name-only "origin/$BASE_BRANCH" -- "$MIGRATIONS_DIR" 2>/dev/null | grep "\.cs$" | grep -v "Designer\|Snapshot" || echo "")
37
+
38
+ # Get local migrations
39
+ LOCAL_MIGRATIONS=$(find "$MIGRATIONS_DIR" -name "*.cs" 2>/dev/null | grep -v "Designer\|Snapshot" | xargs -I{} basename {} 2>/dev/null || echo "")
40
+
41
+ # Find migrations unique to this branch
42
+ BRANCH_ONLY_MIGRATIONS=()
43
+ for mig in $LOCAL_MIGRATIONS; do
44
+ if ! echo "$BASE_MIGRATIONS" | grep -q "$(basename "$mig")"; then
45
+ BRANCH_ONLY_MIGRATIONS+=("$mig")
46
+ fi
47
+ done
48
+
49
+ MIGRATION_COUNT=${#BRANCH_ONLY_MIGRATIONS[@]}
50
+ BASE_MIGRATION_COUNT=$(echo "$BASE_MIGRATIONS" | grep -c "." || echo "0")
51
+
52
+ echo "Branch: $CURRENT_BRANCH"
53
+ echo "Parent: $BASE_BRANCH"
54
+ echo "Migrations to squash: $MIGRATION_COUNT (branch-only)"
55
+ echo "Migrations from parent: $BASE_MIGRATION_COUNT (preserved)"
56
+ ```
57
+
58
+ ### 3. Check If Squash Needed
59
+
60
+ ```bash
61
+ if [ "$MIGRATION_COUNT" -eq 0 ]; then
62
+ echo "No branch-specific migrations to squash."
63
+ echo "Nothing to do."
64
+ exit 0
65
+ fi
66
+
67
+ if [ "$MIGRATION_COUNT" -eq 1 ]; then
68
+ echo "Only 1 migration on branch."
69
+ # Ask if user wants to continue anyway
70
+ fi
71
+ ```
72
+
73
+ ### 4. Display Summary
74
+
75
+ ```
76
+ SQUASH PREVIEW
77
+ ==============
78
+ Branch: {CURRENT_BRANCH}
79
+ Parent: {BASE_BRANCH}
80
+ DbContext: {DBCONTEXT} ({DBCONTEXT_TYPE})
81
+
82
+ Migrations to squash ({MIGRATION_COUNT}):
83
+ {for mig in BRANCH_ONLY_MIGRATIONS}
84
+ - {mig}
85
+ {endfor}
86
+
87
+ Migrations from parent ({BASE_MIGRATION_COUNT}):
88
+ (will be preserved)
89
+
90
+ Result: {BASE_MIGRATION_COUNT + 1} migrations total
91
+ ```
92
+
93
+ ### 5. User Confirmation
94
+
95
+ **If NOT auto_mode:**
96
+
97
+ ```yaml
98
+ AskUserQuestion:
99
+ header: "Squash"
100
+ question: "Squash {MIGRATION_COUNT} migrations from {CURRENT_BRANCH}?
101
+
102
+ The ModelSnapshot and migrations from {BASE_BRANCH} will be recovered.
103
+ Your {MIGRATION_COUNT} migrations will be consolidated into ONE.
104
+
105
+ This operation is DESTRUCTIVE but a backup will be created."
106
+ options:
107
+ - label: "Yes, squash"
108
+ description: "Consolidate on base of {BASE_BRANCH}"
109
+ - label: "View details"
110
+ description: "Show migrations to be squashed"
111
+ - label: "Cancel"
112
+ description: "Do nothing"
113
+ multiSelect: false
114
+ ```
115
+
116
+ **Handle response:**
117
+ - "Yes, squash" → Continue to next step
118
+ - "View details" → Show full migration list, ask again
119
+ - "Cancel" → Exit
120
+
121
+ ---
122
+
123
+ ## STATE OUTPUT:
124
+
125
+ | Variable | Description |
126
+ |----------|-------------|
127
+ | `{branch_only_migrations}` | Array of migrations to squash |
128
+ | `{migration_count}` | Number of migrations to squash |
129
+ | `{base_migration_count}` | Number of parent migrations |
130
+
131
+ ---
132
+
133
+ ## SUCCESS CRITERIA:
134
+
135
+ - Working directory clean
136
+ - At least 1 branch-specific migration
137
+ - User confirmed (or auto_mode)
138
+
139
+ ## NEXT STEP:
140
+
141
+ → `step-01-backup.md`
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: step-01-backup
3
+ description: Create backup of all migration files
4
+ next_step: step-02-fetch.md
5
+ ---
6
+
7
+ # Step 1: Backup
8
+
9
+ ## YOUR TASK:
10
+
11
+ Create a complete backup of all migration files before destructive operations.
12
+
13
+ **Previous step:** `step-00-init.md`
14
+
15
+ ---
16
+
17
+ ## EXECUTION SEQUENCE:
18
+
19
+ ### 1. Create Backup Directory
20
+
21
+ ```bash
22
+ TIMESTAMP=$(date +%Y%m%d_%H%M%S)
23
+ BACKUP_DIR=".claude/gitflow/backup/migrations/squash_${TIMESTAMP}"
24
+
25
+ mkdir -p "$BACKUP_DIR"
26
+ echo "Backup directory: $BACKUP_DIR"
27
+ ```
28
+
29
+ ### 2. Backup All Migration Files
30
+
31
+ ```bash
32
+ # Backup all .cs files from migrations directory
33
+ cp "$MIGRATIONS_DIR"/*.cs "$BACKUP_DIR/" 2>/dev/null || {
34
+ echo "ERROR: No migration files found to backup"
35
+ exit 1
36
+ }
37
+
38
+ # Count backed up files
39
+ BACKUP_COUNT=$(ls -1 "$BACKUP_DIR"/*.cs 2>/dev/null | wc -l)
40
+ echo "Backed up: $BACKUP_COUNT files"
41
+ ```
42
+
43
+ ### 3. Create Backup Manifest
44
+
45
+ ```bash
46
+ cat > "$BACKUP_DIR/MANIFEST.md" << EOF
47
+ # Squash Backup Manifest
48
+
49
+ **Created:** $(date -Iseconds)
50
+ **Branch:** $CURRENT_BRANCH
51
+ **Parent:** $BASE_BRANCH
52
+ **DbContext:** $DBCONTEXT
53
+
54
+ ## Files Backed Up
55
+
56
+ \`\`\`
57
+ $(ls -la "$BACKUP_DIR"/*.cs)
58
+ \`\`\`
59
+
60
+ ## Migrations to Squash
61
+
62
+ $(for mig in "${BRANCH_ONLY_MIGRATIONS[@]}"; do echo "- $mig"; done)
63
+
64
+ ## Restore Command
65
+
66
+ \`\`\`bash
67
+ cp "$BACKUP_DIR"/*.cs "$MIGRATIONS_DIR/"
68
+ \`\`\`
69
+ EOF
70
+
71
+ echo "Manifest created: $BACKUP_DIR/MANIFEST.md"
72
+ ```
73
+
74
+ ### 4. Verify Backup
75
+
76
+ ```bash
77
+ # Ensure critical files exist
78
+ SNAPSHOT_BACKUP=$(ls "$BACKUP_DIR"/*ModelSnapshot.cs 2>/dev/null | head -1)
79
+
80
+ if [ -z "$SNAPSHOT_BACKUP" ]; then
81
+ echo "WARNING: No ModelSnapshot in backup"
82
+ fi
83
+
84
+ echo ""
85
+ echo "Backup complete:"
86
+ echo " Directory: $BACKUP_DIR"
87
+ echo " Files: $BACKUP_COUNT"
88
+ echo " Snapshot: $(basename "$SNAPSHOT_BACKUP" 2>/dev/null || echo 'N/A')"
89
+ ```
90
+
91
+ ---
92
+
93
+ ## STATE OUTPUT:
94
+
95
+ | Variable | Value |
96
+ |----------|-------|
97
+ | `{backup_dir}` | `.claude/gitflow/backup/migrations/squash_{timestamp}` |
98
+ | `{backup_count}` | Number of files backed up |
99
+
100
+ ---
101
+
102
+ ## RECOVERY:
103
+
104
+ If squash fails, restore with:
105
+
106
+ ```bash
107
+ cp "{BACKUP_DIR}"/*.cs "{MIGRATIONS_DIR}/"
108
+ ```
109
+
110
+ ---
111
+
112
+ ## SUCCESS CRITERIA:
113
+
114
+ - Backup directory created
115
+ - All migration files copied
116
+ - Manifest created
117
+
118
+ ## NEXT STEP:
119
+
120
+ → `step-02-fetch.md`