diff --git a/.gitignore b/.gitignore index 0840093..32bd47c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Local dev overrides (copy docker-compose.override.yml.example if needed) +docker-compose.override.yml + # App .env .env.local diff --git a/docker-compose.override.yml.example b/docker-compose.override.yml.example new file mode 100644 index 0000000..019fddb --- /dev/null +++ b/docker-compose.override.yml.example @@ -0,0 +1,14 @@ +# 本机差异配置:复制为 docker-compose.override.yml(已在 .gitignore) +# docker compose 会自动合并 base + override +# +# cp docker-compose.override.yml.example docker-compose.override.yml + +services: + neo4j: + environment: + # 若本机 Neo4j 密码与 .env 不一致,在此覆盖 + NEO4J_AUTH: neo4j/jinrong_dev_neo4j + + redis: + ports: + - "6379:6379" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..516cb24 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +# JinRong 本地依赖:Redis + Neo4j(MySQL 用本机 3306,不在此 compose 内) +services: + redis: + image: redis:7-alpine + container_name: jinrong-redis + ports: + - "6379:6379" + volumes: + - jinrong_redis_data:/data + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 10 + + neo4j: + image: neo4j:5 + container_name: jinrong-neo4j + ports: + - "7474:7474" + - "7687:7687" + environment: + NEO4J_AUTH: neo4j/jinrong_dev_neo4j + NEO4J_PLUGINS: '["apoc"]' + volumes: + - jinrong_neo4j_data:/data + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:7474 || exit 1"] + interval: 10s + timeout: 5s + retries: 12 + +volumes: + jinrong_redis_data: + jinrong_neo4j_data: diff --git a/scripts/dev/bootstrap.ps1 b/scripts/dev/bootstrap.ps1 new file mode 100644 index 0000000..9dd36f4 --- /dev/null +++ b/scripts/dev/bootstrap.ps1 @@ -0,0 +1,83 @@ +#Requires -Version 5.1 +param( + [string]$MysqlUser = "root", + [string]$MysqlHost = "127.0.0.1", + [string]$MysqlPassword = $env:MYSQL_PASSWORD +) + +$ErrorActionPreference = "Stop" +$Root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent +Set-Location $Root + +if (-not $MysqlPassword) { + if (Test-Path ".env") { + Get-Content ".env" | ForEach-Object { + if ($_ -match '^\s*MYSQL_PASSWORD=(.*)$') { $MysqlPassword = $Matches[1].Trim() } + } + } +} +if (-not $MysqlPassword) { + throw "MYSQL_PASSWORD missing in env or .env" +} + +function Invoke-SqlFile($path) { + Write-Host "SQL file: $path" + Get-Content -LiteralPath $path -Encoding UTF8 | & mysql -h $MysqlHost -u $MysqlUser "-p$MysqlPassword" +} + +Write-Host "[1/6] Docker Redis + Neo4j" +docker compose up -d +docker compose ps + +Write-Host "[2/6] Recreate jinrong_core" +& mysql -h $MysqlHost -u $MysqlUser "-p$MysqlPassword" -e "DROP DATABASE IF EXISTS jinrong_core;" + +$coreFiles = @( + "scripts/core/00-create-database.sql", + "scripts/core/01-ddl.sql", + "scripts/core/02-seed-base.sql", + "scripts/core/03-seed-customers.sql", + "scripts/core/04-seed-holdings.sql", + "scripts/core/05-seed-trades.sql", + "scripts/core/06-seed-nav.sql" +) +foreach ($f in $coreFiles) { Invoke-SqlFile (Join-Path $Root $f) } + +Write-Host "[3/6] Agent base tables" +python -c @" +from pathlib import Path +import subprocess +pwd = '$MysqlPassword' +root = Path('.') +for name in ['01-mysql-共用底座.sql', '02-mysql-agent专用.sql']: + f = root / 'docs' / '项目框架设计' / '表设计' / name + print('SQL', f) + sql = f.read_text(encoding='utf-8') + p = subprocess.run(['mysql','-h','$MysqlHost','-u','$MysqlUser',f'-p{pwd}'], input=sql.encode('utf-8')) + if p.returncode != 0: + raise SystemExit(p.returncode) +"@ + +Write-Host "[4/6] Sync advisor rel" +python scripts/sync/sync_advisor_rel.py + +Write-Host "[5/6] Wait Neo4j then sync graph" +$ready = $false +for ($i = 0; $i -lt 30; $i++) { + try { + $r = Invoke-WebRequest -Uri "http://127.0.0.1:7474" -UseBasicParsing -TimeoutSec 3 + if ($r.StatusCode -eq 200) { $ready = $true; break } + } catch { + Start-Sleep -Seconds 2 + } +} +if ($ready) { + python scripts/sync/sync_neo4j.py +} else { + Write-Host "WARN: Neo4j not ready; run: python scripts/sync/sync_neo4j.py" +} + +Write-Host "[6/6] Verify counts" +& mysql -h $MysqlHost -u $MysqlUser "-p$MysqlPassword" -e "SELECT COUNT(*) AS core_customers FROM jinrong_core.core_customer; SELECT COUNT(*) AS advisor_rel FROM jinrong_agent.customer_advisor_rel; SHOW TABLES FROM jinrong_agent LIKE 'agent_session';" + +Write-Host "Bootstrap finished."