feat(F-054): completed feature

This commit is contained in:
chattie
2026-08-19 13:15:30 +02:00
parent 6a74f5ede6
commit de41a42d88
17 changed files with 446 additions and 100 deletions

View File

@@ -15,6 +15,7 @@ FRONTEND_PORT="${FRONTEND_PORT:-3003}"
ADMIN_PORT="${ADMIN_PORT:-3004}"
STOREFRONT_PORT="${STOREFRONT_PORT:-3005}"
START_TIMEOUT="${START_TIMEOUT:-90}"
WATCH_INTERVAL="${WATCH_INTERVAL:-5}"
SERVICES=(backend frontend admin storefront)
@@ -29,6 +30,7 @@ Commands:
stop Gracefully stop every managed HTTP process
logs Follow all service logs (Ctrl-C exits without stopping services)
urls Print localhost and LAN URLs
watch Auto-respawn any dead service every WATCH_INTERVAL seconds
Environment overrides:
LAN_IP, BACKEND_PORT, FRONTEND_PORT, ADMIN_PORT, STOREFRONT_PORT
@@ -41,7 +43,7 @@ if [[ "$MODE" != "dev" && "$MODE" != "prod" ]]; then
exit 2
fi
case "$ACTION" in
start|restart|status|stop|logs|urls) ;;
start|restart|status|stop|logs|urls|watch) ;;
*) usage >&2; exit 2 ;;
esac
@@ -238,28 +240,28 @@ spawn_service() {
case "$MODE:$service" in
dev:backend)
(cd "$dir" && nohup env HOST=0.0.0.0 PORT="$port" NODE_ENV=development node --env-file=.env node_modules/tsx/dist/cli.mjs watch src/infrastructure/http/server.ts >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$dir" && nohup env HOST=0.0.0.0 PORT="$port" NODE_ENV=development node --env-file=.env node_modules/tsx/dist/cli.mjs watch src/infrastructure/http/server.ts >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
prod:backend)
(cd "$dir" && nohup env HOST=0.0.0.0 PORT="$port" NODE_ENV=production node --env-file=.env dist/infrastructure/http/server.js >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$dir" && nohup env HOST=0.0.0.0 PORT="$port" NODE_ENV=production node --env-file=.env dist/infrastructure/http/server.js >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
dev:admin)
(cd "$PROJECT_DIR/apps/admin" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$PROJECT_DIR/apps/admin" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
prod:admin)
(cd "$PROJECT_DIR/apps/admin" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$PROJECT_DIR/apps/admin" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
dev:frontend)
(cd "$PROJECT_DIR/frontend" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$PROJECT_DIR/frontend" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
prod:frontend)
(cd "$PROJECT_DIR/frontend" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$PROJECT_DIR/frontend" && nohup env NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
dev:storefront)
(cd "$PROJECT_DIR/storefront" && nohup env API_BASE_URL="$API_PUBLIC_URL" NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$PROJECT_DIR/storefront" && nohup env API_BASE_URL="$API_PUBLIC_URL" NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
prod:storefront)
(cd "$PROJECT_DIR/storefront" && nohup env API_BASE_URL="$API_PUBLIC_URL" NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 & echo $! >"$pidfile")
(cd "$PROJECT_DIR/storefront" && nohup env API_BASE_URL="$API_PUBLIC_URL" NEXT_PUBLIC_API_URL="$API_PUBLIC_URL" node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port "$port" >"$log" 2>&1 < /dev/null & disown; echo $! >"$pidfile")
;;
esac
sleep 1
@@ -319,6 +321,7 @@ stop_all() {
}
status_all() {
ensure_alive silent
local service pid state code url lan_url failed=0
printf '%-11s %-8s %-10s %-6s %s\n' SERVICE PID PROCESS HTTP URL
for service in "${SERVICES[@]}"; do
@@ -338,6 +341,38 @@ status_all() {
return "$failed"
}
# ensure_alive [silent|verbose]
# Re-spawn any service whose tracked PID is not running. Used by `status`
# so an operator who runs `monolith.sh status` always sees live processes
# even after a backend crash with no error trace.
ensure_alive() {
local verbose="${1:-silent}" service pid
[[ "$verbose" == "verbose" ]] || verbose='silent'
for service in "${SERVICES[@]}"; do
pid="$(read_pid "$service")"
if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
continue
fi
if [[ "$verbose" == "verbose" ]]; then
echo "[WATCHDOG] $service not running (last PID: ${pid:-none}); respawning..."
fi
rm -f "$(pid_file "$service")"
# Only respawn if infrastructure is reachable; otherwise let `start` handle it.
if (cd "$PROJECT_DIR" && docker ps --format '{{.Names}}' 2>/dev/null | grep -qE '^(mdv-dev-postgres|mdv-dev-redis)$'); then
spawn_service "$service" || true
fi
done
}
watch_loop() {
echo "[WATCHDOG] watching services every ${WATCH_INTERVAL}s (Ctrl+C to stop)"
ensure_alive verbose
while true; do
sleep "$WATCH_INTERVAL"
ensure_alive verbose
done
}
print_urls() {
cat <<EOF
Mode: $MODE
@@ -369,4 +404,5 @@ case "$ACTION" in
stop) stop_all ;;
logs) follow_logs ;;
urls) print_urls ;;
watch) watch_loop ;;
esac