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