diff --git a/maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java b/maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java index 0d633b51..bd179829 100644 --- a/maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java +++ b/maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java @@ -208,16 +208,15 @@ public class PersonRuleServiceImpl extends AbstractAcsPassService implements Per this.logger.info("UC-01:调用方未指定楼层,取被访人默认楼层为 {}", candidate); } - // === 阶段3:ALWAYS 查询策略,有策略且生效则求交 === + // === 阶段3:ALWAYS 查询策略,有策略则以策略 allow 替代 === List orgIds = personResult.getOrganizationIds(); this.logger.info("被访人所属组织 orgIds={}", orgIds); TenantVisitorFloorPolicyDto policy = findPolicyByOrgIds(orgIds); List effective; if (policy != null) { - this.logger.info("找到启用策略 policyId={} orgId={} allow={}", policy.getId(), policy.getOrgId(), - policy.getAllowZoneIds()); - effective = resolveEffectiveFloors(candidate, candidate, policy, param.getPersonId()); - this.logger.info("策略求交后最终楼层 effective={}", effective); + List allow = parseAllowZoneIds(policy.getAllowZoneIds()); + this.logger.info("找到启用策略 policyId={} orgId={} allow={}", policy.getId(), policy.getOrgId(), allow); + effective = allow; } else { this.logger.info("未找到启用策略,使用候选楼层原值 {}", candidate); effective = candidate; diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/BUILD_MANIFEST.txt b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/BUILD_MANIFEST.txt new file mode 100644 index 00000000..ad8adf8b --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/BUILD_MANIFEST.txt @@ -0,0 +1,10 @@ +artifact=cw-elevator-application-V1.0.0.20211103.jar +bundle_dir_name=cw-elevator-application-V2.0.20.20260505 +directory=/media/zebra/9e8fa357-7db6-4d70-88ed-d5de5a059a663/星河湾星中星/源码/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505 +built_at=2026-05-05T19:49:01+08:00 +java_home=/usr/lib/jvm/java-8-openjdk-amd64 +java_version_line=openjdk version "1.8.0_482" +java_version_line=OpenJDK Runtime Environment (build 1.8.0_482-8u482-ga~us1-0ubuntu1~22.04-b08) +java_version_line=OpenJDK 64-Bit Server VM (build 25.482-b08, mixed mode) +git_rev=f7da04caea3b2f8be7a790582d62f7b047a6f30c +git_branch=release/cw-elevator-v1-lib-min-risk diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/SQL与代码一致性审核记录.md b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/SQL与代码一致性审核记录.md new file mode 100644 index 00000000..b1d1d204 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/SQL与代码一致性审核记录.md @@ -0,0 +1,75 @@ +# cw-elevator-application v2.0.6 SQL与代码一致性审核记录 + +**审核目标**:确认发布规范涉及 SQL 脚本与当前代码逻辑一致,满足实施交付依据留档要求。 +**审核范围**:`tenant_visitor_floor_policy` 建表脚本、初始化脚本、访客派梯策略读取与求交流程。 +**审核时间**:`2026-04-29` +**审核人**:`____________` + +--- + +## 1. 审核过程 + +1. 审阅 SQL 脚本: + - `docs/sql/tenant_visitor_floor_policy.sql` + - `docs/sql/tenant_visitor_floor_policy_init_guangfa_fund.sql` +2. 审阅代码路径: + - `cw-elevator-application-service/.../PersonRuleServiceImpl#addVisitor` + - `cw-elevator-application-data/.../TenantVisitorFloorPolicyMapper.xml` + - `cw-elevator-application-data/.../TenantVisitorFloorPolicyDto` +3. 做场景对照: + - UC-01:调用方未传 `floorIds` + - UC-02:调用方已传 `floorIds` + - 策略缺失/无效 JSON/交集为空等异常分支 +4. 形成一致性结论与风险提示,并纳入发布包。 + +--- + +## 2. 审核依据与结果 + +| 检查项 | SQL 依据 | 代码依据 | 结论 | +|------|----------|----------|------| +| 策略表字段是否齐全(business_id/policy_type/allow_zone_ids/building_id/enabled/policy_version) | `tenant_visitor_floor_policy.sql` DDL 定义上述字段 | Mapper 查询并映射到 DTO 同名语义字段 | 一致 | +| 代码是否只读取“启用+租户默认+INTERSECT_ALLOWLIST”策略 | 初始化脚本使用 `policy_type='INTERSECT_ALLOWLIST'`、`building_id=NULL`、`enabled=1` | Mapper `WHERE enabled=1 AND policy_type='INTERSECT_ALLOWLIST' AND (building_id IS NULL OR building_id='')` | 一致 | +| allow_zone_ids 的数据格式是否匹配代码解析方式 | SQL 注释与初始化脚本均为 JSON 数组字符串(如 `["605560545117995008"]`) | `parseAllowZoneIds` 使用 `JSON.parseArray(..., String.class)` 解析 | 一致 | +| 未传 floorIds 时是否执行“被访人楼层 ∩ 策略楼层” | 策略表提供 allowlist 数据来源 | `addVisitor` 在 `!callerProvidedFloors` 分支求交 | 一致 | +| 交集为空是否按规范失败 | 初始化脚本可构造交集为空场景 | `intersected.isEmpty()` 返回 `76260532` | 一致 | +| 已传 floorIds 是否跳过策略表 | SQL 与此分支无冲突 | `callerProvidedFloors=true` 时不进入策略读取分支 | 一致 | + +--- + +## 3. 关键证据(摘录) + +- 代码读取策略(启用、类型、租户默认)来自 `TenantVisitorFloorPolicyMapper.xml`。 +- 代码在 `PersonRuleServiceImpl#addVisitor` 中: + - `!callerProvidedFloors` 才读取被访人楼层与租户策略; + - `allow_zone_ids` 解析成功且非空才参与求交; + - 求交为空返回 `76260532`; + - 调用方已传楼层时不走策略求交流程。 +- 初始化脚本 `tenant_visitor_floor_policy_init_guangfa_fund.sql` 的字段取值与上述查询条件完全兼容。 + +--- + +## 4. 审核结论 + +**结论:通过。** +发布规范涉及的 SQL 脚本内容与当前代码逻辑一致,满足 v2.0.6 发布包“数据库脚本 + 功能升级说明 + 实施交付依据”要求。 + +--- + +## 5. 风险提示与建议 + +1. **唯一性治理风险(中)** + DDL 使用 `UNIQUE KEY (business_id, building_id)`,在 MySQL 下 `building_id=NULL` 可能存在多行;当前代码通过 `ORDER BY updated_at DESC, policy_version DESC LIMIT 1` 取最新一条,不阻断功能,但建议运维侧增加“每租户默认策略唯一”巡检。 +2. **配置数据质量风险(中)** + `allow_zone_ids` 必须是电梯域 `zone_id` 字符串数组,若误填其它系统 UUID 会导致策略不生效或交集为空。 + +--- + +## 6. 签字确认 + +| 角色 | 姓名 | 日期 | 备注 | +|------|------|------|------| +| 审核人 | `____________` | `____` | `____` | +| 实施负责人 | `____________` | `____` | `____` | +| 甲方确认(可选) | `____________` | `____` | `____` | + diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/application-access-control.properties b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/application-access-control.properties new file mode 100644 index 00000000..2110b2d9 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/application-access-control.properties @@ -0,0 +1,45 @@ +# \u56FE\u7247\u524D\u7F00 +cloudwalk.elevator.common.relativePrefix=/cwos-portal/portal/fileManager/imgByPath?path= +# \u6570\u636E\u5E93sharding\u914D\u7F6E +spring.shardingsphere.sharding.tables.IT_ACS_RECOG_RECORD.actual-data-nodes=ds0.IT_ACS_RECOG_RECORD_$->{2020..2030} +spring.shardingsphere.sharding.tables.IT_ACS_RECOG_RECORD.table-strategy.standard.sharding-column=RECOGNITION_TIME +spring.shardingsphere.sharding.tables.IT_ACS_RECOG_RECORD.table-strategy.standard.precise-algorithm-class-name=cn.cloudwalk.elevator.YearlyShardingAlgorithm +spring.shardingsphere.sharding.tables.IT_ACS_RECOG_RECORD.table-strategy.standard.range-algorithm-class-name=cn.cloudwalk.elevator.YearlyShardingAlgorithm +# \u7535\u68AF\u5F00\u95E8\u4E8B\u4EF6\u8868 +spring.shardingsphere.sharding.tables.IT_ACS_ELEVATOR_RECORD.actual-data-nodes=ds0.IT_ACS_ELEVATOR_RECORD_$->{2020..2030} +spring.shardingsphere.sharding.tables.IT_ACS_ELEVATOR_RECORD.table-strategy.standard.sharding-column=RECOGNITION_TIME +spring.shardingsphere.sharding.tables.IT_ACS_ELEVATOR_RECORD.table-strategy.standard.precise-algorithm-class-name=cn.cloudwalk.elevator.YearlyShardingAlgorithm +spring.shardingsphere.sharding.tables.IT_ACS_ELEVATOR_RECORD.table-strategy.standard.range-algorithm-class-name=cn.cloudwalk.elevator.YearlyShardingAlgorithm +spring.shardingsphere.sharding.binding-tables=IT_ACS_ELEVATOR_RECORD,IT_ACS_RECOG_RECORD +# \u4EBA\u8138\u6293\u62CD\u8BC6\u522B\u9608\u503C +cloudwalk.access-control.common.device-atrr-map.ACS_FACE_REG_THRESHOLD=75 +# \u4EBA\u8138\u6BD4\u5BF9\u67E5\u8BE2\u8FC7\u6EE4\u9608\u503C +cloudwalk.access-control.common.face-compare-THRESHOLD=80 +# \u5B9A\u65F6\u4EFB\u52A1\u914D\u7F6E +cloudwalk.access-control.schedual.jobs.AcsRecordStatisticsByDayJob.name=AcsRecordStatisticsByDayJob +cloudwalk.access-control.schedual.jobs.AcsRecordStatisticsByDayJob.group=ACCESS-CONTROL_GROUP +cloudwalk.access-control.schedual.jobs.AcsRecordStatisticsByDayJob.executable-class=cn.cloudwalk.service.ninca.accesscontrol.common.job.executable.AcsRecordStatisticsByDayJob +cloudwalk.access-control.schedual.jobs.AcsRecordStatisticsByDayJob.description=AcsRecordStatisticsByDay job is starting......... +## \u6BCF\u5929\u51CC\u66680\u70B910\u5206\u6267\u884C +cloudwalk.access-control.schedual.jobs.AcsRecordStatisticsByDayJob.cron-expression=0 10 0 * * ? +cloudwalk.access-control.schedual.jobs.AcsRecordStatisticsByDayJob.priority=1 +# \u5F00\u95E8\u8BB0\u5F55\u63A8\u9001\u5F00\u5173\uFF1Atrue-\u5F00\uFF1Bfalse-\u5173\u3002\u9ED8\u8BA4\u4E3A\u5173 +cloudwalk.access-control.common.publish-opendoor-switch=false +# \u5F00\u95E8\u8BB0\u5F55\u63A8\u9001serviceCode +cloudwalk.access-control.common.publish-opendoor-service-code=access-control +# \u540E\u7AEF\u8BC6\u522B\u4E0B\u53D1\u5F00\u95E8\u6307\u4EE4\u76F8\u5173\u914D\u7F6E +# \u6293\u62CD\u65F6\u95F4\u5728\u591A\u4E45\u4E4B\u524D\u4E0D\u4E0B\u53D1\u5F00\u95E8\u6307\u4EE4\u3002\u9ED8\u8BA45\u5206\u949F\u3002\u5355\u4F4D\uFF1A\u6BEB\u79D2\u3002 +cloudwalk.access-control.common.face-capture-time-expired-milliseconds=300000 +# \u591A\u5C11\u6BEB\u79D2\u4EE5\u5185\u7684\u591A\u6761\u6293\u62CD\u8BB0\u5F55\u53EA\u4E0B\u53D1\u4E00\u6B21\u5F00\u95E8\u6307\u4EE4\u3002\u9ED8\u8BA43\u79D2\u3002\u5355\u4F4D\uFF1A\u6BEB\u79D2 +cloudwalk.access-control.common.face-capture-interval-milliseconds=3000 +# \u5F00\u95E8\u8BB0\u5F55\u8FC7\u671F\u65F6\u95F4\u3002\u591A\u5C11\u6BEB\u79D2\u4E4B\u540E\uFF0C\u672A\u4E0A\u62A5\u5F00\u95E8\u8BB0\u5F55\uFF0C\u5F00\u95E8\u8BB0\u5F55\u72B6\u6001\u66F4\u65B0\u4E3A\u5931\u8D25\u3002\u9ED8\u8BA410\u5206\u949F\u3002\u5355\u4F4D\uFF1A\u6BEB\u79D2 +cloudwalk.access-control.common.face-capture-open-door-fail-milliseconds=600000 +# \u95E8\u7981\u63A7\u5236\u5668\u7C7B\u578B\u96C6\u5408 +cloudwalk.access-control.common.device-controller-array[0]=mqtt +# \u8BBE\u5907\u79CD\u7C7Bid\u96C6\u5408 +cloudwalk.access-control.common.device-category-array[0]=4 +cloudwalk.access-control.common.device-category-array[1]=5 +cloudwalk.access-control.common.device-category-array[2]=7 +cloudwalk.access-control.common.device-category-array[3]=2 +cloudwalk.access-control.common.device-category-array[4]=8 +cloudwalk.access-control.common.device-category-array[5]=11 diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/application.properties b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/application.properties new file mode 100644 index 00000000..9708773e --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/application.properties @@ -0,0 +1,119 @@ +# deploy/v2-maven \uFF1Amaven \u6784\u5EFA cw-elevator-application-2.0.0.jar\uFF08\u540C\u76EE\u5F55\u542F\u52A8\uFF09 +# \u751F\u4EA7\u6A21\u62DF\uFF1Aaccess-control \u4E1A\u52A1/\u5206\u8868/\u95E8\u7981\u9608\u503C\u7B49\u89C1\u540C\u76EE\u5F55 application-access-control.properties +# \uFF08\u4E0E \u661F\u4E2D\u5FC3/cw-elevator-application-V1.0.0.20211103 \u5BF9\u9F50\uFF09\u3002\u672C\u6587\u4EF6\u4FDD\u7559\u7AEF\u53E3\u3001JDBC/Redis/Ribbon/Kafka \u7B49\u9A8C\u8BC1\u73AF\u5883\u8986\u76D6\u3002 +server.port=18081 +server.tomcat.uri-encoding=UTF-8 +spring.application.name=elevator-app +# Boot 1.5 \u65E0 spring.main.allow-bean-definition-overriding\uFF1B\u82E5\u91CD\u590D Bean \u9700\u5728\u4EE3\u7801\u4FA7\u6D88\u6B67\u4E49\u6216\u5347\u7EA7 Spring Boot + + +# spring\u914D\u7F6E +spring.mvc.throw-exception-if-no-handler-found=true +spring.mvc.locale=zh_CN +# \u8D44\u6E90\u6587\u4EF6\u914D\u7F6E +spring.messages.basename=access-control +spring.messages.always-use-message-format=true +spring.messages.encoding=utf-8 +# http\u914D\u7F6E +spring.http.multipart.max-file-size=200MB +spring.http.multipart.max-request-size=200MB +spring.http.encoding.force=true +spring.http.encoding.charset=UTF-8 +spring.http.encoding.enabled=true +# \u65E5\u5FD7\u914D\u7F6E +logging.config=classpath:logs/logback.xml +logging.file=${spring.application.name} +logging.path=logs +logging.level.root=info +logging.level.cn.cloudwalk=info +# mybatis\u914D\u7F6E +mybatis.mapper-locations=classpath*:cn/cloudwalk/elevator/**/*.xml +mybatis.config-location=classpath:mapper/mybatis-config.xml +# \u5E8F\u5217\u53F7\u914D\u7F6E +cloudwalk.serial.enabled=true +cloudwalk.serial.serial-length=8 +cloudwalk.serial.serial-type=redis +cloudwalk.serial.serial-redis-key=CLOUDWALK-ACS-SERIAL-KEY +# \u7F13\u5B58\u914D\u7F6E +cloudwalk.spring.cache.expires=CACHE_NAME_APPLICATIONIDS#21600,ACS_DeviceTypesCache#7200,ACS_DeviceTypeFeaturesCache#7200,ACS_DeviceAttrsCache#7200,ACS_RecordStatisticsCache#90000,ACS_AreaTreeCache#60 +# \u5185\u90E8\u63A5\u53E3\u8C03\u7528\u5BA2\u6237\u7AEF\u53CA\u8D85\u65F6\u914D\u7F6E +feign.hystrix.enable=true +feign.httpclient.enable=false +feign.okhttp.enable=true +ribbon.http.client.enabled=false +ribbon.okhttp.enabled=true +ribbon.ReadTimeout=10000 +ribbon.ConnectTimeout=10000 +hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000 +# \u5065\u5EB7\u68C0\u67E5\u914D\u7F6E +management.health.redis.enabled=false +management.health.db.enabled=false +# \u6570\u636E\u8131\u654F\u914D\u7F6E +cloudwalk.datafield.enable=true +cloudwalk.datafield.securityKey=d4b2aabc97394a12a27fc3cca6cd9ba1 +cloudwalk.datafield.encrypt=AES +# redis\u914D\u7F6E\uFF08\u672C\u673A Docker\uFF1Aybs-redis 6379->6379\uFF0C\u82E5\u7528 craftlabs-redis \u6539\u4E3A 6380\uFF09 +spring.redis.host=127.0.0.1 +spring.redis.port=6379 +# \u672C\u673A Redis \u65E0\u5BC6\u7801\u65F6\u5FC5\u987B\u4FDD\u7559\u4E0B\u884C\u7A7A\u503C\uFF0C\u4EE5\u8986\u76D6 fat-jar \u5185\u5D4C\u65E7\u5BC6\u7801\uFF08\u5426\u5219 Redisson ERR AUTH\uFF09 +spring.redis.password= +spring.redis.database=5 +spring.redis.timeout=0 +spring.redis.pool.max-active=10 +spring.redis.pool.max-idle=1 +spring.redis.pool.max-wait=10 +spring.redis.pool.min-idle=0 +# \u6570\u636E\u5E93sharding\u914D\u7F6E +spring.shardingsphere.datasource.names=ds0 +spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource +spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver +spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://192.168.3.12:3307/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 +spring.shardingsphere.datasource.ds0.connection-timeout=60000 +spring.shardingsphere.datasource.ds0.maximum-pool-size=20 +spring.shardingsphere.datasource.ds0.minimum-idle=5 +spring.shardingsphere.datasource.ds0.max-lifetime=1765000 +spring.shardingsphere.datasource.ds0.auto-commit=true +spring.shardingsphere.datasource.ds0.pool-name=ds0-pool +spring.shardingsphere.props.sql.show=false +spring.shardingsphere.sharding.default-data-source-name=ds0 +# \u5FAE\u670D\u52A1\u670D\u52A1\u540D\u914D\u7F6E +feign.device.name=cwos-portal +feign.resource.name=cwos-portal +feign.cwos-portal.name=cwos-portal +feign.ninca-crk-std.name=ninca-crk-std +feign.davinci-portal.name=cwos-portal +feign.component-organization.name=ninca-common-component-organization +feign.ninca-common.name=ninca-common +feign.mqtt.name=cloudwalk-device-thirdparty +# CWOS\u4E8B\u4EF6\u914D\u7F6E +cloudwalk.event.bootstrap-servers=192.168.3.12:9092 +cloudwalk.event.group-id=cw-elevator-application-1 +cloudwalk.event.handler-executor-config.core-pool-size=10 +cloudwalk.event.handler-executor-config.maximum-pool-size=30 +# \u5206\u5E03\u5F0F\u9501\u914D\u7F6E +intelligent.lock.enable=true +intelligent.lock.config.default-wait-time=10000 +lockWatchdogTimeout=21000 +# PERSON_NAME_SPACE +person.name.space=recordEvent +elevator.application.key=xinghewan +elevator.application.time=600 +elevator.application.keyA=5B7DEF88FF04 +ninca-crk-std.ip=10.128.161.95:16106 +#\u53D1\u9001\u7B2C\u4E09\u65B9\u6570\u636Eip +sendRecord.ip=hrec.star-river.com:32165 +sendRecord.token.corpId=53db867a8bb747a1bd04dd1afcad8ca6 +sendRecord.token.appKey=293e2d708f0143c2957b702cef44d951 +sendRecord.token.appSecret=5f6995009b864669b52041b8f5dc4625 +sendRecord.boolean=true + +# \u8BBE\u5907\u5904\u7406\u7EBF\u7A0B\u6C60\u914D\u7F6E +ninca.update.floor.pool.corePoolSize=5 +ninca.update.floor.pool.maxPoolSize=5 +ninca.update.floor.pool.queueCapacity=100000 +ninca.update.floor.pool.keepAliveSeconds=150 +ninca.update.floor.pool.allowCoreThreadTimeOut=true +#\u697C\u680Bid +floor.building.id=605560539791228928 diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/bootstrap.properties b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/bootstrap.properties new file mode 100644 index 00000000..f333b0db --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/bootstrap.properties @@ -0,0 +1,18 @@ +server.port=16112 +server.tomcat.uri-encoding=UTF-8 +spring.application.name=elevator-app +spring.profiles.active=access-control +# consul\u914D\u7F6E +spring.cloud.consul.host=371bfca4972c43d2aefcf302d0a4a277 +spring.cloud.consul.port=8500 +spring.cloud.consul.enabled=true +spring.cloud.consul.discovery.register=true +spring.cloud.consul.discovery.enabled=false +spring.cloud.consul.discovery.prefer-ip-address=true +spring.cloud.consul.discovery.instance-id=${spring.application.name}-${spring.cloud.client.ipAddress}:${server.port} +spring.cloud.consul.discovery.ip-address=${spring.cloud.client.ipAddress} +spring.cloud.consul.discovery.deregister=false +# zookeeper\u914D\u7F6E +dubbo.registry.address=zookeeper://10.0.22.207:2181 +dubbo.protocol.port=16107 +dubbo.provider.version=1.0 diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/collect_elevator_runtime_evidence.sh b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/collect_elevator_runtime_evidence.sh new file mode 100755 index 00000000..513d4559 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/collect_elevator_runtime_evidence.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -euo pipefail + +# 生产只读证据采集(Maven 发布包内与本脚本同置于部署根目录,与 start.sh / properties 同层): +# - 进程参数/环境/工作目录 +# - 本地配置文件 +# - jcmd system properties +# - 应用日志关键片段 +# - Consul 健康与 KV 快照 +# 最终输出 tar.gz,便于离线定位“配置来源 -> Ribbon 实例列表”问题。 + +APP_DIR="${1:-/data/cwos/cw-elevator-application-V1.0.0.20211103}" +CONSUL_ADDR="${2:-10.0.22.102:8500}" +OUT_ROOT="${3:-${APP_DIR}/evidence}" +APP_NAME="${4:-elevator-app}" + +# 现场 JDK(生产 cwos-node 固定路径;不依赖 PATH) +CWOS_JAVA_BIN="/data/cwos/java/bin" +JAVA_BIN="${CWOS_JAVA_BIN}/java" +JAR_BIN="${CWOS_JAVA_BIN}/jar" +JCMD_BIN="${CWOS_JAVA_BIN}/jcmd" +DATE_BIN="/bin/date" + +timestamp="$(${DATE_BIN} +%Y%m%d-%H%M%S)" +OUT_DIR="${OUT_ROOT}/elevator-evidence-${timestamp}" +mkdir -p "${OUT_DIR}" + +log() { echo "[collect] $*"; } + +log "APP_DIR=${APP_DIR}" +log "CONSUL_ADDR=${CONSUL_ADDR}" +log "OUT_DIR=${OUT_DIR}" +log "JAVA_BIN=${JAVA_BIN} JAR_BIN=${JAR_BIN} JCMD_BIN=${JCMD_BIN}" + +PID="$(ps -ef | awk '/java/ && /cw-elevator-application/ && !/awk/ {print $2; exit}')" +if [[ -z "${PID}" ]]; then + echo "ERROR: 未找到 cw-elevator-application Java 进程" >&2 + exit 1 +fi +log "PID=${PID}" +echo "${PID}" > "${OUT_DIR}/pid.txt" + +# 1) 进程与系统基础信息 +ps -ef > "${OUT_DIR}/ps-ef.txt" +uname -a > "${OUT_DIR}/uname.txt" +${DATE_BIN} +%Y-%m-%dT%H:%M:%S%z > "${OUT_DIR}/collected-at.txt" + +tr '\0' ' ' < "/proc/${PID}/cmdline" > "${OUT_DIR}/proc-cmdline.txt" || true +tr '\0' '\n' < "/proc/${PID}/environ" > "${OUT_DIR}/proc-environ.txt" || true +ls -l "/proc/${PID}/cwd" > "${OUT_DIR}/proc-cwd.txt" || true + +# 2) 本地配置快照(若存在) +for f in bootstrap.properties application.properties application-access-control.properties start.sh stop.sh cw-elevator-application.service; do + if [[ -f "${APP_DIR}/${f}" ]]; then + cp -a "${APP_DIR}/${f}" "${OUT_DIR}/${f}" + fi +done + +# 3) JAR 与结构快照 +JAR_PATH="$(awk '{print $1}' "${OUT_DIR}/proc-cmdline.txt" | sed 's/[[:space:]]*$//')" +if [[ -f "${APP_DIR}/cw-elevator-application-V1.0.0.20211103.jar" ]]; then + JAR_PATH="${APP_DIR}/cw-elevator-application-V1.0.0.20211103.jar" +fi +echo "${JAR_PATH}" > "${OUT_DIR}/jar-path.txt" +if [[ -f "${JAR_PATH}" ]]; then + sha256sum "${JAR_PATH}" > "${OUT_DIR}/jar.sha256.txt" || true + if [[ -x "${JAR_BIN}" ]]; then + "${JAR_BIN}" tf "${JAR_PATH}" > "${OUT_DIR}/jar-tf.txt" || true + else + echo "jar not found or not executable: ${JAR_BIN}" > "${OUT_DIR}/jar-tf.txt" + fi + unzip -p "${JAR_PATH}" application.properties > "${OUT_DIR}/jar-application.properties.txt" 2>/dev/null || true + unzip -p "${JAR_PATH}" bootstrap.properties > "${OUT_DIR}/jar-bootstrap.properties.txt" 2>/dev/null || true +fi + +# 4) jcmd system properties + attach 诊断(不修改应用配置;便于修复 AttachNotSupportedException) +{ + echo "=== current shell user ===" + id 2>/dev/null || true + echo "=== target java process ===" + ps -o user=,group=,pid=,args= -p "${PID}" 2>/dev/null || true + PROC_USER="$(stat -c '%U' "/proc/${PID}" 2>/dev/null || echo "")" + PROC_UID="$(stat -c '%u' "/proc/${PID}" 2>/dev/null || echo "")" + echo "proc_owner=${PROC_USER} uid=${PROC_UID}" + echo "=== /tmp hsperfdata (HotSpot perf counter; attach 相关) ===" + if [[ -n "${PROC_USER}" && "${PROC_USER}" != "unknown" ]]; then + HS="/tmp/hsperfdata_${PROC_USER}" + if [[ -d "${HS}" ]]; then + ls -la "${HS}" 2>/dev/null | head -30 || true + ls -la "${HS}/${PID}" 2>/dev/null || echo "missing ${HS}/${PID}" + else + echo "no directory ${HS}" + fi + fi + echo "=== cmdline tokens (attach / jdwp) ===" + tr '\0' '\n' < "/proc/${PID}/cmdline" 2>/dev/null | grep -E 'DisableAttach|Attach|jdwp|agentpath' || echo "(none matched)" +} > "${OUT_DIR}/jcmd-attach-diagnose.txt" 2>&1 + +if [[ -x "${JCMD_BIN}" ]]; then + "${JCMD_BIN}" "${PID}" VM.system_properties > "${OUT_DIR}/jcmd-system-properties.txt" 2>&1 || true + if grep -q 'AttachNotSupportedException\|Unable to open socket file' "${OUT_DIR}/jcmd-system-properties.txt" 2>/dev/null; then + { + echo "" + echo "HINT: jcmd attach 失败常见原因:" + echo " 1) 与 Java 进程不同用户执行 jcmd(请用与进程相同用户,例如: sudo -u ${JCMD_BIN} ${PID} VM.system_properties)" + echo " 2) /tmp/hsperfdata_/ 缺失或权限异常" + echo " 3) JVM 启动参数含 -XX:+DisableAttachMechanism(见 jcmd-attach-diagnose.txt 中 cmdline)" + echo " 4) 进程非 HotSpot 或尚未完全初始化(极少见于长期运行的 Spring Boot)" + } >> "${OUT_DIR}/jcmd-system-properties.txt" + fi +else + echo "jcmd not found or not executable: ${JCMD_BIN}" > "${OUT_DIR}/jcmd-system-properties.txt" +fi + +# 4b) java 版本(与现场 JDK 一致性的旁证) +if [[ -x "${JAVA_BIN}" ]]; then + "${JAVA_BIN}" -version > "${OUT_DIR}/java-version.txt" 2>&1 || true +else + echo "java not found or not executable: ${JAVA_BIN}" > "${OUT_DIR}/java-version.txt" +fi + +# 5) 应用日志关键行 +LOG_FILE="${APP_DIR}/logs/elevator-app.log" +if [[ -f "${LOG_FILE}" ]]; then + cp -a "${LOG_FILE}" "${OUT_DIR}/elevator-app.log.full" + awk ' + /CONFIG SOURCE PROBE START|CONFIG SOURCE PROBE END|probe key=|ConfigurationBasedServerList|Load balancer does not have available server|DynamicServerListLoadBalancer|ConsulServiceRegistry|Registering service with consul/ { print } + ' "${LOG_FILE}" > "${OUT_DIR}/elevator-app.log.keylines.txt" +fi + +# 6) Consul 快照 +CURL="curl -sS --max-time 8" +${CURL} "http://${CONSUL_ADDR}/v1/health/service/${APP_NAME}?passing=true" > "${OUT_DIR}/consul-health-${APP_NAME}.json" || true +for svc in cwos-portal ninca-common ninca-common-component-organization ninca-crk-std cloudwalk-device-thirdparty; do + ${CURL} "http://${CONSUL_ADDR}/v1/health/service/${svc}?passing=true" > "${OUT_DIR}/consul-health-${svc}.json" || true +done +${CURL} "http://${CONSUL_ADDR}/v1/kv/config/${APP_NAME}/data?raw" > "${OUT_DIR}/consul-kv-${APP_NAME}.properties" || true +${CURL} "http://${CONSUL_ADDR}/v1/kv/config/${APP_NAME},access-control/data?raw" > "${OUT_DIR}/consul-kv-${APP_NAME},access-control.properties" || true + +# 7) 现场可达性快照(已知主机名) +for host in 0837a70b5fab47569391828f5feb2561 371bfca4972c43d2aefcf302d0a4a277 44700995ee904679a7ad5afddcf93bb5; do + getent hosts "${host}" > "${OUT_DIR}/getent-${host}.txt" 2>&1 || true + curl -I --max-time 5 "http://${host}:8089/" > "${OUT_DIR}/curl-head-${host}-8089.txt" 2>&1 || true +done + +ARCHIVE="${OUT_DIR}.tar.gz" +tar -czf "${ARCHIVE}" -C "$(dirname "${OUT_DIR}")" "$(basename "${OUT_DIR}")" +log "DONE archive=${ARCHIVE}" +echo "${ARCHIVE}" diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/common-java.sh b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/common-java.sh new file mode 100644 index 00000000..454673fb --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/common-java.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# 由 v1-legacy/run.sh、v2-maven/run.sh source:JAVA_HOME;非 JDK8 时追加 --add-opens。 +# +# === 本机 JDK 8 安装根目录(含 bin/java);换机器只需改下行默认路径或通过环境变量覆盖 === +: "${DEPLOY_JDK8:=/usr/lib/jvm/java-8-openjdk-amd64}" + +_pick_java_home() { + if [[ "${ELEVATOR_USE_ENV_JAVA:-0}" == "1" ]] && [[ -n "${JAVA_HOME:-}" && -x "${JAVA_HOME}/bin/java" ]]; then + return 0 + fi + if [[ -x "${DEPLOY_JDK8}/bin/java" ]]; then + export JAVA_HOME="${DEPLOY_JDK8}" + return 0 + fi + for d in /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/java-1.8.0-openjdk; do + if [[ -x "$d/bin/java" ]]; then + export JAVA_HOME="$d" + return 0 + fi + done + if [[ -n "${JAVA_HOME:-}" && -x "${JAVA_HOME}/bin/java" ]]; then + return 0 + fi + export JAVA_HOME="${JAVA_HOME:-${DEPLOY_JDK8}}" +} + +_jdk8_open_flags() { + local java="$1" + if "$java" -version 2>&1 | grep -qE 'version "1\.8\.'; then + echo "" + return + fi + echo "--add-opens=java.base/java.lang=ALL-UNNAMED" + echo "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED" + echo "--add-opens=java.base/java.util=ALL-UNNAMED" + echo "--add-opens=java.base/java.io=ALL-UNNAMED" +} diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/cw-elevator-application.service b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/cw-elevator-application.service new file mode 100644 index 00000000..68f543d4 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/cw-elevator-application.service @@ -0,0 +1,23 @@ +[Unit] +Description=cw-elevator-application 2.0.20 (Maven V2 fat jar) +After=network.target remote-fs.target nss-lookup.target + +[Service] +# 将 WorkingDirectory、ExecStart、ExecStop 中的路径占位改为实际部署绝对路径(与 JAR、start.sh、properties 同目录)。 +PIDFile=/run/cw-elevator-application-2.0.20.pid +ExecStartPre=/bin/rm -f /run/cw-elevator-application-2.0.20.pid +ExecStart=/bin/bash /path/to/cw-elevator-application/start.sh +ExecStop=/bin/bash /path/to/cw-elevator-application/stop.sh +ExecReload=/bin/kill -s HUP $MAINPID +KillSignal=SIGQUIT +TimeoutStopSec=5 +KillMode=process +PrivateTmp=true +Restart=always +RestartSec=10 +StandardOutput=null +StandardError=null +WorkingDirectory=/path/to/cw-elevator-application + +[Install] +WantedBy=multi-user.target diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy.sql b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy.sql new file mode 100644 index 00000000..32151c02 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy.sql @@ -0,0 +1,27 @@ +-- 租户访客默认楼层策略(电梯应用库) +-- 设计说明:docs/business/租户访客默认楼层-数据库配置阶段技术设计.md + +CREATE TABLE IF NOT EXISTS tenant_visitor_floor_policy ( + id VARCHAR(32) NOT NULL COMMENT '主键', + business_id VARCHAR(64) NOT NULL COMMENT '机构/租户 ID', + policy_type VARCHAR(32) NOT NULL DEFAULT 'INTERSECT_ALLOWLIST' COMMENT '策略类型', + allow_zone_ids TEXT NULL COMMENT 'JSON 数组,zoneId 列表', + building_id VARCHAR(64) NULL COMMENT '预留:楼栋维度;租户默认填 NULL', + enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1 启用 0 停用', + policy_version BIGINT NOT NULL DEFAULT 1 COMMENT '配置版本号', + remark VARCHAR(256) NULL, + created_by VARCHAR(64) NULL, + created_at BIGINT NULL, + updated_by VARCHAR(64) NULL, + updated_at BIGINT NULL, + PRIMARY KEY (id), + UNIQUE KEY uk_biz_building (business_id, building_id), + KEY idx_business_enabled (business_id, enabled) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户访客默认楼层策略(与组织 floorList 求交)'; + +-- 示例(实施时替换占位符后执行) +-- INSERT INTO tenant_visitor_floor_policy +-- (id, business_id, policy_type, allow_zone_ids, building_id, enabled, policy_version, remark, created_at, updated_at) +-- VALUES +-- (REPLACE(UUID(),'-',''), 'REPLACE_WITH_BUSINESS_ID', 'INTERSECT_ALLOWLIST', +-- '["REPLACE_ZONE_A","REPLACE_ZONE_B"]', NULL, 1, 1, '实施录入', UNIX_TIMESTAMP(NOW())*1000, UNIX_TIMESTAMP(NOW())*1000); diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy_init_guangfa_fund.sql b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy_init_guangfa_fund.sql new file mode 100644 index 00000000..67bc4cdb --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy_init_guangfa_fund.sql @@ -0,0 +1,47 @@ +-- 广发基金租户:访客默认楼层策略初始化(电梯库 cw-elevator-application) +-- +-- 字段说明:allow_zone_ids 为 JSON 数组,元素使用 code_elevator_area.zone_id(snowflake 格式), +-- 与 PersonResult.floorList 和 image_rule_ref.zone_id 同一套 ID。 +-- +-- 数据来源(现场查询 192.168.3.12:3307): +-- org_id:component-organization.cw_is_organization +-- NAME='[28-38F]广发基金管理有限公司' -> ID = 488b8ad049bb43408a6fbcc50bcb89ac +-- 28F zone_id:cw-elevator-application.code_elevator_area +-- zone_id = 605560545117995008(zone_name=28F,code=0x1C) +-- +-- 重复执行:使用固定 id + ON DUPLICATE KEY UPDATE,幂等。 + +SET NAMES utf8mb4; + +INSERT INTO tenant_visitor_floor_policy ( + id, + org_id, + business_id, + policy_type, + allow_zone_ids, + building_id, + enabled, + policy_version, + remark, + created_at, + updated_at +) VALUES ( + 'gf_vstr_policy_guangfa_fund_001x', + '488b8ad049bb43408a6fbcc50bcb89ac', + '2524639890ba4f2cba9ba1a4eeaa4015', + 'INTERSECT_ALLOWLIST', + '["605560545117995008"]', + NULL, + 1, + 1, + '广发基金:访客与 floorList 求交后仅保留 allowlist(默认仅 28F zone)。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + org_id = VALUES(org_id), + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy_init_property_mgmt_6f.sql b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy_init_property_mgmt_6f.sql new file mode 100644 index 00000000..0fc2613a --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/ddl/tenant_visitor_floor_policy_init_property_mgmt_6f.sql @@ -0,0 +1,186 @@ +-- 物业公司租户:访客默认楼层策略初始化(电梯库 cw-elevator-application) +-- 访客不传 floorIds 时,默认仅开放 6F,与被访人 floorList 求交。 +-- +-- 数据来源(192.168.3.12:3307): +-- org_id:component-organization.cw_is_organization +-- 星河湾物业管理有限公司 → 64fdc8eaf5824df5a1329819af29b79f +-- 星河湾物业管理公司 → 8fc3f910bd834198a539832017fe920e +-- 星河湾物管公司 → cc760fdf9c384a0cbf4951ccf2c6452e +-- 星中心物业管理公司 → f216235e54ca42bfa0379e69b3754aff +-- 星中心物业服务中心 → 95818575a2284db6833289474d33671f +-- 星中心物管公司 → 348328d755624b3491cd307a3109f36a +-- 物业管理总部 → dde6cc9a4f6b4f5490d03e26fb016200 +-- 6F zone_id:cw-elevator-application.code_elevator_area +-- zone_id = 605560541473144832(code=0x06) +-- +-- 重复执行:使用固定 id + ON DUPLICATE KEY UPDATE。 + +SET NAMES utf8mb4; + +-- ============================================================ +-- 1. 星河湾物业管理有限公司 +-- ============================================================ +INSERT INTO tenant_visitor_floor_policy ( + id, business_id, org_id, policy_type, allow_zone_ids, + building_id, enabled, policy_version, remark, created_at, updated_at +) VALUES ( + 'pm_6f_vstr_policy_001', + '2524639890ba4f2cba9ba1a4eeaa4015', + '64fdc8eaf5824df5a1329819af29b79f', + 'INTERSECT_ALLOWLIST', + '["605560541473144832"]', + NULL, 1, 1, + '星河湾物业管理有限公司:访客默认仅开放 6F。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); + +-- ============================================================ +-- 2. 星河湾物业管理公司 +-- ============================================================ +INSERT INTO tenant_visitor_floor_policy ( + id, business_id, org_id, policy_type, allow_zone_ids, + building_id, enabled, policy_version, remark, created_at, updated_at +) VALUES ( + 'pm_6f_vstr_policy_002', + '2524639890ba4f2cba9ba1a4eeaa4015', + '8fc3f910bd834198a539832017fe920e', + 'INTERSECT_ALLOWLIST', + '["605560541473144832"]', + NULL, 1, 1, + '星河湾物业管理公司:访客默认仅开放 6F。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); + +-- ============================================================ +-- 3. 星河湾物管公司 +-- ============================================================ +INSERT INTO tenant_visitor_floor_policy ( + id, business_id, org_id, policy_type, allow_zone_ids, + building_id, enabled, policy_version, remark, created_at, updated_at +) VALUES ( + 'pm_6f_vstr_policy_003', + '2524639890ba4f2cba9ba1a4eeaa4015', + 'cc760fdf9c384a0cbf4951ccf2c6452e', + 'INTERSECT_ALLOWLIST', + '["605560541473144832"]', + NULL, 1, 1, + '星河湾物管公司:访客默认仅开放 6F。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); + +-- ============================================================ +-- 4. 星中心物业管理公司 +-- ============================================================ +INSERT INTO tenant_visitor_floor_policy ( + id, business_id, org_id, policy_type, allow_zone_ids, + building_id, enabled, policy_version, remark, created_at, updated_at +) VALUES ( + 'pm_6f_vstr_policy_004', + '2524639890ba4f2cba9ba1a4eeaa4015', + 'f216235e54ca42bfa0379e69b3754aff', + 'INTERSECT_ALLOWLIST', + '["605560541473144832"]', + NULL, 1, 1, + '星中心物业管理公司:访客默认仅开放 6F。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); + +-- ============================================================ +-- 5. 星中心物业服务中心 +-- ============================================================ +INSERT INTO tenant_visitor_floor_policy ( + id, business_id, org_id, policy_type, allow_zone_ids, + building_id, enabled, policy_version, remark, created_at, updated_at +) VALUES ( + 'pm_6f_vstr_policy_005', + '2524639890ba4f2cba9ba1a4eeaa4015', + '95818575a2284db6833289474d33671f', + 'INTERSECT_ALLOWLIST', + '["605560541473144832"]', + NULL, 1, 1, + '星中心物业服务中心:访客默认仅开放 6F。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); + +-- ============================================================ +-- 6. 星中心物管公司 +-- ============================================================ +INSERT INTO tenant_visitor_floor_policy ( + id, business_id, org_id, policy_type, allow_zone_ids, + building_id, enabled, policy_version, remark, created_at, updated_at +) VALUES ( + 'pm_6f_vstr_policy_006', + '2524639890ba4f2cba9ba1a4eeaa4015', + '348328d755624b3491cd307a3109f36a', + 'INTERSECT_ALLOWLIST', + '["605560541473144832"]', + NULL, 1, 1, + '星中心物管公司:访客默认仅开放 6F。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); + +-- ============================================================ +-- 7. 物业管理总部 +-- ============================================================ +INSERT INTO tenant_visitor_floor_policy ( + id, business_id, org_id, policy_type, allow_zone_ids, + building_id, enabled, policy_version, remark, created_at, updated_at +) VALUES ( + 'pm_6f_vstr_policy_007', + '2524639890ba4f2cba9ba1a4eeaa4015', + 'dde6cc9a4f6b4f5490d03e26fb016200', + 'INTERSECT_ALLOWLIST', + '["605560541473144832"]', + NULL, 1, 1, + '物业管理总部:访客默认仅开放 6F。', + UNIX_TIMESTAMP(NOW()) * 1000, + UNIX_TIMESTAMP(NOW()) * 1000 +) ON DUPLICATE KEY UPDATE + policy_type = VALUES(policy_type), + allow_zone_ids = VALUES(allow_zone_ids), + enabled = VALUES(enabled), + policy_version = policy_version + 1, + remark = VALUES(remark), + updated_at = VALUES(updated_at); diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/run.sh b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/run.sh new file mode 100755 index 00000000..f1a432e1 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/run.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# 与当前目录下 application.properties 同路径启动 V2(maven 构建)包。 +# 默认优先系统 JDK 8;若只有 JDK11+ 会自动附加 --add-opens。 +# ELEVATOR_USE_ENV_JAVA=1 ./run.sh 使用当前 JAVA_HOME(如 Conda)。 +# 发布包内脚本与 JAR、properties 均位于发布根目录(与 cw-elevator-application-V1.0.0.20211103 布局一致)。 +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=../common-java.sh +source "${SCRIPT_DIR}/../common-java.sh" +cd "$SCRIPT_DIR" + +JAR="" +for candidate in $(ls -1t cw-elevator-application-*.jar 2>/dev/null || true); do + if [[ "${candidate}" == *.jar.original ]]; then + continue + fi + JAR="${candidate}" + break +done +if [[ -z "${JAR}" || ! -f "${JAR}" ]]; then + echo "缺少 cw-elevator-application-*.jar,请在 deploy 目录执行: ./sync-jars.sh" >&2 + exit 1 +fi + +_pick_java_home +if [[ ! -x "${JAVA_HOME}/bin/java" ]]; then + echo "ERROR: 未找到可执行的 JDK。请安装 openjdk-8-jdk,或设定 JAVA_HOME / ELEVATOR_USE_ENV_JAVA=1 ./run.sh(使用 Conda 等当前环境)。" >&2 + exit 1 +fi +JAVA="${JAVA_HOME}/bin/java" +OPEN_FLAGS=() +while IFS= read -r line; do + [[ -n "$line" ]] && OPEN_FLAGS+=("$line") +done < <(_jdk8_open_flags "$JAVA") + +# 强制走 Consul:不再注入本地 application*.properties / redis-override.properties。 +# shellcheck disable=SC2086 +exec "$JAVA" "${OPEN_FLAGS[@]}" ${ELEVATOR_JAVA_OPTS:-} -jar "$JAR" diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/start.sh b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/start.sh new file mode 100755 index 00000000..d08a9439 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/start.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# 与「星中心」V1 部署习惯对齐:本脚本与 cw-elevator-application-V1.0.0.20211103.jar、bootstrap/application*.properties 位于同一目录。 +# 覆盖 JVM:设置环境变量 ELEVATOR_JAVA_OPTS(可选);指定 Java:JAVA_HOME 或 JAVA_CMD。 +set -euo pipefail +dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd "$dir" +JAR="cw-elevator-application-V1.0.0.20211103.jar" +if [[ ! -f "$JAR" ]]; then + echo "ERROR: 未找到 ${JAR}(当前目录 $(pwd))" >&2 + exit 1 +fi +if [[ -n "${JAVA_CMD:-}" ]]; then + JAVA_EXEC="$JAVA_CMD" +elif [[ -n "${JAVA_HOME:-}" && -x "${JAVA_HOME}/bin/java" ]]; then + JAVA_EXEC="${JAVA_HOME}/bin/java" +else + JAVA_EXEC="/usr/lib/jvm/java-8-openjdk-amd64/bin/java" +fi +if [[ -z "${ELEVATOR_JAVA_OPTS:-}" ]]; then + ELEVATOR_JAVA_OPTS="-Xmx3072m -Xms3072m -Xmn1024m" +fi +# shellcheck disable=SC2086 +exec "$JAVA_EXEC" $ELEVATOR_JAVA_OPTS -jar "$JAR" diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/stop.sh b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/stop.sh new file mode 100755 index 00000000..c540f9ec --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/stop.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# 停止与本目录 cw-elevator-application-V1.0.0.20211103.jar 对应的 Java 进程(仅匹配命令行中含该 JAR 名的进程)。 +set -euo pipefail +JAR="cw-elevator-application-V1.0.0.20211103.jar" +# shellcheck disable=SC2009 +pid=$(ps -ef | grep '[j]ava' | grep "$JAR" | awk '{print $2}' || true) +if [[ -n "${pid}" ]]; then + kill -9 $pid +fi diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/升级计划.md b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/升级计划.md new file mode 100644 index 00000000..281e7025 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/升级计划.md @@ -0,0 +1,106 @@ +# cw-elevator-application v2.0.6 升级计划 + +**项目名称**(可填):智慧电梯 / 访客派梯系统升级 +**版本**:v2.0.6 +**计划性质**:执行级排期草案,**具体日期、起止时刻以与甲方书面/邮件确认为准**。 + +--- + +## 1. 升级目标 + +完成电梯派梯应用 **v2.0.6** 上线,启用**租户访客固定访问楼层**能力所需的应用与数据库对象;按业务需要为指定租户配置策略并完成验收。 + +--- + +## 2. 计划时间窗口(夜间 · 暂定周二、周三) + +| 窗口 | 意向安排 | 建议内容(可合并或调整) | +|------|-----------|----------------------------| +| **第一次:周二晚间** | 夜间低峰段,具体 **HH:MM–HH:MM** 待定 | 环境检查、数据库备份、执行 **DDL**(新建策略表)、(可选)预发布验证、必要时准备回滚包与检查单 | +| **第二次:周三晚间** | 夜间低峰段,具体 **HH:MM–HH:MM** 待定 | 部署新版本 **JAR**、滚动/重启应用、按需 **INSERT** 租户策略数据、业务联调与验收、监控与值守 | + +**说明**: + +- 若贵方现场要求**一个晚上完成全部步骤**,可将 DDL 与部署**合并在同一晚间窗口**执行,本表仅体现「周二、周三两晚」的**当前意向拆分**,最终以确认单为准。 +- 两次窗口建议**间隔至少数小时至一个工作日**,便于第一次变更后观察库表与低风险项;若合并为单次窗口,须在计划单中注明**连续操作顺序与回滚点**。 + +**待确认栏**(实施时填写): + +- 周二实施日期:`____年____月____日`,时段: `____ : ____` – `____ : ____` +- 周三实施日期:`____年____月____日`,时段: `____ : ____` – `____ : ____` +- 甲方现场联系人: `____________` 乙方/实施负责人: `____________` + +--- + +## 3. 影响范围与沟通 + +| 项目 | 说明 | +|------|------| +| 影响系统 | 电梯派梯相关应用(`cw-elevator-application`)及同一业务库。 | +| 用户感知 | 应用重启期间可能出现短时派梯接口失败;策略误配可能导致部分访客路径失败,需按验收清单核对。 | +| 通知范围 | 建议提前通知:物业/客服、前台与访客登记、安保与梯控相关值班(按项目实际 roster 确定)。 | + +--- + +## 4. 前置条件(升级前) + +- [ ] 已与甲方确认 **周二 / 周三** 夜间窗口。 +- [ ] 取得 **v2.0.6** 发布包(含 `jar`、`ddl/tenant_visitor_floor_policy.sql`、说明书)。 +- [ ] 目标环境 **JDK 版本**符合实施方要求(与构建说明一致,一般为 JDK 8)。 +- [ ] 数据库已做**备份**(全库或按运维规范),并可从发布包定位 DDL。 +- [ ] 明确需启用「固定访客楼层」的租户列表及**允许区域**配置(若不启用,可跳过策略数据录入,行为与升级前一致)。 +- [ ] 回滚包:保留**当前线上 JAR** 备份与回滚步骤(见下文)。 + +--- + +## 5. 实施步骤(建议顺序) + +### 5.1 周二晚间(或首个窗口) + +1. 备份数据库。 +2. 执行 `tenant_visitor_floor_policy.sql`(`CREATE TABLE IF NOT EXISTS`,可重复执行需与 DBA 确认)。 +3. (可选)在测试/预发环境先执行一遍并验证。 +4. 记录执行人、时间与结果。 + +### 5.2 周三晚间(或第二个窗口 / 同晚续作) + +1. 停止或滚动发布应用(按现网规范)。 +2. 替换为 `cw-elevator-application-2.0.6.jar` 并启动。 +3. 按业务需求对需启用的租户执行策略 **INSERT**(`enabled=1`、`allow_zone_ids` 等为合法 JSON 等,字段级以技术说明书为准)。 +4. 抽样验证:未传显式楼层时的访客派梯、租户策略开/关、与组织楼层无交集时的失败提示等。 +5. 观察监控与日志,**值守**至约定结束时间。 + +*若合并为单次窗口:按「备份 → DDL → 部署 JAR → 策略数据 → 验收」顺序连续执行,并预留回滚决策时间。* + +--- + +## 6. 验收要点(摘要) + +- 未配置或未启用策略时:与升级前行为一致。 +- 已启用策略且业务走「未显式指定楼层」路径:访客可去楼层为**组织允许**与**租户允许**的**交集**。 +- 交集为空时:接口返回预期业务错误(技术码见实施方说明书)。 +- 第三方已显式传入楼层的路径:不因本策略表改变原逻辑。 + +--- + +## 7. 回滚预案 + +| 场景 | 建议动作 | +|------|-----------| +| 应用异常 | 回退至上一版本 JAR;数据库新表若已存在且旧应用不读该表,通常可继续服务;与实施方确认。 | +| 策略配置错误 | 优先**停用或修正策略行**,避免大规模回滚应用。 | +| 必须撤表 | 仅在评估无依赖后由 DBA 执行删表;**高风险**,需书面确认。 | + +--- + +## 8. 交付物核对 + +- [ ] `cw-elevator-application-2.0.6.jar` +- [ ] `ddl/tenant_visitor_floor_policy.sql` +- [ ] 《版本升级说明书》(实施/技术) +- [ ] 本《甲方版本升级说明》(如已作为对甲交付) +- [ ] 本《升级计划》(双方确认签字/邮件留档) + +--- + +**文档状态**:草案;**时间点为暂定周二、周三晚间**,正式实施前请更新「待确认栏」并留存确认记录。 diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/发布说明.md b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/发布说明.md new file mode 100644 index 00000000..f44c05df --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/发布说明.md @@ -0,0 +1,32 @@ +# cw-elevator-application v2.0.6 发布索引 + +本版本**功能升级说明**已单独成文,**仅覆盖「租户访客固定访问楼层」**及配套数据库 DDL,见: + +**[cw-elevator-application-v2.0.6-版本升级说明书](./cw-elevator-application-v2.0.6-版本升级说明书.md)** + +**对甲交付(业务表述与排期)**: + +- [甲方版本升级说明](./cw-elevator-application-v2.0.6-甲方版本升级说明.md) +- [升级计划(含夜间 · 周二/周三窗口)](./cw-elevator-application-v2.0.6-升级计划.md) +- [实施交付清单(实施方内部与对甲交付核对)](./cw-elevator-application-v2.0.6-实施交付清单.md) +- [实施验收记录模板(上线当晚记录)](./cw-elevator-application-v2.0.6-实施验收记录模板.md) +- [SQL与代码一致性审核记录(发布规范走查依据)](./cw-elevator-application-v2.0.6-SQL与代码一致性审核记录.md) + +--- + +## 一键构建与发布目录 + +在仓库根目录、**JDK 8** 下执行: + +```bash +export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 +./scripts/release-cw-elevator-application.sh 2.0.6 +``` + +输出:**`maven-cw-elevator-application/releases/cw-elevator-application-V2.0.6./`**(目录名含构建日期,与 `cw-elevator-application-V1.0.0.20211103` 命名风格一致;可用环境变量 **`RELEASE_DATE_LABEL`** 指定日期),含 `cw-elevator-application-2.0.6.jar`、`ddl/`、发布根目录下的 `bootstrap.properties` / `application*.properties`(与星中心/V1 同层摆放,**无额外 `config/` 子目录**)、`start.sh` / `stop.sh` / `cw-elevator-application.service`(路径占位符需现场替换)、`run.sh`、`common-java.sh`、**`collect_elevator_runtime_evidence.sh`**(根目录,现场只读证据采集)、`版本升级说明书.md`、甲方与实施类 Markdown、`BUILD_MANIFEST.txt`;默认另生成 **`releases/cw-elevator-application-V2.0.6..zip`**(设 `RELEASE_MAKE_ZIP=0` 可跳过)。 + +--- + +## Git 与大文件 + +`maven-cw-elevator-application/.gitignore` 忽略 `**releases/**/*.jar**`;**DDL 与说明书**可提交;可执行 JAR 请通过制品库或制品服务器分发。 \ No newline at end of file diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/实施交付清单.md b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/实施交付清单.md new file mode 100644 index 00000000..dc8e99a1 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/实施交付清单.md @@ -0,0 +1,60 @@ +# cw-elevator-application v2.0.6 实施交付清单 + +**用途**:用于正式发布交付前后的材料核对,满足“发布包 + 数据库脚本 + 升级说明 + 实施验收记录”闭环。 + +--- + +## 1. 发布包文件清单 + +- [ ] `cw-elevator-application-2.0.6.jar` +- [ ] `ddl/tenant_visitor_floor_policy.sql`(建表脚本) +- [ ] `ddl/tenant_visitor_floor_policy_init_guangfa_fund.sql`(广发基金初始化示例/可直接执行) +- [ ] `版本升级说明书.md`(技术实施口径) +- [ ] `甲方版本升级说明.md`(业务口径) +- [ ] `升级计划.md`(实施窗口与回滚安排) +- [ ] `实施验收记录模板.md`(上线当晚记录) +- [ ] `BUILD_MANIFEST.txt`(构建时间、分支、提交号) + +--- + +## 2. 数据库变更交付项 + +- [ ] DBA 已确认目标库与执行窗口 +- [ ] 已备份目标库(全库/指定库按现场规范) +- [ ] 已执行 `tenant_visitor_floor_policy.sql` +- [ ] 已执行或评审 `tenant_visitor_floor_policy_init_guangfa_fund.sql` +- [ ] 已确认 `allow_zone_ids` 使用的是电梯库 `zone_id`(非其它系统 UUID) +- [ ] 已留存 SQL 执行记录(执行人、时间、结果) + +--- + +## 3. 应用部署交付项 + +- [ ] 上线前已保存旧版 JAR 回滚包 +- [ ] 已按窗口替换为 `cw-elevator-application-2.0.6.jar` +- [ ] 应用启动日志无严重报错 +- [ ] 关键接口健康检查通过(含 `add/visitor` 主链路) +- [ ] 监控观察窗口内无持续异常 + +--- + +## 4. 验收交付项 + +- [ ] UC-01:未传 `floorIds` 且策略启用时,楼层为 `floorList ∩ allow_zone_ids` +- [ ] UC-01:无交集时返回 `76260532` +- [ ] UC-02:显式传 `floorIds` 时不受策略表影响 +- [ ] 未启用策略租户行为与升级前一致 +- [ ] 已按《实施验收记录模板》完成签字/邮件留档 + +--- + +## 5. 交付确认信息 + +| 项目 | 内容 | +|------|------| +| 实施项目 | cw-elevator-application v2.0.6 | +| 实施日期 | `____年____月____日` | +| 甲方确认人 | `____________` | +| 乙方实施人 | `____________` | +| 文档留存路径 | `____________` | + diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/实施验收记录模板.md b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/实施验收记录模板.md new file mode 100644 index 00000000..ada23381 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/实施验收记录模板.md @@ -0,0 +1,73 @@ +# cw-elevator-application v2.0.6 实施验收记录模板 + +**用途**:实施当晚记录数据库执行、应用部署、业务验收和回滚判定,作为交付归档依据。 + +--- + +## 1. 基本信息 + +| 项目 | 内容 | +|------|------| +| 项目名称 | 智慧电梯 / 访客派梯系统 | +| 发布版本 | v2.0.6 | +| 实施日期 | `____年____月____日` | +| 实施时段 | `____:____` - `____:____` | +| 环境 | 生产 / 预生产(圈选) | +| 实施负责人 | `____________` | +| 甲方联系人 | `____________` | + +--- + +## 2. 数据库执行记录 + +| 序号 | 脚本 | 执行时间 | 执行人 | 结果 | 备注 | +|------|------|----------|--------|------|------| +| 1 | tenant_visitor_floor_policy.sql | `____` | `____` | 成功/失败 | `____` | +| 2 | tenant_visitor_floor_policy_init_guangfa_fund.sql | `____` | `____` | 成功/失败 | `____` | + +**异常记录**:`______________________________________________` + +--- + +## 3. 应用发布记录 + +| 项目 | 记录 | +|------|------| +| 上线前版本 | `____________` | +| 上线后版本 | `cw-elevator-application-2.0.6.jar` | +| 启停方式 | `____________` | +| 服务恢复时间 | `____________` | +| 日志健康检查 | 通过 / 不通过 | +| 监控观察结论 | 正常 / 异常(说明) | + +--- + +## 4. 验收结果记录 + +| 用例 | 期望 | 实际 | 结论 | +|------|------|------|------| +| UC-01(未传 floorIds,策略启用) | floorList 与 allow_zone_ids 求交 | `____` | 通过/不通过 | +| UC-01(交集为空) | 返回 `76260532` | `____` | 通过/不通过 | +| UC-02(显式传 floorIds) | 不受策略表影响 | `____` | 通过/不通过 | +| 无策略租户回归 | 行为与升级前一致 | `____` | 通过/不通过 | + +--- + +## 5. 回滚判定 + +- [ ] 无需回滚,发布成功 +- [ ] 需要回滚应用(原因:`________________`) +- [ ] 需要回滚数据/策略(原因:`________________`) + +回滚执行记录(如发生):`______________________________________________` + +--- + +## 6. 签字确认 + +| 角色 | 姓名 | 日期 | 备注 | +|------|------|------|------| +| 甲方确认 | `____________` | `____` | `____` | +| 乙方实施 | `____________` | `____` | `____` | +| 乙方复核 | `____________` | `____` | `____` | + diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/版本升级说明书.md b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/版本升级说明书.md new file mode 100644 index 00000000..bf3515f4 --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/版本升级说明书.md @@ -0,0 +1,112 @@ +# cw-elevator-application v2.0.6 版本升级说明书 + +**适用范围**:本说明**仅**描述 **v2.0.6** 中与 **租户访客固定访问楼层**(租户级允许区域与组织 `floorList` 求交)相关的升级内容,不含其它性能优化或通用发布项。 + +**应用制品**:`cw-elevator-application-2.0.6.jar`(Spring Boot 可执行 fat JAR)。 + +--- + +## 1. 功能概述 + +在 **访客派梯** 接口 **`add/visitor`**(实现类 `PersonRuleServiceImpl#addVisitor`)中,当调用方 **未传入非空 `floorIds`**(业务流程 **UC-01**:按被访人组织侧楼层推导)时: + +1. 服务仍先通过 **`person/detail`** 取得被访人 **`floorList`**(与升级前一致)。 +2. **新增**:若数据库中存在**启用**的租户策略行,且 **`allow_zone_ids`** 解析为非空 JSON 数组,则最终生效楼层为 + **`effectiveFloors = floorList ∩ allow_zone_ids`**(顺序保持 **`floorList`** 原有顺序)。 +3. 若交集 **为空**,接口返回失败码 **`76260532`**(不允许静默放宽到其它楼层)。 +4. 若无策略表、无启用行、`allow_zone_ids` 为空或 JSON 无效:行为与升级前一致,使用 **`floorList` 全集**。 + +当调用方 **已传入非空 `floorIds`**(**UC-02**,第三方显式指定楼层)时:**不读取**策略表,**不对入参求交**,与升级前一致。 + +> **产品表述**:「固定访问楼层」在本阶段由租户管理员通过 **`allow_zone_ids`** 声明**允许开放给访客派梯的区域(zoneId)集合**;在 UC-01 路径下与组织返回的 **`floorList`** 取交集,从而将访客权限**收敛**到既有「被访人可去楼层」与「租户允许楼层」的双重约束内。 + +--- + +## 2. 涉及的数据库变更 + +### 2.1 变更类型 + +| 类型 | 对象 | +|------|------| +| **新增表** | `tenant_visitor_floor_policy` | + +**执行库**:与电梯应用 **同一数据源**(MySQL/InnoDB,与现有派梯业务库一致)。 + +### 2.2 表用途(摘要) + +| 字段 | 含义 | +|------|------| +| `business_id` | 租户/机构 ID | +| `policy_type` | 本阶段固定 **`INTERSECT_ALLOWLIST`** | +| `allow_zone_ids` | **TEXT**,存 **JSON 数组**字符串,元素为允许访客派梯的 **zoneId** | +| `building_id` | 租户级默认策略填 **NULL**(预留楼栋维) | +| `enabled` | **1** 启用 / **0** 停用 | +| `policy_version` | 配置版本号(审计) | + +唯一约束 **`uk_biz_building (business_id, building_id)`**:同一租户、租户级策略(`building_id` 为空)**建议仅维护一行**,避免多行时查询仅命中「最新一条」与运维预期不符。 + +### 2.3 DDL 脚本位置 + +| 用途 | 仓库内路径 | +|------|------------| +| **权威 DDL** | `docs/sql/tenant_visitor_floor_policy.sql` | + +**发布包内副本**:随 v2.0.6 发布目录一并下发,路径为 **`ddl/tenant_visitor_floor_policy.sql`**(与根目录 JAR 同级下的 `ddl` 子目录)。 + +脚本内容为 **`CREATE TABLE IF NOT EXISTS`**,在未建表环境可重复执行;**不含**业务数据 `INSERT`,上线需按租户配置自行 **`INSERT`** 策略行。 + +### 2.4 上线执行顺序(建议) + +1. **备份**当前电梯应用库(至少包含待变更库的全库或相关表备份策略)。 +2. 在目标库执行 **`ddl/tenant_visitor_floor_policy.sql`**(或直接使用仓库 `docs/sql` 下同源文件)。 +3. 对需启用策略的租户 **`INSERT`** 一行(示例字段:`business_id`、`policy_type='INTERSECT_ALLOWLIST'`、`allow_zone_ids` 为合法 JSON 数组、`enabled=1`、`building_id` 为 **NULL**)。 +4. 部署 **`cw-elevator-application-2.0.6.jar`** 并滚动重启应用。 +5. 按 §4 做 **UC-01 / UC-02** 验收。 + +### 2.5 回滚说明 + +- **仅回滚应用**:还原旧版本 JAR 后,若库中**已存在**策略行且仍为 **enabled=1**,旧版本应用**通常不读取**该表,行为与历史一致;表结构可保留。 +- **回滚数据库**:若需删除表(谨慎),在确认无其它依赖后执行 **`DROP TABLE tenant_visitor_floor_policy`**;请在变更窗口与 DBA 确认。 + +--- + +## 3. 行为与错误码(验收) + +| 场景 | `floorIds` | 策略库 | 期望 | +|------|------------|--------|------| +| UC-01 基线 | 空/未传 | 无启用行或 allow 空/无效 | 使用组织 **`floorList` 全集**(与升级前一致) | +| UC-01 + 固定楼层 | 空/未传 | 有启用行且 allow 非空 | **`floorList ∩ allow`**(保序) | +| 无交集 | 空/未传 | allow 与 `floorList` 无交集 | **`76260532`** | +| 被访人无楼层 | 空/未传 | 任意 | **`76260531`** | +| UC-02 | **非空** | 任意 | **不读策略表**,按请求楼层处理 | + +--- + +## 4. 发布包目录结构(v2.0.6) + +执行仓库根目录 **`./scripts/release-cw-elevator-application.sh 2.0.6`** 后,输出目录为(名称含构建日期 ``,与历史运行包 **`cw-elevator-application-V1.0.0.20211103`** 同构;可用环境变量 **`RELEASE_DATE_LABEL`** 固定日期): + +**`maven-cw-elevator-application/releases/cw-elevator-application-V2.0.6./`** + +| 文件/目录 | 说明 | +|-----------|------| +| `cw-elevator-application-2.0.6.jar` | 可执行应用 | +| `bootstrap.properties`、`application*.properties` | 与 JAR 同层(**不**再使用 `config/` 子目录重复存放) | +| `ddl/tenant_visitor_floor_policy.sql` | 与本功能相关的 **唯一 DDL**(与 `docs/sql` 同源) | +| `版本升级说明书.md` | 本文件副本(便于随包交付) | +| `BUILD_MANIFEST.txt` | 构建时间、JDK、`git` 修订号 | + +--- + +## 5. 参考文档(仓库内) + +| 文档 | 路径 | +|------|------| +| 数据库阶段变更记录 | `docs/business/租户访客默认楼层-数据库阶段变更记录.md` | +| 数据库配置阶段技术设计 | `docs/business/租户访客默认楼层-数据库配置阶段技术设计.md` | +| 技术产品方案 | `docs/business/租户访客默认楼层技术产品方案.md` | +| 访客注册与派梯楼层走查 | `docs/business/访客注册与派梯楼层业务流程走查.md` | + +--- + +**文档版本**:与制品 **`cw-elevator-application-2.0.6`** 对齐;若仅升级文档而不改代码,请以 **`BUILD_MANIFEST.txt`** 中构建时间为准。 diff --git a/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/甲方版本升级说明.md b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/甲方版本升级说明.md new file mode 100644 index 00000000..89ae5c8d --- /dev/null +++ b/maven-cw-elevator-application/releases/cw-elevator-application-V2.0.20.20260505/甲方版本升级说明.md @@ -0,0 +1,34 @@ +# 电梯派梯应用 v2.0.6 — 版本升级说明(广发基金) + +**制品**:`cw-elevator-application-2.0.6.jar`。技术细节、验收码与脚本位置见同目录《版本升级说明书》。 + +--- + +## 本次升级做什么 + +针对**广发基金**租户:访客走常见派梯路径(接口**未单独传楼层**)时,系统在「被访人所在单位给的可去楼层」基础上,再按**广发基金侧配置的允许区域**做一次收紧,两边**都满足**的楼层才能派梯。这样可以把访客权限收在比如固定接待层,而员工本人仍可按组织权限去多层办公。 + +广发基金若**未配置或未启用**该策略,行为与现在一致。 + +--- + +## 上线要动什么 + +- 换新版应用包。 +- 库里**多一张策略表**(脚本在发布包 `ddl/` 下);表里为广发基金写入**一行**启用策略即可,允许区域(如接待层对应的 zone)由业务与实施定稿。 + +其它租户不配策略则**不受影响**。 + +--- + +## 对您这边的影响 + +- **时间**:安排在**夜间**,具体周二/周三窗口见《升级计划》。 +- **中断**:重启应用时派梯接口可能**短暂**不可用,一般会控制在很短时间。 +- **配合**:指定一个对接人;确认广发基金侧要开放的**访客可达区域/楼层**(与前台、接待流程对齐);上线后若有异常派梯请及时反馈。 + +--- + +## 出问题怎么办 + +应用可先退回上一版包;策略数据可单独改/停,不一定整库回滚。细则见《升级计划》。 \ No newline at end of file