|
1
|
#!/bin/bash |
|
2
|
# Post-migration sanity check for fullstack_js projects. |
|
3
|
# Usage: bash fullstack_sanity_check.sh <app-name> |
|
4
|
# |
|
5
|
# Verifies the mechanical migration was done correctly. |
|
6
|
# Run this BEFORE the visual verification step. |
|
7
|
|
|
8
|
set -euo pipefail |
|
9
|
|
|
10
|
if [ $# -lt 1 ]; then |
|
11
|
echo "Usage: bash fullstack_sanity_check.sh <app-name>" |
|
12
|
exit 1 |
|
13
|
fi |
|
14
|
|
|
15
|
APP="$1" |
|
16
|
BACKUP=".migration-backup" |
|
17
|
|
|
18
|
echo "==== MIGRATION SANITY CHECK ====" |
|
19
|
echo "App: $APP" |
|
20
|
FAIL=0 |
|
21
|
|
|
22
|
# 1. Artifact directory exists |
|
23
|
if [ -d "artifacts/$APP/src" ]; then |
|
24
|
echo "PASS: artifact src/ exists" |
|
25
|
else |
|
26
|
echo "FAIL: artifacts/$APP/src/ missing" |
|
27
|
FAIL=1 |
|
28
|
fi |
|
29
|
|
|
30
|
# 2. index.html copied |
|
31
|
if [ -f "artifacts/$APP/index.html" ]; then |
|
32
|
echo "PASS: index.html present" |
|
33
|
else |
|
34
|
echo "FAIL: index.html missing — fonts/favicons/meta tags will be lost" |
|
35
|
FAIL=1 |
|
36
|
fi |
|
37
|
|
|
38
|
# 3. All client source directories copied |
|
39
|
if [ -d "$BACKUP/client/src" ]; then |
|
40
|
CLIENT_SRC="$BACKUP/client/src" |
|
41
|
elif [ -d "$BACKUP/src" ]; then |
|
42
|
CLIENT_SRC="$BACKUP/src" |
|
43
|
else |
|
44
|
CLIENT_SRC="" |
|
45
|
fi |
|
46
|
|
|
47
|
if [ -n "$CLIENT_SRC" ]; then |
|
48
|
DIR_FAIL=0 |
|
49
|
for dir in "$CLIENT_SRC"/*/; do |
|
50
|
[ ! -d "$dir" ] && continue |
|
51
|
name=$(basename "$dir") |
|
52
|
# Skip node_modules and build output |
|
53
|
case "$name" in |
|
54
|
node_modules|dist|build|.next) continue ;; |
|
55
|
esac |
|
56
|
if [ ! -d "artifacts/$APP/src/$name" ]; then |
|
57
|
echo "FAIL: client directory $name was NOT copied" |
|
58
|
DIR_FAIL=1 |
|
59
|
FAIL=1 |
|
60
|
fi |
|
61
|
done |
|
62
|
[ $DIR_FAIL -eq 0 ] && echo "PASS: all client source directories copied" |
|
63
|
fi |
|
64
|
|
|
65
|
# 4. Schema file present with zod/v4 |
|
66
|
SCHEMA_OK=0 |
|
67
|
for f in lib/db/src/schema/*.ts; do |
|
68
|
[ -f "$f" ] || continue |
|
69
|
SCHEMA_OK=1 |
|
70
|
# Match 'from "zod"' or "from 'zod'" exactly (not 'from "zod/v4"') |
|
71
|
if grep -qE "from ['\"]zod['\"]" "$f" 2>/dev/null; then |
|
72
|
echo "FAIL: $f still imports from 'zod' instead of 'zod/v4'" |
|
73
|
FAIL=1 |
|
74
|
fi |
|
75
|
done |
|
76
|
if [ $SCHEMA_OK -eq 1 ]; then |
|
77
|
echo "PASS: schema files present in lib/db/src/schema/" |
|
78
|
else |
|
79
|
echo "FAIL: no schema files in lib/db/src/schema/" |
|
80
|
FAIL=1 |
|
81
|
fi |
|
82
|
|
|
83
|
# 5. Route files present |
|
84
|
ROUTE_FILES=$(find "artifacts/api-server/src/routes/" -name "*.ts" ! -name "health.ts" ! -name "index.ts" 2>/dev/null | head -1) |
|
85
|
if [ -f "artifacts/api-server/src/routes/routes.ts" ] || [ -n "$ROUTE_FILES" ]; then |
|
86
|
echo "PASS: route files present" |
|
87
|
else |
|
88
|
echo "FAIL: no route files in artifacts/api-server/src/routes/" |
|
89
|
FAIL=1 |
|
90
|
fi |
|
91
|
|
|
92
|
# 6. No stale @shared/ imports in server files |
|
93
|
if grep -rq "@shared/\|from ['\"]\.\.\/.*shared\|from ['\"]\.\.\/\.\.\/shared" artifacts/api-server/src/ --include="*.ts" 2>/dev/null; then |
|
94
|
echo "FAIL: old @shared/ or ../../shared/ imports still present in server files:" |
|
95
|
grep -rn "@shared/\|from ['\"]\.\.\/.*shared\|from ['\"]\.\.\/\.\.\/shared" artifacts/api-server/src/ --include="*.ts" 2>/dev/null || true |
|
96
|
FAIL=1 |
|
97
|
else |
|
98
|
echo "PASS: no old shared imports in server files" |
|
99
|
fi |
|
100
|
|
|
101
|
# 7. No stale @shared/ imports in frontend |
|
102
|
if grep -rq "@shared/\|from ['\"]\.\.\/.*shared" "artifacts/$APP/src/" --include="*.ts" --include="*.tsx" 2>/dev/null; then |
|
103
|
echo "FAIL: old @shared/ imports still present in frontend:" |
|
104
|
grep -rn "@shared/\|from ['\"]\.\.\/.*shared" "artifacts/$APP/src/" --include="*.ts" --include="*.tsx" 2>/dev/null || true |
|
105
|
FAIL=1 |
|
106
|
else |
|
107
|
echo "PASS: no old shared imports in frontend" |
|
108
|
fi |
|
109
|
|
|
110
|
# 8. No server code imported in frontend |
|
111
|
if grep -rq "from ['\"]@workspace/db['\"]" "artifacts/$APP/src/" --include="*.ts" --include="*.tsx" 2>/dev/null; then |
|
112
|
echo "FAIL: @workspace/db imported in frontend — use generated hooks instead" |
|
113
|
FAIL=1 |
|
114
|
else |
|
115
|
echo "PASS: no server code imports in frontend" |
|
116
|
fi |
|
117
|
|
|
118
|
# 9. No broken @/ imports |
|
119
|
BROKEN_IMPORTS=$({ grep -rn "from ['\"]@/" "artifacts/$APP/src/" --include="*.ts" --include="*.tsx" 2>/dev/null || true; } | while IFS= read -r line; do |
|
120
|
file=$(echo "$line" | cut -d: -f1) |
|
121
|
import_path=$(echo "$line" | sed -n "s/.*from ['\"]@\/\([^'\"]*\)['\"].*/\1/p") |
|
122
|
[ -z "$import_path" ] && continue |
|
123
|
base="artifacts/$APP/src/$import_path" |
|
124
|
if [ ! -f "$base.ts" ] && [ ! -f "$base.tsx" ] && [ ! -f "$base/index.ts" ] && [ ! -f "$base/index.tsx" ] && [ ! -f "$base" ]; then |
|
125
|
echo "$file → @/$import_path" |
|
126
|
fi |
|
127
|
done) |
|
128
|
if [ -n "$BROKEN_IMPORTS" ]; then |
|
129
|
echo "FAIL: broken @/ imports found:" |
|
130
|
echo "$BROKEN_IMPORTS" |
|
131
|
FAIL=1 |
|
132
|
else |
|
133
|
echo "PASS: all @/ imports resolve" |
|
134
|
fi |
|
135
|
|
|
136
|
# 10. Theme.json carried over if applicable |
|
137
|
if [ -f "$BACKUP/theme.json" ]; then |
|
138
|
if [ -f "artifacts/$APP/theme.json" ]; then |
|
139
|
echo "PASS: theme.json copied" |
|
140
|
else |
|
141
|
echo "FAIL: theme.json exists in backup but not in artifact — colors will be broken" |
|
142
|
FAIL=1 |
|
143
|
fi |
|
144
|
fi |
|
145
|
|
|
146
|
# 11. Attached assets |
|
147
|
if [ -d "$BACKUP/attached_assets" ]; then |
|
148
|
if [ -d "attached_assets" ]; then |
|
149
|
echo "PASS: attached_assets present" |
|
150
|
else |
|
151
|
echo "FAIL: attached_assets directory missing" |
|
152
|
FAIL=1 |
|
153
|
fi |
|
154
|
fi |
|
155
|
|
|
156
|
# 12. Wouter base path |
|
157
|
APP_TSX="artifacts/$APP/src/App.tsx" |
|
158
|
if [ -f "$APP_TSX" ]; then |
|
159
|
if grep -q "from ['\"]wouter['\"]" "$APP_TSX" 2>/dev/null; then |
|
160
|
if grep -q "BASE_URL\|base=" "$APP_TSX" 2>/dev/null; then |
|
161
|
echo "PASS: wouter has BASE_URL base path" |
|
162
|
else |
|
163
|
echo "FAIL: App.tsx uses wouter but missing BASE_URL base path — routing will break" |
|
164
|
FAIL=1 |
|
165
|
fi |
|
166
|
fi |
|
167
|
fi |
|
168
|
|
|
169
|
# 13. Font consistency |
|
170
|
if [ -f "artifacts/$APP/index.html" ] && [ -f "artifacts/$APP/src/index.css" ]; then |
|
171
|
LOADED_FONTS=$(grep -oE 'family=[^&"]+' "artifacts/$APP/index.html" 2>/dev/null | sed 's/family=//g; s/+/ /g; s/:.*//g' || true) |
|
172
|
if [ -n "$LOADED_FONTS" ]; then |
|
173
|
echo "$LOADED_FONTS" | while read -r font; do |
|
174
|
[ -z "$font" ] && continue |
|
175
|
if grep -qi "$font" "artifacts/$APP/src/index.css" 2>/dev/null; then |
|
176
|
echo "PASS: font '$font' referenced in index.css" |
|
177
|
else |
|
178
|
echo "WARN: font '$font' loaded in index.html but not referenced in index.css — may render with fallback" |
|
179
|
fi |
|
180
|
done |
|
181
|
fi |
|
182
|
fi |
|
183
|
|
|
184
|
echo "" |
|
185
|
echo "==== END SANITY CHECK ====" |
|
186
|
if [ $FAIL -ne 0 ]; then |
|
187
|
echo "SANITY CHECK FAILED — fix all FAIL lines above before proceeding." |
|
188
|
exit 1 |
|
189
|
else |
|
190
|
echo "ALL CHECKS PASSED" |
|
191
|
fi |