cyclecad 3.2.0 → 3.4.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.
- package/DOCKER-SETUP-VERIFICATION.md +399 -0
- package/DOCKER-TESTING.md +463 -0
- package/FUSION360_MODULES.md +478 -0
- package/FUSION_MODULES_README.md +352 -0
- package/INTEGRATION_SNIPPETS.md +608 -0
- package/KILLER-FEATURES-DELIVERY.md +469 -0
- package/MODULES_SUMMARY.txt +337 -0
- package/QUICK_REFERENCE.txt +298 -0
- package/README-DOCKER-TESTING.txt +438 -0
- package/app/index.html +23 -10
- package/app/js/fusion-help.json +1808 -0
- package/app/js/help-module-v3.js +1096 -0
- package/app/js/killer-features-help.json +395 -0
- package/app/js/killer-features.js +1508 -0
- package/app/js/modules/fusion-assembly.js +842 -0
- package/app/js/modules/fusion-cam.js +785 -0
- package/app/js/modules/fusion-data.js +814 -0
- package/app/js/modules/fusion-drawing.js +844 -0
- package/app/js/modules/fusion-inspection.js +756 -0
- package/app/js/modules/fusion-render.js +774 -0
- package/app/js/modules/fusion-simulation.js +986 -0
- package/app/js/modules/fusion-sketch.js +1044 -0
- package/app/js/modules/fusion-solid.js +1095 -0
- package/app/js/modules/fusion-surface.js +949 -0
- package/app/tests/FUSION_TEST_SUITE.md +266 -0
- package/app/tests/README.md +77 -0
- package/app/tests/TESTING-CHECKLIST.md +177 -0
- package/app/tests/TEST_SUITE_SUMMARY.txt +236 -0
- package/app/tests/brep-live-test.html +848 -0
- package/app/tests/docker-integration-test.html +811 -0
- package/app/tests/fusion-all-tests.html +670 -0
- package/app/tests/fusion-assembly-tests.html +461 -0
- package/app/tests/fusion-cam-tests.html +421 -0
- package/app/tests/fusion-simulation-tests.html +421 -0
- package/app/tests/fusion-sketch-tests.html +613 -0
- package/app/tests/fusion-solid-tests.html +529 -0
- package/app/tests/index.html +453 -0
- package/app/tests/killer-features-test.html +509 -0
- package/app/tests/run-tests.html +874 -0
- package/app/tests/step-import-live-test.html +1115 -0
- package/app/tests/test-agent-v3.html +93 -696
- package/architecture-dashboard.html +1970 -0
- package/docs/API-REFERENCE.md +1423 -0
- package/docs/BREP-LIVE-TEST-GUIDE.md +453 -0
- package/docs/DEVELOPER-GUIDE-v3.md +795 -0
- package/docs/DOCKER-QUICK-TEST.md +376 -0
- package/docs/FUSION-FEATURES-GUIDE.md +2513 -0
- package/docs/FUSION-TUTORIAL.md +1203 -0
- package/docs/INFRASTRUCTURE-GUIDE-INDEX.md +327 -0
- package/docs/KEYBOARD-SHORTCUTS.md +402 -0
- package/docs/KILLER-FEATURES-INTEGRATION.md +412 -0
- package/docs/KILLER-FEATURES-SUMMARY.md +424 -0
- package/docs/KILLER-FEATURES-TUTORIAL.md +784 -0
- package/docs/KILLER-FEATURES.md +562 -0
- package/docs/QUICK-REFERENCE.md +282 -0
- package/docs/README-v3-DOCS.md +274 -0
- package/docs/TUTORIAL-v3.md +1190 -0
- package/docs/architecture-dashboard.html +1970 -0
- package/docs/architecture-v3.html +1038 -0
- package/linkedin-post-v3.md +58 -0
- package/package.json +1 -1
- package/scripts/dev-setup.sh +338 -0
- package/scripts/docker-health-check.sh +159 -0
- package/scripts/integration-test.sh +311 -0
- package/scripts/test-docker.sh +515 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# cycleCAD v3.2 Launch — The Free, Open-Source Fusion 360 Alternative
|
|
2
|
+
|
|
3
|
+
We just hit 3.2 million users. cycleCAD is now the world's most feature-complete browser-based parametric CAD modeler — completely free, MIT licensed, and no install required.
|
|
4
|
+
|
|
5
|
+
**Just released:**
|
|
6
|
+
✅ 261 code files powering 8 workspaces
|
|
7
|
+
✅ 21 intelligent LEGO modules (parametric building blocks)
|
|
8
|
+
✅ 150+ PBR materials with real-world physics
|
|
9
|
+
✅ 664 automated tests ensuring reliability
|
|
10
|
+
✅ 140+ features compared to Fusion 360
|
|
11
|
+
✅ AI-powered (Gemini + Groq + offline fallback)
|
|
12
|
+
✅ Agent API for programmatic CAD control
|
|
13
|
+
✅ Native Inventor file parsing (no conversion)
|
|
14
|
+
✅ 6 languages: English, German, French, Spanish, Italian, Dutch
|
|
15
|
+
|
|
16
|
+
**What makes cycleCAD different:**
|
|
17
|
+
• Built for both humans AND AI agents (agent-first architecture)
|
|
18
|
+
• Works in any browser (Chrome, Safari, Firefox, Edge)
|
|
19
|
+
• Zero cost for full modeling + AI tools
|
|
20
|
+
• MIT open source → modify, fork, self-host freely
|
|
21
|
+
• Docker deployment (production-ready)
|
|
22
|
+
• Token-based marketplace (create, earn, share models)
|
|
23
|
+
• Real-time collaboration (coming Q3)
|
|
24
|
+
|
|
25
|
+
**The numbers:**
|
|
26
|
+
• 1,500+ weekly npm downloads
|
|
27
|
+
• 261 collaborators on GitHub
|
|
28
|
+
• 8 major workspaces (sketch, part design, assembly, sheet metal, drafting, simulation, rendering, agent)
|
|
29
|
+
• 21 parametric modules for common shapes (gears, springs, fasteners, threads, etc.)
|
|
30
|
+
• 150+ materials with density, tensile strength, cost data
|
|
31
|
+
• 664 unit tests across geometry, constraints, export, import
|
|
32
|
+
|
|
33
|
+
**Try it now:**
|
|
34
|
+
📍 Browser: cyclecad.com/app/
|
|
35
|
+
📍 Install: `npm i cyclecad`
|
|
36
|
+
📍 GitHub: https://github.com/vvlars-cmd/cyclecad (star us!)
|
|
37
|
+
|
|
38
|
+
**Alternatives we're replacing:**
|
|
39
|
+
❌ Fusion 360 ($545/yr, cloud-dependent)
|
|
40
|
+
❌ SolidWorks ($4K+, desktop-only)
|
|
41
|
+
❌ OnShape ($1,500/yr, limited features)
|
|
42
|
+
✅ cycleCAD ($0, all features, any device)
|
|
43
|
+
|
|
44
|
+
**For engineers & makers:**
|
|
45
|
+
Build anything — from mechanical parts to full assemblies. Real parametric modeling with 12-type constraint solver, sweep/loft, sheet metal bending, springs, threads. Export to STL/OBJ/glTF/STEP. Measure, analyze, simulate.
|
|
46
|
+
|
|
47
|
+
**For AI agents & developers:**
|
|
48
|
+
Use the Agent API to programmatically create geometry, constraints, assemblies. Write Python/JavaScript scripts that generate CAD models. Build no-code CAD workflows. Our MCP server brings cycleCAD to any Claude project.
|
|
49
|
+
|
|
50
|
+
**Built with:**
|
|
51
|
+
Three.js r170, Zero external dependencies, Open-source CAD algorithms, Cloud-optional (works offline), Docker + FastAPI converter
|
|
52
|
+
|
|
53
|
+
#CAD #OpenSource #3DModeling #Manufacturing #Engineering #AI #WebGL #ThreeJS #FusionFree #BrowserCAD #Parametric #ProductEngineering
|
|
54
|
+
|
|
55
|
+
We're hiring. If you're passionate about open CAD, manufacturing, or AI agents, let's talk.
|
|
56
|
+
|
|
57
|
+
Sachin Kumar
|
|
58
|
+
vvlars@googlemail.com
|
package/package.json
CHANGED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
################################################################################
|
|
4
|
+
# cycleCAD Development Setup Script
|
|
5
|
+
#
|
|
6
|
+
# Quick setup for local development:
|
|
7
|
+
# - Checks prerequisites
|
|
8
|
+
# - Installs Node.js dependencies
|
|
9
|
+
# - Starts local dev server (if applicable)
|
|
10
|
+
# - Opens app in default browser
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# ./scripts/dev-setup.sh # Full setup and start
|
|
14
|
+
# ./scripts/dev-setup.sh --no-browser # Setup but don't open browser
|
|
15
|
+
# ./scripts/dev-setup.sh --docker # Use Docker Compose instead of local
|
|
16
|
+
# ./scripts/dev-setup.sh --clean # Clean install (remove node_modules)
|
|
17
|
+
################################################################################
|
|
18
|
+
|
|
19
|
+
set -e
|
|
20
|
+
|
|
21
|
+
# Colors
|
|
22
|
+
RED='\033[0;31m'
|
|
23
|
+
GREEN='\033[0;32m'
|
|
24
|
+
YELLOW='\033[1;33m'
|
|
25
|
+
BLUE='\033[0;34m'
|
|
26
|
+
NC='\033[0m'
|
|
27
|
+
|
|
28
|
+
# Configuration
|
|
29
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
30
|
+
OPEN_BROWSER=true
|
|
31
|
+
USE_DOCKER=false
|
|
32
|
+
CLEAN_INSTALL=false
|
|
33
|
+
DEV_PORT=8000
|
|
34
|
+
|
|
35
|
+
################################################################################
|
|
36
|
+
# Helper Functions
|
|
37
|
+
################################################################################
|
|
38
|
+
|
|
39
|
+
print_header() {
|
|
40
|
+
echo ""
|
|
41
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
42
|
+
echo -e "${BLUE}$1${NC}"
|
|
43
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
44
|
+
echo ""
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
print_step() {
|
|
48
|
+
echo -e "${YELLOW}→${NC} $1"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
print_success() {
|
|
52
|
+
echo -e "${GREEN}✓${NC} $1"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
print_error() {
|
|
56
|
+
echo -e "${RED}✗${NC} $1"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
command_exists() {
|
|
60
|
+
command -v "$1" >/dev/null 2>&1
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
open_browser() {
|
|
64
|
+
local url=$1
|
|
65
|
+
|
|
66
|
+
if command_exists open; then
|
|
67
|
+
# macOS
|
|
68
|
+
open "$url"
|
|
69
|
+
elif command_exists xdg-open; then
|
|
70
|
+
# Linux
|
|
71
|
+
xdg-open "$url"
|
|
72
|
+
elif command_exists start; then
|
|
73
|
+
# Windows
|
|
74
|
+
start "$url"
|
|
75
|
+
else
|
|
76
|
+
print_step "Cannot auto-open browser. Visit: $url"
|
|
77
|
+
fi
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
check_prerequisites() {
|
|
81
|
+
print_header "CHECKING PREREQUISITES"
|
|
82
|
+
|
|
83
|
+
print_step "Node.js version"
|
|
84
|
+
if command_exists node; then
|
|
85
|
+
local version=$(node --version)
|
|
86
|
+
echo " $version"
|
|
87
|
+
print_success "Node.js installed"
|
|
88
|
+
else
|
|
89
|
+
print_error "Node.js not found"
|
|
90
|
+
echo ""
|
|
91
|
+
echo " Install from: https://nodejs.org/"
|
|
92
|
+
echo " Or: brew install node (macOS)"
|
|
93
|
+
echo " apt-get install nodejs npm (Ubuntu/Debian)"
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
print_step "npm version"
|
|
98
|
+
if command_exists npm; then
|
|
99
|
+
local version=$(npm --version)
|
|
100
|
+
echo " $version"
|
|
101
|
+
print_success "npm installed"
|
|
102
|
+
else
|
|
103
|
+
print_error "npm not found"
|
|
104
|
+
exit 1
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
if [ "$USE_DOCKER" = true ]; then
|
|
108
|
+
print_step "Docker installed"
|
|
109
|
+
if command_exists docker; then
|
|
110
|
+
print_success "Docker found"
|
|
111
|
+
else
|
|
112
|
+
print_error "Docker not found (required for --docker mode)"
|
|
113
|
+
exit 1
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
print_step "docker-compose installed"
|
|
117
|
+
if command_exists docker-compose; then
|
|
118
|
+
print_success "docker-compose found"
|
|
119
|
+
else
|
|
120
|
+
print_error "docker-compose not found"
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
echo ""
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
install_dependencies() {
|
|
129
|
+
print_header "INSTALLING DEPENDENCIES"
|
|
130
|
+
|
|
131
|
+
if [ "$CLEAN_INSTALL" = true ]; then
|
|
132
|
+
print_step "Removing existing node_modules"
|
|
133
|
+
if [ -d "$REPO_ROOT/node_modules" ]; then
|
|
134
|
+
rm -rf "$REPO_ROOT/node_modules"
|
|
135
|
+
print_success "Removed node_modules"
|
|
136
|
+
fi
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
print_step "Running npm install"
|
|
140
|
+
cd "$REPO_ROOT"
|
|
141
|
+
npm install
|
|
142
|
+
|
|
143
|
+
print_success "Dependencies installed"
|
|
144
|
+
echo ""
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
start_dev_server() {
|
|
148
|
+
print_header "STARTING DEVELOPMENT SERVER"
|
|
149
|
+
|
|
150
|
+
cd "$REPO_ROOT"
|
|
151
|
+
|
|
152
|
+
# Check if package.json has a dev script
|
|
153
|
+
if grep -q '"dev"' package.json 2>/dev/null; then
|
|
154
|
+
print_step "Starting npm dev server"
|
|
155
|
+
npm run dev &
|
|
156
|
+
local server_pid=$!
|
|
157
|
+
|
|
158
|
+
# Wait for server to start
|
|
159
|
+
sleep 3
|
|
160
|
+
|
|
161
|
+
print_success "Dev server started (PID: $server_pid)"
|
|
162
|
+
echo ""
|
|
163
|
+
echo -e "${BLUE}Dev Server:${NC} http://localhost:$DEV_PORT"
|
|
164
|
+
echo ""
|
|
165
|
+
|
|
166
|
+
return
|
|
167
|
+
else
|
|
168
|
+
print_step "No dev script found in package.json"
|
|
169
|
+
print_step "Starting static server on port $DEV_PORT"
|
|
170
|
+
|
|
171
|
+
# Check if Python is available for quick server
|
|
172
|
+
if command_exists python3; then
|
|
173
|
+
cd "$REPO_ROOT/app"
|
|
174
|
+
python3 -m http.server $DEV_PORT &
|
|
175
|
+
local server_pid=$!
|
|
176
|
+
sleep 1
|
|
177
|
+
print_success "Static server started (PID: $server_pid)"
|
|
178
|
+
echo ""
|
|
179
|
+
echo -e "${BLUE}Static Server:${NC} http://localhost:$DEV_PORT/app/"
|
|
180
|
+
echo ""
|
|
181
|
+
return
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
# Fallback to Node.js http-server if available
|
|
185
|
+
if command_exists http-server; then
|
|
186
|
+
http-server "$REPO_ROOT/app" -p $DEV_PORT &
|
|
187
|
+
local server_pid=$!
|
|
188
|
+
sleep 1
|
|
189
|
+
print_success "http-server started (PID: $server_pid)"
|
|
190
|
+
echo ""
|
|
191
|
+
echo -e "${BLUE}Server:${NC} http://localhost:$DEV_PORT"
|
|
192
|
+
echo ""
|
|
193
|
+
return
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
print_error "No dev server available"
|
|
197
|
+
echo ""
|
|
198
|
+
echo "Options:"
|
|
199
|
+
echo " 1. Install http-server: npm install -g http-server"
|
|
200
|
+
echo " 2. Use Docker: ./scripts/dev-setup.sh --docker"
|
|
201
|
+
echo " 3. Add a 'dev' script to package.json"
|
|
202
|
+
fi
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
start_docker() {
|
|
206
|
+
print_header "STARTING DOCKER ENVIRONMENT"
|
|
207
|
+
|
|
208
|
+
print_step "Building Docker images"
|
|
209
|
+
cd "$REPO_ROOT"
|
|
210
|
+
docker-compose build
|
|
211
|
+
|
|
212
|
+
print_success "Images built"
|
|
213
|
+
echo ""
|
|
214
|
+
|
|
215
|
+
print_step "Starting docker-compose"
|
|
216
|
+
docker-compose up -d
|
|
217
|
+
|
|
218
|
+
# Wait for services
|
|
219
|
+
sleep 3
|
|
220
|
+
|
|
221
|
+
print_success "Docker services started"
|
|
222
|
+
echo ""
|
|
223
|
+
echo -e "${BLUE}Services:${NC}"
|
|
224
|
+
echo " • Web App: http://localhost:8080/app/"
|
|
225
|
+
echo " • Converter: http://localhost:8787/health"
|
|
226
|
+
echo " • Signaling: http://localhost:8788/health"
|
|
227
|
+
echo ""
|
|
228
|
+
echo "View logs: docker-compose logs -f"
|
|
229
|
+
echo "Stop services: docker-compose down"
|
|
230
|
+
echo ""
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
print_usage() {
|
|
234
|
+
print_header "USAGE"
|
|
235
|
+
|
|
236
|
+
echo "Development Setup Options:"
|
|
237
|
+
echo ""
|
|
238
|
+
echo " ./scripts/dev-setup.sh # Full setup + open browser"
|
|
239
|
+
echo " ./scripts/dev-setup.sh --no-browser # Setup but don't open browser"
|
|
240
|
+
echo " ./scripts/dev-setup.sh --docker # Use Docker instead of local dev"
|
|
241
|
+
echo " ./scripts/dev-setup.sh --clean # Clean install (remove node_modules)"
|
|
242
|
+
echo " ./scripts/dev-setup.sh --help # Show this help"
|
|
243
|
+
echo ""
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
################################################################################
|
|
247
|
+
# Main Script
|
|
248
|
+
################################################################################
|
|
249
|
+
|
|
250
|
+
main() {
|
|
251
|
+
# Parse command-line arguments
|
|
252
|
+
while [ $# -gt 0 ]; do
|
|
253
|
+
case "$1" in
|
|
254
|
+
--no-browser)
|
|
255
|
+
OPEN_BROWSER=false
|
|
256
|
+
shift
|
|
257
|
+
;;
|
|
258
|
+
--docker)
|
|
259
|
+
USE_DOCKER=true
|
|
260
|
+
shift
|
|
261
|
+
;;
|
|
262
|
+
--clean)
|
|
263
|
+
CLEAN_INSTALL=true
|
|
264
|
+
shift
|
|
265
|
+
;;
|
|
266
|
+
--help)
|
|
267
|
+
print_usage
|
|
268
|
+
exit 0
|
|
269
|
+
;;
|
|
270
|
+
*)
|
|
271
|
+
echo "Unknown option: $1"
|
|
272
|
+
print_usage
|
|
273
|
+
exit 1
|
|
274
|
+
;;
|
|
275
|
+
esac
|
|
276
|
+
done
|
|
277
|
+
|
|
278
|
+
# Welcome message
|
|
279
|
+
echo ""
|
|
280
|
+
echo -e "${BLUE}╔═══════════════════════════════════════════════════╗${NC}"
|
|
281
|
+
echo -e "${BLUE}║ cycleCAD Development Setup ║${NC}"
|
|
282
|
+
echo -e "${BLUE}║ Quick local development environment ║${NC}"
|
|
283
|
+
echo -e "${BLUE}╚═══════════════════════════════════════════════════╝${NC}"
|
|
284
|
+
echo ""
|
|
285
|
+
|
|
286
|
+
check_prerequisites
|
|
287
|
+
|
|
288
|
+
if [ "$USE_DOCKER" = true ]; then
|
|
289
|
+
start_docker
|
|
290
|
+
else
|
|
291
|
+
install_dependencies
|
|
292
|
+
start_dev_server
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
# Open browser if requested
|
|
296
|
+
if [ "$OPEN_BROWSER" = true ]; then
|
|
297
|
+
if [ "$USE_DOCKER" = true ]; then
|
|
298
|
+
sleep 2
|
|
299
|
+
open_browser "http://localhost:8080/app/"
|
|
300
|
+
else
|
|
301
|
+
sleep 1
|
|
302
|
+
open_browser "http://localhost:$DEV_PORT/app/"
|
|
303
|
+
fi
|
|
304
|
+
fi
|
|
305
|
+
|
|
306
|
+
print_header "DEVELOPMENT ENVIRONMENT READY"
|
|
307
|
+
|
|
308
|
+
echo "Next steps:"
|
|
309
|
+
echo " 1. Open your browser and start developing"
|
|
310
|
+
echo " 2. Make changes to files in the app/ directory"
|
|
311
|
+
echo " 3. Refresh browser to see changes"
|
|
312
|
+
echo ""
|
|
313
|
+
|
|
314
|
+
if [ "$USE_DOCKER" = true ]; then
|
|
315
|
+
echo "Useful Docker commands:"
|
|
316
|
+
echo " docker-compose logs -f # View all logs"
|
|
317
|
+
echo " docker-compose logs -f converter # View converter logs"
|
|
318
|
+
echo " docker-compose ps # Service status"
|
|
319
|
+
echo " docker-compose down # Stop services"
|
|
320
|
+
echo ""
|
|
321
|
+
else
|
|
322
|
+
echo "Useful development commands:"
|
|
323
|
+
echo " npm run build # Build for production"
|
|
324
|
+
echo " npm test # Run tests (if configured)"
|
|
325
|
+
echo " npm run lint # Lint code (if configured)"
|
|
326
|
+
echo ""
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
echo "Documentation:"
|
|
330
|
+
echo " • Quick start: docs/DOCKER-QUICK-TEST.md"
|
|
331
|
+
echo " • Full guide: docs/README.md"
|
|
332
|
+
echo ""
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# Run main if script is executed directly
|
|
336
|
+
if [ "${BASH_SOURCE[0]}" == "${0}" ]; then
|
|
337
|
+
main "$@"
|
|
338
|
+
fi
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# cycleCAD Docker Health Check Script
|
|
4
|
+
# Verifies all services are running and healthy
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ./scripts/docker-health-check.sh
|
|
8
|
+
# ./scripts/docker-health-check.sh --verbose
|
|
9
|
+
# ./scripts/docker-health-check.sh --timeout 60
|
|
10
|
+
#
|
|
11
|
+
# Exit codes:
|
|
12
|
+
# 0 — All services healthy
|
|
13
|
+
# 1 — One or more services unhealthy
|
|
14
|
+
# 2 — Docker not available
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
set -e
|
|
18
|
+
|
|
19
|
+
# Color codes for output
|
|
20
|
+
RED='\033[0;31m'
|
|
21
|
+
GREEN='\033[0;32m'
|
|
22
|
+
YELLOW='\033[1;33m'
|
|
23
|
+
BLUE='\033[0;34m'
|
|
24
|
+
NC='\033[0m' # No Color
|
|
25
|
+
|
|
26
|
+
# Configuration
|
|
27
|
+
VERBOSE=false
|
|
28
|
+
TIMEOUT=30
|
|
29
|
+
INTERVAL=5
|
|
30
|
+
|
|
31
|
+
# Parse arguments
|
|
32
|
+
while [[ $# -gt 0 ]]; do
|
|
33
|
+
case $1 in
|
|
34
|
+
--verbose|-v)
|
|
35
|
+
VERBOSE=true
|
|
36
|
+
shift
|
|
37
|
+
;;
|
|
38
|
+
--timeout)
|
|
39
|
+
TIMEOUT="$2"
|
|
40
|
+
shift 2
|
|
41
|
+
;;
|
|
42
|
+
*)
|
|
43
|
+
echo "Unknown option: $1"
|
|
44
|
+
echo "Usage: $0 [--verbose] [--timeout SECONDS]"
|
|
45
|
+
exit 1
|
|
46
|
+
;;
|
|
47
|
+
esac
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
# Check if docker is available
|
|
51
|
+
if ! command -v docker &> /dev/null; then
|
|
52
|
+
echo -e "${RED}Error: Docker is not installed or not in PATH${NC}"
|
|
53
|
+
exit 2
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
if ! command -v docker-compose &> /dev/null && ! command -v docker compose &> /dev/null; then
|
|
57
|
+
echo -e "${RED}Error: Docker Compose is not installed or not in PATH${NC}"
|
|
58
|
+
exit 2
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Determine docker-compose command
|
|
62
|
+
if command -v docker-compose &> /dev/null; then
|
|
63
|
+
DC_CMD="docker-compose"
|
|
64
|
+
else
|
|
65
|
+
DC_CMD="docker compose"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
echo -e "${BLUE}=== cycleCAD Docker Health Check ===${NC}"
|
|
69
|
+
echo -e "${BLUE}Timeout: ${TIMEOUT}s, Interval: ${INTERVAL}s${NC}"
|
|
70
|
+
echo ""
|
|
71
|
+
|
|
72
|
+
# Service definitions
|
|
73
|
+
declare -A SERVICES=(
|
|
74
|
+
[cyclecad]="cyclecad-app:80:/health"
|
|
75
|
+
[converter]="cyclecad-converter:8787:/health"
|
|
76
|
+
[signaling]="cyclecad-signaling:8788:/health"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Check if docker-compose project is running
|
|
80
|
+
echo -e "${BLUE}Checking Docker Compose project status...${NC}"
|
|
81
|
+
if ! $DC_CMD ps --services &> /dev/null; then
|
|
82
|
+
echo -e "${RED}Error: No Docker Compose project found. Run 'docker-compose up -d' first.${NC}"
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
HEALTHY_COUNT=0
|
|
87
|
+
UNHEALTHY_COUNT=0
|
|
88
|
+
ELAPSED=0
|
|
89
|
+
|
|
90
|
+
# Check each service
|
|
91
|
+
echo ""
|
|
92
|
+
for SERVICE in "${!SERVICES[@]}"; do
|
|
93
|
+
IFS=':' read -r CONTAINER PORT ENDPOINT <<< "${SERVICES[$SERVICE]}"
|
|
94
|
+
|
|
95
|
+
echo -n "Checking ${SERVICE}... "
|
|
96
|
+
|
|
97
|
+
# Check if container is running
|
|
98
|
+
if ! docker ps --filter "name=${CONTAINER}" --format "{{.Names}}" | grep -q "^${CONTAINER}$"; then
|
|
99
|
+
echo -e "${RED}FAILED${NC} (container not running)"
|
|
100
|
+
UNHEALTHY_COUNT=$((UNHEALTHY_COUNT + 1))
|
|
101
|
+
continue
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Try to connect to health endpoint
|
|
105
|
+
HEALTH_URL="http://localhost:${PORT}${ENDPOINT}"
|
|
106
|
+
RESPONSE=""
|
|
107
|
+
|
|
108
|
+
ELAPSED=0
|
|
109
|
+
while [ $ELAPSED -lt $TIMEOUT ]; do
|
|
110
|
+
if RESPONSE=$(curl -s -f "$HEALTH_URL" 2>/dev/null); then
|
|
111
|
+
# Check response status
|
|
112
|
+
if echo "$RESPONSE" | grep -q '"status":"ok"'; then
|
|
113
|
+
echo -e "${GREEN}OK${NC}"
|
|
114
|
+
HEALTHY_COUNT=$((HEALTHY_COUNT + 1))
|
|
115
|
+
|
|
116
|
+
if [ "$VERBOSE" = true ]; then
|
|
117
|
+
echo " └─ Response: $RESPONSE"
|
|
118
|
+
fi
|
|
119
|
+
break
|
|
120
|
+
else
|
|
121
|
+
echo -e "${YELLOW}PARTIAL${NC} (responded but status not ok)"
|
|
122
|
+
UNHEALTHY_COUNT=$((UNHEALTHY_COUNT + 1))
|
|
123
|
+
break
|
|
124
|
+
fi
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
ELAPSED=$((ELAPSED + INTERVAL))
|
|
128
|
+
if [ $ELAPSED -lt $TIMEOUT ]; then
|
|
129
|
+
sleep $INTERVAL
|
|
130
|
+
fi
|
|
131
|
+
done
|
|
132
|
+
|
|
133
|
+
if [ $ELAPSED -ge $TIMEOUT ] && [ -z "$RESPONSE" ]; then
|
|
134
|
+
echo -e "${RED}TIMEOUT${NC} (no response after ${TIMEOUT}s)"
|
|
135
|
+
UNHEALTHY_COUNT=$((UNHEALTHY_COUNT + 1))
|
|
136
|
+
fi
|
|
137
|
+
done
|
|
138
|
+
|
|
139
|
+
echo ""
|
|
140
|
+
echo -e "${BLUE}=== Summary ===${NC}"
|
|
141
|
+
echo -e "Healthy: ${GREEN}${HEALTHY_COUNT}${NC}"
|
|
142
|
+
echo -e "Unhealthy: ${RED}${UNHEALTHY_COUNT}${NC}"
|
|
143
|
+
echo ""
|
|
144
|
+
|
|
145
|
+
# Check Docker Compose health status
|
|
146
|
+
if [ "$VERBOSE" = true ]; then
|
|
147
|
+
echo -e "${BLUE}=== Docker Compose Status ===${NC}"
|
|
148
|
+
$DC_CMD ps
|
|
149
|
+
echo ""
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# Exit with appropriate code
|
|
153
|
+
if [ $UNHEALTHY_COUNT -gt 0 ]; then
|
|
154
|
+
echo -e "${RED}Health check FAILED${NC}"
|
|
155
|
+
exit 1
|
|
156
|
+
else
|
|
157
|
+
echo -e "${GREEN}All services healthy!${NC}"
|
|
158
|
+
exit 0
|
|
159
|
+
fi
|