# yin **Repository Path**: tangyb/yin ## Basic Information - **Project Name**: yin - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-12 - **Last Updated**: 2026-09-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

YIN(殷)

YIN Spring Boot Spring Modulith Vue Java MySQL PRs Welcome

## 系统说明 - **YIN(殷)** 是面向企业后台的 **多租户 RBAC 脚手架**:后端 **Spring Modulith 模块化单体**,前端 **Vue3 管理端**。 - 横切能力拆为 **即插即用 Starter**(web / security / mybatis / cache / lock / event / file / sms / job),业务模块按包边界隔离:`shared` · `iam` · `system`。 - IAM 热域(Auth / User / Tenant / Role / Dept / Menu)采用 **六边形 + 逻辑 CQRS**;跨模块副作用用 Modulith 事件落到 `system`。 - 认证基于 **Sa-Token(Redis 会话)**;数据层 **MyBatis-Plus + Flyway**;租户行级隔离,**无租户上下文 fail-closed**。 **设计理念:** 最小公共、各司其职、Starter = 即插即用能力;业务边界用 Modulith NamedInterface 锁死。 > Agent / 编码约定见 [AGENTS.md](AGENTS.md) 与 [`.cursor/rules/`](.cursor/rules/)。 ## 架构全景 ``` 浏览器 / yin-ui (:5173) │ /api 代理 ▼ yin-launcher Spring Boot (:8080) ├── iam /api/v1/auth · /api/v1/iam/** AuthFacade / IamStatsFacade ├── system /api/v1/system/** 字典 · 日志 · 仪表盘 · 配置 · 文件 · 任务 └── shared NamedInterface web|security|mybatis|cache|lock|event|file|sms|notice|job ▲ │ yin-common 纯类型 + yin-starters/* 实现 → yin-shared 聚合 基础设施:MySQL 8.0(SQL 方言兼容 5.7)· Redis 7 · Flyway · Actuator · springdoc ``` ## 快速开始 ### 基础环境 | 组件 | 版本 | |------|------| | JDK | **25**(设置 `JAVA_HOME`) | | Maven | **3.9+** | | Node.js | **22+**(根目录 `.nvmrc`;`fnm use` / `nvm use`) | | MySQL | **8.0+ 推荐**(Docker Compose 为 `mysql:8.0`);迁移脚本保持 **5.7 方言**(避免 8.0 专有语法)。5.7 已 EOL,新环境请用 8.0/8.4 | | Redis | **6+**(推荐 7;<6 已做 Sa-Token KEEPTTL 兼容) | ### 1. 准备基础设施 ```sql CREATE DATABASE yin DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ``` - MySQL 默认:`127.0.0.1:3306`,用户/密码 `root`/`123456`(可用 `MYSQL_*` 覆盖) - Redis 默认:`127.0.0.1:6379`,无密码(可用 `REDIS_*` 覆盖) **不必手工导 SQL**:启动时 Flyway 执行 `yin-launcher/src/main/resources/db/migration`(schema + 种子数据)。以 Flyway 脚本为唯一真相源,勿维护平行 schema/seed 快照。 ### 2. 启动后端 仓库根目录: ```powershell $env:JAVA_HOME='D:\path\to\jdk-25' mvn -q -pl yin-launcher -am spring-boot:run # 或指定环境 mvn -q -pl yin-launcher -am spring-boot:run "-Dspring-boot.run.profiles=sit" ``` | 入口 | 地址 | |------|------| | API | http://localhost:8080 | | springdoc | http://localhost:8080/swagger-ui.html | | Actuator | `/actuator/health`(另暴露 `info` / `metrics` / `modulith`) | ### 3. 启动前端 ```bash cd yin-ui fnm use # 或 nvm use npm install npm run dev ``` 开发地址:http://localhost:5173(Vite 将 `/api` 代理到 `http://127.0.0.1:8080`)。 其它脚本:`npm run build:sit` / `build:uat` / `build:prod`;环境变量在 `yin-ui/config/`。 ### 默认账号 与 Flyway 种子数据一致;登录需填写 **租户编码** + 用户名 + 密码。 | 角色 | 租户编码 | tenant_id | 用户名 | 密码 | |------|----------|-----------|--------|------| | 平台超管 | `platform` | `0` | `admin` | `Tenant@2026` | | 租户管理员 | `demo` | `1` | `tenant_admin` | `Tenant@2026` | 平台超管可在顶栏切换「管理租户」,请求头携带 `X-Tenant-Id`(仅平台超管生效)。 ## 核心依赖 | 依赖 | 版本 | |------|------| | Java | 25 | | Spring Boot | 4.1.1 | | Spring Modulith | 2.1.1 | | MyBatis-Plus | 3.5.17 | | Sa-Token | 1.46.0 | | Redisson | 4.3.1 | | Druid | 1.2.28 | | springdoc | 3.1.1 | | Vue / Vite / Element Plus | 3 / 最新 / 最新 | | Node.js | 22+ | ## 功能特性 | 功能 | 说明 | |------|------| | **Modulith 模块化单体** | 包级模块 `shared` / `iam` / `system`;NamedInterface 显式依赖;`ModularityTests` 校验 | | **六边形 + 逻辑 CQRS** | IAM 热域:`domain` + `CommandService` / `QueryService`;ArchUnit 锁 domain 无框架依赖 | | **即插即用 Starter** | web / security / mybatis / cache / lock / event / file / sms / job;`yin-shared` 聚合引入;可选增强见空骨架 `yin-starters-contrib`(单点引入,禁止九连发) | | **多租户 RBAC** | `tenant_id` 行级隔离;按钮级权限;`@DataScope` 数据权限;平台租户 `0` | | **Sa-Token 会话** | Redis 会话;`Authorization`;`is-concurrent=false` 新登录挤旧会话;`POST /api/v1/auth/renew` 静默续期;登录失败锁定 `yin.auth.login-lock`;短信登录 `yin.auth.sms-login`(dev 默认开);SSO `yin.auth.sso`(默认关,OIDC 授权码 + UserInfo,无厂商 SDK) | | **审计与事件** | `@OperLog` → 事件落库;登录成功/失败/登出/权限变更由 system 监听 | | **缓存与锁** | L1+L2 Cache;`@DistributedLock`(Redisson) | | **安全横切** | XSS 消毒;`@RepeatSubmit` / `@Idempotent`;`@RateLimit`;`@Desensitize`;`@ApiSign`(默认关);字段 AES-GCM | | **文件 / 短信 / 任务** | `FileStorage`(local / s3,预签名与分片);管理端 >5MB 服务端分片;`SmsSender`(默认 log);`NoticeSender`(默认 log);`@YinJob` 目录 + 手动触发/启停/失败重试(`system:job:trigger|edit`,Flyway V13);多实例下有 `DistributedLock` 时集群互斥(`yin.job.cluster-lock-*`) | | **特性开关** | `sys_config` 的 `feature.*`;布尔真值或 `0`–`100` 百分比灰度(`FeatureFlagContext` 按租户/用户分桶) | | **可观测** | Actuator;MDC `traceId`;访问耗时日志 | ## 模块说明 ```lua yin -- Maven 父工程(根目录执行 mvn) ├── yin-common -- 纯类型:R、异常、BaseEntity、TenantContext、事件类型(无 AutoConfig) ├── yin-starters -- 即插即用 Starter │ ├── yin-web-starter -- Advice、XSS、AccessLog、OperLog、SpringDoc │ ├── yin-security-starter-- Sa-Token、限流/签名/幂等/脱敏 │ ├── yin-mybatis-starter -- MP、租户行、DataScope、字段加密 │ ├── yin-cache-starter -- Spring Cache、L1+L2 │ ├── yin-lock-starter -- DistributedLock / Redisson │ ├── yin-event-starter -- Modulith 事件运维(如 purge) │ ├── yin-file-starter -- FileStorage(local / s3) │ ├── yin-sms-starter -- SmsSender(默认 log) │ ├── yin-notice-starter -- NoticeSender(默认 log) │ └── yin-job-starter -- @YinJob 任务目录 ├── yin-shared -- 聚合 common + starters;Modulith shared 模块根与 NI ├── yin-starters-contrib -- 可选增强聚合(空骨架;勿默认并入 shared) ├── yin-iam-api -- AuthFacade / IamStatsFacade + view / event(auth-api) ├── yin-iam -- 登录与用户/角色/菜单/部门/租户 + HTTP ├── yin-system -- 字典、日志、仪表盘、配置、文件、任务;事件监听 ├── yin-launcher -- Boot 启动、Flyway、application-*.yml └── yin-ui -- Vue3 管理端 ``` ## 配置说明 - Profile:`dev`(默认)/ `sit` / `uat` / `prod`,位于 `yin-launcher/src/main/resources/application-*.yml` - 本机 `application-dev.yml`:MySQL `root`/`123456`、Redis `127.0.0.1:6379`;可用环境变量覆盖 - 缓存:`spring.cache.type=redis` - 前端:`yin-ui/config/.env.{dev,sit,uat,prod}`(Vite `envDir=config`) - 包名统一 `com.yin.*`;Starter 能力经 `shared :: ` 按需声明(禁止 `shared :: *`,无 `shared :: config`) ## 呼叫中心(CC) ### 运营配置顺序(建议) 1. **平台**:菜单「FS 节点」将目标节点置为 `UP`(`/api/v1/cc/fs-nodes`;仅平台角色;密码不回显) 2. **租户**:配置「外呼网关」首选/允许节点 →「租户配额」上限 →「技能组」→「禁呼名单」 3. **活动**:创建活动 → 导入名单 → `PROGRESSIVE` 靠 `@YinJob("cc.campaign.tick")` 自动拨;`PREVIEW` 在活动页「点拨」(领取 / 拨打;名单可删或重置为 PENDING;CLAIMED 超时由 `@YinJob("cc.campaign.preview-reclaim")` 回收) 4. **坐席**:签入后用软电话;通话列表可挂机;话单在「话单查询」(录音:launcher `yin.cc.recording.*` + ESL `yin.cc.esl.recording-dir` 对齐后挂机上传) 菜单与权限种子:`V14`–`V31`(配额 V29、FS 节点 V30、技能组 V31)。管理端页面在 `yin-ui/src/views/cc/`。 ### 联调与冒烟 可选 **双 FreeSWITCH + 双 ESL**:Flyway ≥ V14 后,用 [docker-compose.cc.yml](docker-compose.cc.yml) 的 `cc` profile 起 `fs-1`/`fs-2` 与 `esl-1`/`esl-2`;failover 见 [scripts/cc-dual-fs-smoke.md](scripts/cc-dual-fs-smoke.md)。 国内拉镜像可在 Docker Desktop 配 `registry-mirrors`;FS event_socket / `demo-gw` 见 [deploy/freeswitch/](deploy/freeswitch/)。 坐席软电话默认 `ws://127.0.0.1:5066` / `sip:1000@127.0.0.1` / `1234`(`yin-ui/config/.env.dev` + `deploy/freeswitch/directory`)。HTTPS 用 `wss://127.0.0.1:7443`:先 `powershell -NoProfile -File scripts/gen-fs-wss-cert.ps1`。演示 gateway=`local` → ESL 拨 `user/<分机>`。浏览器步骤:[scripts/cc-softphone-smoke.md](scripts/cc-softphone-smoke.md)。 坐席 SSE:`GET /api/v1/cc/agents/events`(Redis topic 跨 launcher)。SIP 中继模板:[scripts/cc-sip-trunk.md](scripts/cc-sip-trunk.md)。双 launcher / 杀 ESL / 签入:[scripts/cc-phase4-smoke.md](scripts/cc-phase4-smoke.md)。 ## 构建与测试 ```bash # 后端(根目录;需 JDK 25 + Maven 3.9+) mvn -q test # 前端 cd yin-ui && npm run build ``` 变更 Modulith 边界(`package-info` / 模块依赖)后,请确认 `ModularityTests` 通过。 ## 主要 API 前缀 | 模块 | 前缀 | 说明 | |------|------|------| | iam | `/api/v1/auth` | 登录 / 登出 / 当前用户 / 自助改密 / 更新昵称 | | iam | `/api/v1/iam/users\|roles\|menus\|depts\|tenants` | 身份权限 CRUD | | system | `/api/v1/system/dicts\|login-logs\|oper-logs\|dashboard\|configs\|files\|jobs\|events` | 系统能力 | | cc | `/api/v1/cc/agents\|calls\|campaigns\|cdrs\|dnc\|gateways\|quota\|fs-nodes\|skill-groups` | 呼叫中心运营与外呼 | | cc 内网 | `/api/v1/internal/cc/channel-events` | ESL 通道事件(`X-CC-Internal-Token`) |