Initial commit: reorganized source tree

- backend/: 13 Maven modules (cw-elevator-application, cloudwalk-cloud, intelligent-cwoscomponent, ninca-crk, etc.)
- frontend/: 4 Vue projects (elevator-front, cwos-portal, alarm-front, front_acs) + decompiled + scripts
- scripts/: build, test-env, tools (Docker Compose, service templates, API parity)
- docs/: AGENTS.md, superpowers specs, architecture docs
- .gitignore: standard Java/Maven exclusions

Moved from legacy maven-*/ root layout to backend/ organized structure.
This commit is contained in:
hpd840321
2026-05-09 09:00:12 +08:00
commit 7b2bd307f1
7260 changed files with 612980 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
# build-elevator-v2.sh — 编译 cw-elevator-application V2
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
log_info "Building V2 elevator application..."
cd "$REPO_ROOT/maven-cw-elevator-application"
export JAVA_HOME
export PATH="$JAVA_HOME/bin:$PATH"
log_info "JDK: $($JAVA -version 2>&1 | head -1)"
# Build (skip tests)
$MVN clean install $MVN_OPTS 2>&1 | tail -5
if [[ ${PIPESTATUS[0]} -eq 0 ]]; then
log_ok "V2 elevator build SUCCESS"
else
log_error "V2 elevator build FAILED — check logs"
exit 1
fi
# Sync JAR to deploy/ — use wildcard to match any version
LATEST_JAR=$(ls -t cw-elevator-application-starter/target/cw-elevator-application-*.jar 2>/dev/null | grep -v sources | head -1)
if [[ -n "$LATEST_JAR" ]]; then
cp "$LATEST_JAR" deploy/v2-maven/
log_ok "JAR synced: $(basename "$LATEST_JAR") → deploy/v2-maven/"
else
log_error "No JAR found in target/"
exit 1
fi
+94
View File
@@ -0,0 +1,94 @@
#!/bin/bash
# V2 测试环境 — 统一环境变量
# 所有脚本 source 此文件获取统一配置
set -euo pipefail
# ============================================
# 路径
# ============================================
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
STAR_CENTER="$REPO_ROOT/../runtime"
DATA_BACKUP="$REPO_ROOT/../data-backups"
TEST_ENV_DIR="$REPO_ROOT/scripts/test-env"
SERVICE_DIR="$TEST_ENV_DIR/services"
LOG_DIR="$TEST_ENV_DIR/logs"
# ============================================
# Java
# ============================================
JAVA_HOME="${DEPLOY_JDK8:-/usr/lib/jvm/java-8-openjdk-amd64}"
JAVA="$JAVA_HOME/bin/java"
JAVA_OPTS_HEAVY="-Xmx3072m -Xms3072m -Xmn1024m"
JAVA_OPTS_LIGHT="-Xmx2048m -Xms512m"
JAVA_OPTS_DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n"
# ============================================
# 基础设施地址
# ============================================
MYSQL_HOST=192.168.3.12
MYSQL_PORT=3307
MYSQL_USER=root
MYSQL_PASS=123456
REDIS_HOST=127.0.0.1
REDIS_PORT=6380
REDIS_PASS="1qaz!QAZ"
CONSUL_HOST=127.0.0.1
CONSUL_PORT=9517
KAFKA_HOST=127.0.0.1
KAFKA_PORT=9092
ZK_HOST=127.0.0.1
ZK_PORT=2181
# ============================================
# 服务端口
# ============================================
PORT_ELEVATOR_V2=18081
PORT_ELEVATOR_V1=18080
PORT_CRK_STD=16106
PORT_CRK_MGMT=16114
PORT_ALARM=17011
PORT_ALARM_MGMT=17211
PORT_CWOS_PORTAL=33008
PORT_COMPONENT_ORG=33011
PORT_NINCA_COMMON=33010
PORT_CWOS_MANAGER=3721
PORT_SYSTEM_API=3333
PORT_SNAP_APP=33012
PORT_VEHICLE_APP=33013
PORT_PERSON_FILE=33014
PORT_MONITOR_APP=33015
PORT_NGINX=8090
# ============================================
# 数据库名
# ============================================
DB_ELEVATOR="cw-elevator-application"
DB_CRK="ninca_crk_std"
DB_ALARM="alarm_deploy"
DB_MANAGER="cwos_manager"
DB_PORTAL="cwos_portal"
DB_COMMON="ninca_common"
DB_COMPONENT_ORG="component-organization"
DB_ODS="ods"
DB_THIRDPARTY="cloudwalk_device_thirdparty"
DB_G="g"
DB_P="p"
DB_12="12"
DB_34="34"
# ============================================
# Maven
# ============================================
MVN="mvn"
MVN_OPTS="-DskipTests -Dformatter-maven-plugin.version=2.16.0"
ELEVATOR_POM="$REPO_ROOT/backend/cw-elevator-application/pom.xml"
# ============================================
# 日志颜色
# ============================================
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
@@ -0,0 +1,41 @@
# Alarm app test config
spring.application.name=ninca-qk-alarm-app
server.port=__ALARM_PORT__
spring.main.allow-bean-definition-overriding=true
# Consul
spring.cloud.consul.host=__CONSUL_HOST__
spring.cloud.consul.port=__CONSUL_PORT__
spring.cloud.consul.discovery.register=true
spring.cloud.consul.discovery.ip-address=127.0.0.1
# MySQL
spring.datasource.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/alarm_deploy?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
# Redis
spring.redis.host=__REDIS_HOST__
spring.redis.port=6379
spring.redis.password=__REDIS_PASS__
spring.redis.database=7
# Kafka
kafka.producer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
kafka.consumer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
spring.kafka.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
spring.kafka.consumer.group-id=alarm_test
# Feign names
cloudwalk.alarm-app.feign.name.cwos-portal=cwos-portal
cloudwalk.alarm-app.feign.name.component-organization=ninca-common-component-organization
cloudwalk.alarm-app.feign.name.ninca-common=ninca-common
# Management
management.port=__ALARM_MGMT_PORT__
management.context-path=/actuator
management.security.enabled=false
# Disable non-essential features for test
swagger.enable=false
sendRecord.boolean=false
@@ -0,0 +1,11 @@
server.port=__COMPONENT_ORG_PORT__
spring.application.name=ninca-common-component-organization
spring.datasource.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/component-organization?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.cloud.consul.host=__CONSUL_HOST__
spring.cloud.consul.port=__CONSUL_PORT__
spring.cloud.consul.discovery.register=true
spring.redis.host=__REDIS_HOST__
spring.redis.port=6379
spring.redis.password=__REDIS_PASS__
@@ -0,0 +1,54 @@
# CRK-std test config
spring.application.name=ninca-crk-std
server.port=__CRK_PORT__
spring.profiles.active=smart-attendance,visitor-management,access-control,conference-attendance
# Consul
spring.cloud.consul.host=__CONSUL_HOST__
spring.cloud.consul.port=__CONSUL_PORT__
spring.cloud.consul.discovery.register=true
spring.cloud.consul.discovery.ip-address=127.0.0.1
# MySQL
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/ninca_crk_std?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
# Redis
spring.redis.host=__REDIS_HOST__
spring.redis.port=6379
spring.redis.password=__REDIS_PASS__
spring.redis.database=5
# Kafka
kafka.producer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
kafka.consumer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
spring.kafka.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
spring.kafka.consumer.group-id=crk_std_test
cloudwalk.event.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
cloudwalk.event.group-id=crk_std
# Feign service names
feign.device.name=cwos-portal
feign.resource.name=cwos-portal
feign.cwos-portal.name=cwos-portal
feign.portal.name=cwos-portal
feign.component-organization.name=ninca-common-component-organization
feign.davinci-portal.name=cwos-portal
feign.ninca-common.name=ninca-common
feign.elevator.name=elevator-app
# Quartz
quartz.driver=com.mysql.jdbc.Driver
quartz.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/ninca_crk_std?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
quartz.user=root
quartz.password=123456
# Management
management.port=__CRK_MGMT_PORT__
management.context-path=/actuator
management.security.enabled=false
xinhewan.businessid=2524639890ba4f2cba9ba1a4eeaa4015
push.method=1
sendRecord.boolean=false
@@ -0,0 +1,48 @@
# V2 elevator test config — auto-generated from template
# Variables: __MYSQL_HOST__ __MYSQL_PORT__ __REDIS_HOST__ __REDIS_PASS__
# __CONSUL_HOST__ __CONSUL_PORT__ __KAFKA_HOST__ __KAFKA_PORT__
# __CRK_HOST__ __CRK_PORT__
server.port=18081
spring.application.name=elevator-app
spring.profiles.active=access-control
# Consul
spring.cloud.consul.host=__CONSUL_HOST__
spring.cloud.consul.port=__CONSUL_PORT__
spring.cloud.consul.enabled=true
spring.cloud.consul.discovery.register=true
spring.cloud.consul.discovery.enabled=false
# MySQL (ShardingSphere)
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/cw-elevator-application?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
# Redis
spring.redis.host=__REDIS_HOST__
spring.redis.port=6379
spring.redis.password=__REDIS_PASS__
spring.redis.database=5
# Kafka
cloudwalk.event.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
cloudwalk.event.group-id=cw-elevator-application-test
# Feign targets
feign.device.name=cwos-portal
feign.cwos-portal.name=cwos-portal
feign.ninca-crk-std.name=ninca-crk-std
ninca-crk-std.ribbon.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList
ninca-crk-std.ribbon.listOfServers=__CRK_HOST__:__CRK_PORT__
ninca-crk-std.ip=__CRK_HOST__:__CRK_PORT__
# Other
feign.hystrix.enable=true
feign.okhttp.enable=true
ribbon.ReadTimeout=10000
ribbon.ConnectTimeout=10000
elevator.application.key=xinghewan
elevator.application.time=600
elevator.application.keyA=5B7DEF88FF04
floor.building.id=605560539791228928
sendRecord.boolean=false
@@ -0,0 +1,11 @@
server.port=__NINCA_COMMON_PORT__
spring.application.name=ninca-common
spring.datasource.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/ninca_common?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.cloud.consul.host=__CONSUL_HOST__
spring.cloud.consul.port=__CONSUL_PORT__
spring.cloud.consul.discovery.register=true
spring.redis.host=__REDIS_HOST__
spring.redis.port=6379
spring.redis.password=__REDIS_PASS__
+36
View File
@@ -0,0 +1,36 @@
services:
consul:
image: hashicorp/consul:1.22
container_name: v2test-consul
restart: unless-stopped
ports:
- "9517:8500"
command: >
agent -server -bootstrap-expect=1 -ui
-client=0.0.0.0 -bind=0.0.0.0
-data-dir=/consul/data
volumes:
- consul-data:/consul/data
redis:
image: redis:7-alpine
container_name: v2test-redis
restart: unless-stopped
ports:
- "6380:6379"
command: redis-server --requirepass "1qaz!QAZ"
nginx:
image: nginx:alpine
container_name: v2test-nginx
restart: unless-stopped
ports:
- "8090:80"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ../../frontend:/data/cwos/frontend:ro
- ../../nginx.frontend-local.conf:/etc/nginx/conf.d/default.conf:ro
volumes:
consul-data:
+53
View File
@@ -0,0 +1,53 @@
#!/bin/bash
# health-check.sh — 全组件探活检查
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
log_info "=== Health Check ==="
FAILED=0
PASSED=0
check_http() {
local name="$1"; local url="$2"
if curl -sf --max-time 5 "$url" &>/dev/null; then
log_ok " $name ($url)"
((PASSED++))
else
log_error " $name ($url) FAILED"
((FAILED++))
fi
}
check_tcp() {
local name="$1"; local host="$2"; local port="$3"
if nc -z -w3 "$host" "$port" &>/dev/null; then
log_ok " $name ($host:$port)"
((PASSED++))
else
log_error " $name ($host:$port) FAILED"
((FAILED++))
fi
}
log_info "--- Infrastructure ---"
check_http "Consul" "http://$CONSUL_HOST:$CONSUL_PORT/v1/status/leader"
check_tcp "Redis" "$REDIS_HOST" "$REDIS_PORT"
check_tcp "Kafka" "$KAFKA_HOST" "$KAFKA_PORT"
check_http "Nginx" "http://$CONSUL_HOST:$PORT_NGINX"
log_info "--- Application Services ---"
check_http "elevator-v2" "http://127.0.0.1:$PORT_ELEVATOR_V2/health"
check_http "elevator-v1" "http://127.0.0.1:$PORT_ELEVATOR_V1/health"
check_http "crk-std" "http://127.0.0.1:$PORT_CRK_MGMT/health"
check_http "alarm-app" "http://127.0.0.1:$PORT_ALARM_MGMT/health"
log_info "--- Databases ---"
check_tcp "MySQL" "$MYSQL_HOST" "$MYSQL_PORT"
log_info "--- Consul Registration ---"
CONSUL_SVCS=$(curl -sf "http://$CONSUL_HOST:$CONSUL_PORT/v1/agent/services" 2>/dev/null | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo "0")
log_info " Registered services: $CONSUL_SVCS"
echo ""
log_info "=== Result: $PASSED passed, $FAILED failed ==="
[[ $FAILED -eq 0 ]] && exit 0 || exit 1
+91
View File
@@ -0,0 +1,91 @@
#!/bin/bash
# prepare-db.sh — 恢复 11 个数据库 SQL 备份到 MySQL
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
log_info "Phase 2: Database preparation"
log_info "Target: $MYSQL_HOST:$MYSQL_PORT (user: $MYSQL_USER)"
MYSQL_CMD="mysql -h $MYSQL_HOST -P $MYSQL_PORT -u $MYSQL_USER -p${MYSQL_PASS}"
# Check MySQL connectivity
if ! $MYSQL_CMD -e "SELECT 1" &>/dev/null; then
log_error "Cannot connect to MySQL at $MYSQL_HOST:$MYSQL_PORT"
exit 1
fi
log_ok "MySQL connection OK"
# DB name → backup file mapping
declare -A DB_MAP=(
["$DB_ELEVATOR"]="12_2026_04_23_17_28_33.sql.gz"
["$DB_ALARM"]="alarm_deploy_2026_04_23_17_28_33.sql.gz"
["$DB_MANAGER"]="cwos_manager_2026_04_23_17_28_33.sql.gz"
["$DB_PORTAL"]="cwos_portal_2026_04_23_17_28_33.sql.gz"
["$DB_COMMON"]="ninca_common_2026_04_23_17_28_33.sql.gz"
["$DB_COMPONENT_ORG"]="component-organization_2026_04_23_17_28_33.sql.gz"
["$DB_ODS"]="ods_2026_04_23_17_28_33.sql.gz"
["$DB_THIRDPARTY"]="cloudwalk_device_thirdparty_2026_04_23_17_28_33.sql.gz"
["$DB_G"]="g_2026_04_23_17_28_33.sql.gz"
["$DB_P"]="p_2026_04_23_17_28_33.sql.gz"
)
# Check if DB exists and has tables — skip restore if already populated
db_has_tables() {
local db="$1"
local count
count=$($MYSQL_CMD -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$db'" 2>/dev/null || echo "0")
[[ "$count" -gt 0 ]]
}
for db_name in "${!DB_MAP[@]}"; do
backup_file="${DB_MAP[$db_name]}"
backup_path="$DATA_BACKUP/$backup_file"
if [[ ! -f "$backup_path" ]]; then
log_warn "Backup not found: $backup_path — skipping $db_name"
continue
fi
# Idempotency: skip if DB already has data
if db_has_tables "$db_name"; then
log_ok " $db_name already exists ($(du -h "$backup_path" | cut -f1) backup skipped)"
continue
fi
log_info "Restoring $db_name from $backup_file ($(du -h "$backup_path" | cut -f1))..."
# Create DB if not exists
$MYSQL_CMD -e "CREATE DATABASE IF NOT EXISTS \`$db_name\` DEFAULT CHARACTER SET utf8mb4;"
# Import (strip multi-line GTID_PURGED to avoid MySQL error 1840)
zcat "$backup_path" | sed '/SET @@GLOBAL.GTID_PURGED=/,/;/d' | $MYSQL_CMD "$db_name" 2>&1 | tail -1
if [[ ${PIPESTATUS[0]} -eq 0 ]]; then
log_ok " $db_name restored successfully"
else
log_error " $db_name restore FAILED"
fi
done
# Elevator app also needs second backup (34_*.sql.gz) — skip if DB already populated
if [[ -f "$DATA_BACKUP/34_2026_04_23_17_28_33.sql.gz" ]]; then
if db_has_tables "$DB_ELEVATOR"; then
log_ok " $DB_ELEVATOR partition 34 skipped (DB already populated)"
else
log_info "Restoring elevator DB partition 34..."
zcat "$DATA_BACKUP/34_2026_04_23_17_28_33.sql.gz" | sed '/SET @@GLOBAL.GTID_PURGED=/,/;/d' | $MYSQL_CMD "$DB_ELEVATOR"
log_ok " $DB_ELEVATOR partition 34 restored"
fi
fi
# Apply V2.0.7 DDL (tenant_visitor_floor_policy) — skip if table exists
log_info "Checking V2.0.7 DDL (tenant_visitor_floor_policy)..."
TABLE_EXISTS=$($MYSQL_CMD -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DB_ELEVATOR' AND table_name='tenant_visitor_floor_policy'" 2>/dev/null || echo "0")
if [[ "$TABLE_EXISTS" -gt 0 ]]; then
log_ok " tenant_visitor_floor_policy already exists — DDL skipped"
else
log_info "Applying V2.0.7 DDL..."
$MYSQL_CMD "$DB_ELEVATOR" < "$REPO_ROOT/docs/sql/tenant_visitor_floor_policy.sql"
log_ok " V2 DDL applied"
fi
log_info "Database preparation complete"
+82
View File
@@ -0,0 +1,82 @@
#!/bin/bash
# prepare-services.sh — 解压 tar.gz + 从模板生成配置
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
log_info "Phase 4: Service preparation"
mkdir -p "$SERVICE_DIR" "$LOG_DIR"
# Tarballs to extract
TARBALLS=(
"$STAR_CENTER/ninca_common_01-ninca_common_backend.tar.gz:ninca-common"
"$STAR_CENTER/ninca_common_component_organization_01-ninca_common_component_organization.tar.gz:component-org"
"$STAR_CENTER/ninca_common_snap_app_01-ninca_common_snap_app.tar.gz:snap-app"
"$STAR_CENTER/ninca_common_vehicle_app_01-ninca_common_vehicle_app.tar.gz:vehicle-app"
"$STAR_CENTER/ninca_common_monitor_app_01-ninca_common_monitor_app.tar.gz:monitor-app"
"$STAR_CENTER/ninca-person-file-app-V2.9.2_20210216.tar.gz:person-file"
)
for item in "${TARBALLS[@]}"; do
tarball="${item%%:*}"
svc_name="${item##*:}"
svc_dir="$SERVICE_DIR/$svc_name"
if [[ -d "$svc_dir" ]]; then
log_info "Already extracted: $svc_name — skipping"
continue
fi
log_info "Extracting $tarball$svc_dir ..."
mkdir -p "$svc_dir"
tar -xzf "$tarball" -C "$svc_dir" --strip-components=1
log_ok " $svc_name extracted"
done
render_template() {
local template="$1"
local output="$2"
sed \
-e "s|__MYSQL_HOST__|$MYSQL_HOST|g" \
-e "s|__MYSQL_PORT__|$MYSQL_PORT|g" \
-e "s|__REDIS_HOST__|$REDIS_HOST|g" \
-e "s|__REDIS_PASS__|$REDIS_PASS|g" \
-e "s|__CONSUL_HOST__|$CONSUL_HOST|g" \
-e "s|__CONSUL_PORT__|$CONSUL_PORT|g" \
-e "s|__KAFKA_HOST__|$KAFKA_HOST|g" \
-e "s|__KAFKA_PORT__|$KAFKA_PORT|g" \
-e "s|__CRK_HOST__|127.0.0.1|g" \
-e "s|__CRK_PORT__|$PORT_CRK_STD|g" \
-e "s|__CRK_MGMT_PORT__|$PORT_CRK_MGMT|g" \
-e "s|__ALARM_PORT__|$PORT_ALARM|g" \
-e "s|__ALARM_MGMT_PORT__|$PORT_ALARM_MGMT|g" \
-e "s|__NINCA_COMMON_PORT__|$PORT_NINCA_COMMON|g" \
-e "s|__COMPONENT_ORG_PORT__|$PORT_COMPONENT_ORG|g" \
"$template" > "$output"
}
# Generate configs for each service
render_template "$TEST_ENV_DIR/config/service-templates/elevator-v2.properties" \
"$REPO_ROOT/maven-cw-elevator-application/deploy/v2-maven/application-test.properties"
log_ok " elevator-v2 config generated"
render_template "$TEST_ENV_DIR/config/service-templates/crk-std.properties" \
"$STAR_CENTER/ninca_crk_std_01-ninca_crk_std_backend/application-test.properties"
log_ok " crk-std config generated"
render_template "$TEST_ENV_DIR/config/service-templates/alarm.properties" \
"$STAR_CENTER/ninca_qk_alarm_app_01-ninca_qk_alarm_app/application-test.properties"
log_ok " alarm config generated"
# Generate configs for extracted tarball services
if [[ -d "$SERVICE_DIR/ninca-common" ]]; then
render_template "$TEST_ENV_DIR/config/service-templates/ninca-common.properties" \
"$SERVICE_DIR/ninca-common/application-test.properties"
log_ok " ninca-common config generated"
fi
if [[ -d "$SERVICE_DIR/component-org" ]]; then
render_template "$TEST_ENV_DIR/config/service-templates/component-org.properties" \
"$SERVICE_DIR/component-org/application-test.properties"
log_ok " component-org config generated"
fi
log_info "Service preparation complete"
+145
View File
@@ -0,0 +1,145 @@
#!/bin/bash
# setup.sh — V2 测试环境一键搭建入口
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config/env.sh"
cat << 'BANNER'
╔══════════════════════════════════════════════╗
║ V2 Full-System Test Environment Setup ║
║ cw-elevator-application v2.0.7 ║
╚══════════════════════════════════════════════╝
BANNER
START_TIME=$(date +%s)
# ============================================
# Phase 1: 环境检查
# ============================================
log_info "Phase 1/6: Environment check"
# JDK 8
if [[ ! -x "$JAVA_HOME/bin/java" ]]; then
log_error "JDK 8 not found at $JAVA_HOME"
log_info "Set DEPLOY_JDK8 environment variable to correct path"
exit 1
fi
JAVA_VER=$("$JAVA_HOME/bin/java" -version 2>&1 | head -1)
log_ok "JDK: $JAVA_VER"
# Maven
if ! command -v mvn &>/dev/null; then
log_error "Maven not found"
exit 1
fi
log_ok "Maven: $(mvn --version 2>&1 | head -1)"
# Docker
if ! docker compose version &>/dev/null; then
log_error "Docker Compose not found"
exit 1
fi
log_ok "Docker: $(docker compose version)"
# MySQL
if ! mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SELECT 1" &>/dev/null; then
log_error "Cannot connect to MySQL at $MYSQL_HOST:$MYSQL_PORT"
exit 1
fi
log_ok "MySQL: $MYSQL_HOST:$MYSQL_PORT OK"
# 端口冲突
CONFLICT_PORTS=""
for port in 9517 6380 8090 18080 18081 16106 17011 3721; do
if ss -tlnp 2>/dev/null | grep -q ":$port "; then
CONFLICT_PORTS="$CONFLICT_PORTS $port"
fi
done
if [[ -n "$CONFLICT_PORTS" ]]; then
log_warn "Ports already in use:$CONFLICT_PORTS"
log_warn "These services may fail to start. Stop existing processes first."
fi
log_ok "Phase 1 complete"
# ============================================
# Phase 2: 数据库准备
# ============================================
log_info "Phase 2/6: Database preparation"
bash "$SCRIPT_DIR/prepare-db.sh"
log_ok "Phase 2 complete"
# ============================================
# Phase 3: Docker 基础组件启动
# ============================================
log_info "Phase 3/6: Docker infrastructure"
cd "$SCRIPT_DIR"
# Stop and remove any existing v2test containers and conflicting containers
log_info "Cleaning up existing containers..."
docker rm -f v2test-consul v2test-redis v2test-nginx cw-frontend-local-nginx v2-test-redis 2>/dev/null || true
docker compose -f docker-compose.infra.yml down --remove-orphans 2>/dev/null || true
docker compose -f docker-compose.infra.yml up -d
log_info "Waiting for Consul..."
for i in $(seq 1 30); do
if curl -sf "http://$CONSUL_HOST:$CONSUL_PORT/v1/status/leader" &>/dev/null; then
break
fi
sleep 2
done
log_ok "Consul ready"
log_info "Waiting for Kafka..."
sleep 15
log_ok "Kafka ready"
log_ok "Phase 3 complete"
# ============================================
# Phase 4: 服务准备
# ============================================
log_info "Phase 4/6: Service preparation"
bash "$SCRIPT_DIR/prepare-services.sh"
bash "$SCRIPT_DIR/build-elevator-v2.sh"
log_ok "Phase 4 complete"
# ============================================
# Phase 5: 服务启动
# ============================================
log_info "Phase 5/6: Service startup"
bash "$SCRIPT_DIR/start-all.sh"
log_ok "Phase 5 complete"
# ============================================
# Phase 6: 验证
# ============================================
log_info "Phase 6/6: Verification"
bash "$SCRIPT_DIR/health-check.sh"
bash "$SCRIPT_DIR/verify-functional.sh"
log_ok "Phase 6 complete"
# ============================================
# 汇总
# ============================================
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
cat << SUMMARY
╔══════════════════════════════════════════════╗
║ Setup Complete! ║
║ ║
║ Duration: ${DURATION}s ║
║ Consul: http://$CONSUL_HOST:$CONSUL_PORT/ui/ ║
║ Nginx: http://$CONSUL_HOST:$PORT_NGINX/ ║
║ Elevator V2: http://127.0.0.1:$PORT_ELEVATOR_V2 ║
║ Elevator V1: http://127.0.0.1:$PORT_ELEVATOR_V1 ║
║ CRK std: http://127.0.0.1:$PORT_CRK_STD ║
║ Alarm: http://127.0.0.1:$PORT_ALARM ║
╚══════════════════════════════════════════════╝
To stop: bash scripts/test-env/stop-all.sh && docker compose -f scripts/test-env/docker-compose.infra.yml down
SUMMARY
+92
View File
@@ -0,0 +1,92 @@
#!/bin/bash
# start-all.sh — 按拓扑序启动所有 Java 服务
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
export JAVA_HOME
export PATH="$JAVA_HOME/bin:$PATH"
log_info "Phase 5: Starting all services..."
mkdir -p "$LOG_DIR"
# 启动函数: start_service <name> <jar_path> <port> <java_opts> <extra_args>
start_service() {
local name="$1"; local jar="$2"; local port="$3"
local opts="${4:-$JAVA_OPTS_LIGHT}"; shift 4
if pgrep -f "$(basename "$jar")" >/dev/null 2>&1; then
log_warn " $name already running ($(pgrep -f "$(basename "$jar")" | tr '\n' ' ')) — skipping"
return 0
fi
log_info "Starting $name (port $port)..."
if [[ ! -f "$jar" ]]; then
log_error " JAR not found: $jar"
return 1
fi
nohup $JAVA -jar $opts "$jar" "$@" \
--spring.config.location="$(dirname "$jar")/" \
> "$LOG_DIR/${name}.log" 2>&1 &
local pid=$!
echo $pid > "$LOG_DIR/${name}.pid"
# 等待服务就绪 (最多 60s)
for i in $(seq 1 30); do
sleep 2
if curl -sf "http://127.0.0.1:$port/health" &>/dev/null; then
log_ok " $name (pid=$pid, port=$port) STARTED"
return 0
fi
done
log_warn " $name health check timeout after 60s (pid=$pid)"
return 1
}
# ============================================
# 启动顺序 (拓扑序)
# ============================================
# A1: ninca-common
COMMON_JAR=$(find "$SERVICE_DIR/ninca-common" -name "*.jar" -not -name "*-sources*" 2>/dev/null | head -1)
if [[ -n "$COMMON_JAR" ]]; then
start_service "ninca-common" "$COMMON_JAR" "$PORT_NINCA_COMMON" "$JAVA_OPTS_LIGHT"
fi
# A2: component-organization
ORG_JAR=$(find "$SERVICE_DIR/component-org" -name "*.jar" -not -name "*-sources*" 2>/dev/null | head -1)
if [[ -n "$ORG_JAR" ]]; then
start_service "component-org" "$ORG_JAR" "$PORT_COMPONENT_ORG" "$JAVA_OPTS_LIGHT"
fi
# A10: CRK-std
CRK_DIR="$STAR_CENTER/ninca-crk-std/ninca-crk-std-backend-V2.9.2_20210730"
CRK_JAR="$STAR_CENTER/ninca-crk-std/ninca-crk-std-backend-V2.9.2_20210730.jar"
if [[ -f "$CRK_JAR" ]]; then
start_service "crk-std" "$CRK_JAR" "$PORT_CRK_STD" "$JAVA_OPTS_HEAVY" --spring.config.location="$CRK_DIR/"
fi
# A11: alarm-app
ALARM_JAR="$STAR_CENTER/ninca-qk-alarm/ninca-qk-alarm-app-V2.9.2_20210730.jar"
if [[ -f "$ALARM_JAR" ]]; then
start_service "alarm-app" "$ALARM_JAR" "$PORT_ALARM" "$JAVA_OPTS_HEAVY" --spring.config.location="$STAR_CENTER/ninca-qk-alarm/"
fi
# A12: elevator V2 (最后启动) — use wildcard to match any version
ELEVATOR_V2_JAR=$(ls -t "$REPO_ROOT/backend/cw-elevator-application/deploy/v2-maven/cw-elevator-application-"*.jar 2>/dev/null | head -1)
if [[ -n "$ELEVATOR_V2_JAR" ]]; then
start_service "elevator-v2" "$ELEVATOR_V2_JAR" "$PORT_ELEVATOR_V2" "$JAVA_OPTS_HEAVY" --spring.config.location="$REPO_ROOT/backend/cw-elevator-application/deploy/v2-maven/"
else
log_warn "No elevator V2 JAR found in deploy/v2-maven/"
fi
# A13: elevator V1 (对拍对照)
ELEVATOR_V1_JAR=$(ls -t "$REPO_ROOT/backend/cw-elevator-application/deploy/v1-legacy/cw-elevator-application-"*.jar 2>/dev/null | head -1)
if [[ -n "$ELEVATOR_V1_JAR" ]]; then
start_service "elevator-v1" "$ELEVATOR_V1_JAR" "$PORT_ELEVATOR_V1" "$JAVA_OPTS_HEAVY" --spring.config.location="$REPO_ROOT/backend/cw-elevator-application/deploy/v1-legacy/"
else
log_warn "No elevator V1 JAR found in deploy/v1-legacy/"
fi
log_info "All services started"
+56
View File
@@ -0,0 +1,56 @@
#!/bin/bash
# stop-all.sh — 停止所有 V2 测试环境服务 (PID 文件 + 进程名匹配)
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
log_info "Stopping all services..."
# 1. Stop by PID files
for pid_file in "$LOG_DIR"/*.pid; do
if [[ -f "$pid_file" ]]; then
pid=$(cat "$pid_file")
svc=$(basename "$pid_file" .pid)
if kill -0 "$pid" 2>/dev/null; then
log_info "Stopping $svc (pid=$pid)..."
kill "$pid" 2>/dev/null || true
sleep 2
kill -9 "$pid" 2>/dev/null || true
log_ok " $svc stopped"
else
log_info " $svc already dead (pid=$pid)"
fi
rm -f "$pid_file"
fi
done
# 2. Kill any remaining Java processes by name pattern
KILL_PATTERNS=(
"cw-elevator-application"
"ninca-crk-std-backend"
"ninca-qk-alarm-app"
"ninca-common"
"component-organization"
"cwos-portal"
"cwos-manager"
"cwos-system-api"
)
for pattern in "${KILL_PATTERNS[@]}"; do
pids=$(pgrep -f "$pattern" 2>/dev/null || true)
if [[ -n "$pids" ]]; then
for pid in $pids; do
log_info "Killing $pattern (pid=$pid)..."
kill "$pid" 2>/dev/null || true
sleep 1
kill -9 "$pid" 2>/dev/null || true
done
log_ok " $pattern cleaned up"
fi
done
# 3. Stop Docker containers
log_info "Stopping Docker containers..."
cd "$(dirname "${BASH_SOURCE[0]}")"
docker compose -f docker-compose.infra.yml down 2>/dev/null || true
log_ok " Docker containers stopped"
log_info "All services stopped"
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""Stub: PersonResult format — floorList is a top-level field in data"""
from http.server import HTTPServer, BaseHTTPRequestHandler
import json, sys
PERSON_DATA = {
"id": "1072908835884208128", "businessId": "2524639890ba4f2cba9ba1a4eeaa4015",
"personCode": "PC001", "name": "秦夏", "userName": "qinxia", "phone": "13666667067",
"organizationIds": ["488b8ad049bb43408a6fbcc50bcb89ac"],
"organizationNames": ["广发基金"],
"labelIds": [], "labelNames": [],
"floorList": ["605560541473144832", "605560541657694208", "605560542911791104"],
"defaultFloor": "605560541473144832",
"status": 0, "isDel": 0
}
class PersonStub(BaseHTTPRequestHandler):
def log_message(self, f, *a): print(f"[stub] {a}", file=sys.stderr)
def do_POST(self):
body_len = int(self.headers.get('Content-Length', 0))
body = json.loads(self.rfile.read(body_len)) if body_len > 0 else {}
if '/detail' in self.path:
resp = {"code": "00000000", "success": True, "message": "success", "data": PERSON_DATA}
else:
resp = {"code": "00000000", "success": True, "data": {"total": 0, "datas": []}}
self._json(resp)
def do_GET(self):
self._json({"status": "UP"})
def _json(self, data):
resp = json.dumps(data, ensure_ascii=False).encode()
self.send_response(200)
self.send_header('Content-Type', 'application/json;charset=utf-8')
self.send_header('Content-Length', str(len(resp)))
self.end_headers()
self.wfile.write(resp)
port = int(sys.argv[1]) if len(sys.argv) > 1 else 33011
HTTPServer(('127.0.0.1', port), PersonStub).serve_forever()
+65
View File
@@ -0,0 +1,65 @@
#!/bin/bash
# verify-functional.sh — V2 全系统功能验证
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
log_info "=== V2 Functional Verification ==="
FAILED=0
verify() {
local desc="$1"; shift
if "$@"; then
log_ok " $desc"
else
log_error " $desc FAILED"
((FAILED++))
fi
}
# F1: 电梯 V2 探活
log_info "[F1] Elevator V2 health"
verify "elevator-v2 /actuator/health" \
curl -sf "http://127.0.0.1:$PORT_ELEVATOR_V2/actuator/health"
# F2: V1 vs V2 API 对拍
log_info "[F2] V1/V2 API parity test"
cd "$REPO_ROOT/maven-cw-elevator-application/tools/elevator_api_parity"
verify "pytest elevator_api_parity" \
pytest tests/test_smoke_catalog.py -q --tb=short
# F3: V2.0.7 租户策略 — UC-01 基线
log_info "[F3] Tenant visitor policy — UC-01 baseline"
RESP=$(curl -sf -X POST "http://127.0.0.1:$PORT_ELEVATOR_V2/elevator/person/add/visitor" \
-H "Content-Type: application/json" \
-d '{"personId":"test-person","visitorName":"test-visitor"}' 2>/dev/null || echo '{"code":-1}')
verify "UC-01 baseline (no policy)" echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d.get('code')!=76260532"
# F4: V2.0.7 — UC-02 显式传 floorIds
log_info "[F4] Tenant visitor policy — UC-02 explicit floorIds"
RESP2=$(curl -sf -X POST "http://127.0.0.1:$PORT_ELEVATOR_V2/elevator/person/add/visitor" \
-H "Content-Type: application/json" \
-d '{"personId":"test-person","visitorName":"test-visitor2","floorIds":["zone-001"]}' 2>/dev/null || echo '{"code":-1}')
verify "UC-02 (explicit floorIds)" echo "$RESP2" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('code'))"
# F7: CRK 联动
log_info "[F7] CRK integration"
verify "crk-std /actuator/health" \
curl -sf "http://127.0.0.1:$PORT_CRK_MGMT/actuator/health"
# F8: 报警 Kafka — Consul 注册检查
log_info "[F8] Alarm Consul registration"
verify "alarm registered in Consul" \
curl -sf "http://$CONSUL_HOST:$CONSUL_PORT/v1/agent/services" | python3 -c "import sys,json; services=json.load(sys.stdin); assert any('alarm' in k.lower() for k in services)"
# F9: Nginx 前端代理
log_info "[F9] Frontend Nginx"
verify "nginx serves cwos-portal" \
curl -sf -o /dev/null -w "%{http_code}" "http://$CONSUL_HOST:$PORT_NGINX/" | grep -q 200
# I1: MySQL 连通
log_info "[I1] MySQL connectivity"
verify "mysql SELECT 1" \
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SELECT 1" &>/dev/null
echo ""
log_info "=== Verification Complete: $FAILED failures ==="
[[ $FAILED -eq 0 ]] && exit 0 || exit 1