chore: complete infrastructure config, contracts, reference images and ui redesign artifacts
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
dist
|
||||
*.log
|
||||
.env*
|
||||
pnpm-lock.yaml
|
||||
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 176 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 931 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 126 KiB |
@@ -0,0 +1,5 @@
|
||||
target
|
||||
.m2*
|
||||
local-*
|
||||
build-temp
|
||||
*.log
|
||||
@@ -1,5 +1,4 @@
|
||||
# 丹阳公益婚恋服务平台 - Backend
|
||||
version: '3.8'
|
||||
# 丹阳公益婚恋服务平台 - 本地完整环境
|
||||
|
||||
services:
|
||||
postgres:
|
||||
@@ -89,18 +88,29 @@ services:
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
admin-web:
|
||||
build:
|
||||
context: ../admin-web
|
||||
dockerfile: Dockerfile
|
||||
container_name: danyang-match-admin
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: danyang-match-nginx
|
||||
depends_on:
|
||||
- backend
|
||||
backend:
|
||||
condition: service_healthy
|
||||
admin-web:
|
||||
condition: service_started
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "6688:80"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/health"]
|
||||
test: ["CMD-SHELL", "wget -qO /dev/null http://localhost/nginx-health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
@@ -38,6 +38,10 @@ http {
|
||||
server backend:8080;
|
||||
}
|
||||
|
||||
upstream admin_web {
|
||||
server admin-web:80;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
@@ -59,6 +63,8 @@ http {
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
|
||||
add_header Pragma "no-cache";
|
||||
}
|
||||
|
||||
# WebSocket proxy
|
||||
@@ -84,17 +90,13 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Admin web static files
|
||||
location /admin/ {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /admin/index.html;
|
||||
}
|
||||
|
||||
# Don't cache API responses
|
||||
location /api/ {
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
|
||||
add_header Pragma "no-cache";
|
||||
# Admin web
|
||||
location / {
|
||||
proxy_pass http://admin_web;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,38 @@ assert.match(premaritalTemplate, /service-topics/, '婚前辅导页缺少四项
|
||||
assert.match(premaritalTemplate, /预约辅导/, '婚前辅导页缺少预约按钮')
|
||||
assert.match(premaritalTemplate, /服务状态/, '婚前辅导页缺少服务状态')
|
||||
|
||||
const contentTemplate = read('miniapp/pages/content/content.wxml')
|
||||
const contentLogic = read('miniapp/pages/content/content.js')
|
||||
assert.match(contentTemplate, /content-categories/, '婚恋课堂缺少分类导航')
|
||||
assert.match(contentTemplate, /content-list/, '婚恋课堂缺少内容列表')
|
||||
assert.match(contentTemplate, /viewCount/, '婚恋课堂缺少真实浏览量')
|
||||
assert.match(contentTemplate, /publishAtText/, '婚恋课堂缺少发布日期')
|
||||
assert.match(contentLogic, /\/content\/categories/, '婚恋课堂分类必须来自正式接口')
|
||||
assert.match(contentLogic, /\/content\/articles/, '婚恋课堂文章必须来自正式接口')
|
||||
assert.doesNotMatch(contentLogic, /id:\s*['"]1['"]/, '婚恋课堂不得保留演示文章')
|
||||
|
||||
const antiFraudTemplate = read('miniapp/pages/anti-fraud/anti-fraud.wxml')
|
||||
assert.match(antiFraudTemplate, /ui-service-hero/, '婚恋反诈必须使用独立主视觉')
|
||||
assert.match(antiFraudTemplate, /risk-grid/, '婚恋反诈缺少四类风险')
|
||||
assert.match(antiFraudTemplate, /举报可疑行为/, '婚恋反诈缺少举报入口')
|
||||
assert.match(antiFraudTemplate, /安全求助/, '婚恋反诈缺少求助入口')
|
||||
|
||||
const stationTemplate = read('miniapp/pages/service-station/service-station.wxml')
|
||||
const stationLogic = read('miniapp/pages/service-station/service-station.js')
|
||||
for (const label of ['地址', '联系电话', '开放时间', '服务项目', '地图定位', '预约到站服务']) {
|
||||
assert.ok(stationTemplate.includes(label), `服务站缺少 ${label}`)
|
||||
}
|
||||
assert.match(stationLogic, /wx\.makePhoneCall/, '服务站电话必须使用微信原生拨号')
|
||||
assert.match(stationLogic, /wx\.openLocation/, '服务站定位必须使用微信原生地图')
|
||||
assert.match(stationLogic, /api\.get\(['"]\/home['"]\)/, '服务站必须读取真实首页服务站数据')
|
||||
assert.doesNotMatch(stationLogic, /00000000/, '服务站不得保留演示电话')
|
||||
|
||||
for (const envFile of ['miniapp/env.js', 'miniapp/env.ts']) {
|
||||
const envSource = read(envFile)
|
||||
assert.match(envSource, /getAccountInfoSync/, `${envFile} 必须通过微信运行版本识别开发环境`)
|
||||
assert.match(envSource, /envVersion\s*===\s*['"]develop['"]/, `${envFile} 必须将 develop 环境指向本地 API`)
|
||||
}
|
||||
|
||||
const theme = read('miniapp/app.wxss')
|
||||
for (const token of [
|
||||
'--mini-night-start',
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
|
||||
const read = (path) => fs.readFileSync(path, 'utf8')
|
||||
const engine = read('backend/src/main/java/com/danyang/match/platform/match/service/RecommendationEngineService.java')
|
||||
const legacyEligibility = read('backend/src/main/java/com/danyang/match/platform/match/service/MatchEligibilityService.java')
|
||||
const home = read('backend/src/main/java/com/danyang/match/platform/home/service/HomeApplicationService.java')
|
||||
const card = read('miniapp/components/recommend-card/index.wxml')
|
||||
|
||||
assert.match(engine, /isParticipantEligible\(userId\)/, '推荐入口必须校验当前用户资格')
|
||||
assert.match(engine, /findByRelation\(targetUserId, userId, Constants\.RELATION_TYPE_BLOCKED\)/, '必须检查反向 Block')
|
||||
assert.match(engine, /localEligibilityMapper\.findByUserId/, '正式推荐引擎必须接入本地资格 Provider')
|
||||
assert.doesNotMatch(legacyEligibility, /PROFILE_STATUS_PENDING_REVIEW\.equals\(el\.getVerificationStatus\(\)\)/, 'pending_review 不得视为本地资格通过')
|
||||
assert.match(home, /recommendationEngineService\.getDailyRecommendations\(userId\)/, '首页必须调用正式推荐引擎')
|
||||
assert.doesNotMatch(card, /score|percent|匹配率|%/, '用户端不得显示数字匹配率')
|
||||
|
||||
console.log('Phase 06 match eligibility contracts passed')
|
||||