前端配置迁至 config/local.js,完善支付、模板库与部署脚本
- 页面直接引用 local.js 设置 SOON_DEPLOY_CONFIG,移除 deploy-config - Docker sync-config 生成 local.js;更新 README 与 agent-core 说明 - 模板库自动扫描 .soon;新增后端部署/种子/排查脚本 - 完善支付配置、订阅弹窗与后台支付管理页 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# 部署脚本
|
||||
|
||||
## 权限(推荐:SSH 粘贴,勿 FTP 上传 .sh)
|
||||
|
||||
FTP 会把脚本改成 CRLF,报 `set: pipefail`。**在服务器 SSH 整段粘贴:**
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/designadmin.cardsoon.com
|
||||
U=www; G=www; ROOT="$PWD"
|
||||
mkdir -p "$ROOT/storage"/{users,logs,payment,cache/rate,cache/wechat_certs}
|
||||
chown -R "$U:$G" "$ROOT"
|
||||
find "$ROOT/src" "$ROOT/public" -type d -exec chmod 755 {} +
|
||||
find "$ROOT/src" "$ROOT/public" -type f -exec chmod 644 {} +
|
||||
chmod 755 "$ROOT/config"
|
||||
test -f "$ROOT/config/local.php" && chmod 640 "$ROOT/config/local.php"
|
||||
chmod 775 "$ROOT/storage/users" "$ROOT/storage/logs" "$ROOT/storage/cache/rate" "$ROOT/storage/cache/wechat_certs"
|
||||
chmod 700 "$ROOT/storage/payment"
|
||||
rm -f "$ROOT/storage/cache/rate/"*.json
|
||||
echo OK
|
||||
```
|
||||
|
||||
## 上线步骤
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/designadmin.cardsoon.com
|
||||
```
|
||||
|
||||
```bash
|
||||
cp config/local.php.example config/local.php
|
||||
vi config/local.php
|
||||
```
|
||||
|
||||
改 `db`、`jwt_secret`、`site`、`storage` 路径。
|
||||
|
||||
```bash
|
||||
mysql -u root -p soondesign < schema.sql
|
||||
```
|
||||
|
||||
再执行上面「权限」整段粘贴。
|
||||
|
||||
## 初始化管理员
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/designadmin.cardsoon.com
|
||||
php scripts/seed-admin.php admin@cardsoon.com cardsoon
|
||||
```
|
||||
|
||||
成功输出 `OK created admin` 或 `OK updated admin`。登录:`https://design.cardsoon.com/pages/admin/login.html`
|
||||
|
||||
模型目录:`.soon` 放后端站点(推荐,避免防跨站读不到):
|
||||
|
||||
```bash
|
||||
mkdir -p /www/wwwroot/designadmin.cardsoon.com/soonModels
|
||||
cp /www/wwwroot/design.cardsoon.com/soonModels/*.soon /www/wwwroot/designadmin.cardsoon.com/soonModels/
|
||||
chmod 755 /www/wwwroot/designadmin.cardsoon.com/soonModels
|
||||
chmod 644 /www/wwwroot/designadmin.cardsoon.com/soonModels/*.soon
|
||||
```
|
||||
|
||||
`local.php`:
|
||||
|
||||
```php
|
||||
'models_dir' => '/www/wwwroot/designadmin.cardsoon.com/soonModels',
|
||||
```
|
||||
|
||||
排查:
|
||||
|
||||
```bash
|
||||
php scripts/check-soon-models.php
|
||||
```
|
||||
|
||||
## 宝塔
|
||||
|
||||
- 网站运行目录:`public`
|
||||
- Nginx:`/api/v1/` → `index.php`,`/api/admin/` → `admin.php`
|
||||
|
||||
## 配置
|
||||
|
||||
后端只维护 `config/local.php`(从 `local.php.example` 复制)。
|
||||
|
||||
前端(`design.cardsoon.com`)只维护 `config/local.js`(从 `config/local.js.example` 复制);全量更新 frontend 时不要覆盖。
|
||||
|
||||
## 本地脚本
|
||||
|
||||
`setup-backend-perms.sh` 供 git 拉取使用;Windows/FTP 上传易坏,请用上面 SSH 粘贴块。
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
fwrite(STDERR, "CLI only\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require dirname(__DIR__) . '/src/bootstrap.php';
|
||||
|
||||
use Soon\Api\Core\Config;
|
||||
use Soon\Api\Services\SoonModelService;
|
||||
|
||||
$configured = rtrim((string)Config::get('storage.models_dir', ''), '/\\');
|
||||
$local = SOON_SERVER_ROOT . '/soonModels';
|
||||
|
||||
fwrite(STDOUT, "configured models_dir: {$configured}\n");
|
||||
fwrite(STDOUT, " is_dir=" . (@is_dir($configured) ? 'yes' : 'no') . ' readable=' . (@is_readable($configured) ? 'yes' : 'no') . "\n");
|
||||
|
||||
fwrite(STDOUT, "backend soonModels: {$local}\n");
|
||||
fwrite(STDOUT, " is_dir=" . (@is_dir($local) ? 'yes' : 'no') . ' readable=' . (@is_readable($local) ? 'yes' : 'no') . "\n");
|
||||
|
||||
$roots = SoonModelService::roots();
|
||||
fwrite(STDOUT, 'scan roots: ' . (count($roots) ? implode(', ', $roots) : '(none)') . "\n");
|
||||
|
||||
foreach ($roots as $root) {
|
||||
$entries = @scandir($root) ?: [];
|
||||
$soon = array_values(array_filter($entries, static fn(string $e): bool => str_ends_with(strtolower($e), '.soon')));
|
||||
fwrite(STDOUT, " {$root} => " . count($soon) . " .soon\n");
|
||||
foreach ($soon as $f) {
|
||||
fwrite(STDOUT, " - {$f}\n");
|
||||
}
|
||||
}
|
||||
|
||||
$items = SoonModelService::list();
|
||||
fwrite(STDOUT, 'API items: ' . count($items) . "\n");
|
||||
foreach ($items as $item) {
|
||||
fwrite(STDOUT, ' - ' . ($item['name'] ?? '') . ' (' . ($item['file'] ?? '') . ")\n");
|
||||
}
|
||||
|
||||
if ($configured !== '' && !@is_readable($configured)) {
|
||||
fwrite(STDOUT, "\nHint: PHP 读不到 configured 目录。把 .soon 复制到后端 {$local},或在宝塔后端站点防跨站放行:{$configured}\n");
|
||||
}
|
||||
|
||||
exit(count($items) > 0 ? 0 : 1);
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* 创建或重置管理员(CLI,读取 config/local.php)。
|
||||
* 用法: cd backend-web根目录 && php scripts/seed-admin.php [email] [password]
|
||||
*/
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
fwrite(STDERR, "CLI only\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require dirname(__DIR__) . '/src/bootstrap.php';
|
||||
|
||||
use Soon\Api\Core\Db;
|
||||
|
||||
$email = trim((string)($argv[1] ?? getenv('SOON_ADMIN_EMAIL') ?: 'admin@cardsoon.com'));
|
||||
$plain = (string)($argv[2] ?? getenv('SOON_ADMIN_PASS') ?: 'cardsoon');
|
||||
|
||||
if ($email === '' || $plain === '') {
|
||||
fwrite(STDERR, "usage: php scripts/seed-admin.php [email] [password]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$pdo = Db::pdo();
|
||||
$hash = password_hash($plain, PASSWORD_BCRYPT, ['cost' => 12]);
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
$stmt = $pdo->prepare('SELECT id FROM users WHERE email = :email LIMIT 1');
|
||||
$stmt->execute(['email' => $email]);
|
||||
$id = $stmt->fetchColumn();
|
||||
|
||||
if ($id) {
|
||||
$pdo->prepare(
|
||||
'UPDATE users SET password_hash = :h, role = :role, admin_level = :level, status = :status WHERE id = :id'
|
||||
)->execute([
|
||||
'h' => $hash,
|
||||
'role' => 'admin',
|
||||
'level' => 'full',
|
||||
'status' => 'active',
|
||||
'id' => (int)$id,
|
||||
]);
|
||||
fwrite(STDOUT, "OK updated admin #{$id} {$email}\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$pdo->prepare(
|
||||
'INSERT INTO users (email, password_hash, role, admin_level, status, created_at) '
|
||||
. 'VALUES (:email, :h, :role, :level, :status, :created_at)'
|
||||
)->execute([
|
||||
'email' => $email,
|
||||
'h' => $hash,
|
||||
'role' => 'admin',
|
||||
'level' => 'full',
|
||||
'status' => 'active',
|
||||
'created_at' => $now,
|
||||
]);
|
||||
|
||||
fwrite(STDOUT, "OK created admin {$email}\n");
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# cd 到 backend-web 根目录后: bash scripts/setup-backend-perms.sh [soonModels路径]
|
||||
set -eu
|
||||
|
||||
ROOT="$(cd "${1:-.}" && pwd)"
|
||||
MODELS="${2:-}"
|
||||
U="${WEB_USER:-www}"
|
||||
G="${WEB_GROUP:-www}"
|
||||
|
||||
[[ -d "$ROOT/public" && -d "$ROOT/src" ]] || { echo "错误: 请先 cd 到 backend-web"; exit 1; }
|
||||
id "$U" &>/dev/null || { echo "错误: 用户 $U 不存在"; exit 1; }
|
||||
|
||||
mkdir -p "$ROOT/storage"/{users,logs,payment,cache/rate,cache/wechat_certs}
|
||||
chown -R "$U:$G" "$ROOT"
|
||||
find "$ROOT/src" "$ROOT/public" -type d -exec chmod 755 {} +
|
||||
find "$ROOT/src" "$ROOT/public" -type f -exec chmod 644 {} +
|
||||
chmod 755 "$ROOT/config"
|
||||
[[ -f "$ROOT/config/local.php" ]] && chmod 640 "$ROOT/config/local.php"
|
||||
chmod 775 "$ROOT/storage/users" "$ROOT/storage/logs" "$ROOT/storage/cache/rate" "$ROOT/storage/cache/wechat_certs"
|
||||
chmod 700 "$ROOT/storage/payment"
|
||||
rm -f "$ROOT/storage/cache/rate/"*.json 2>/dev/null || true
|
||||
|
||||
if [[ -n "$MODELS" ]]; then
|
||||
mkdir -p "$MODELS"
|
||||
chown -R "$U:$G" "$MODELS"
|
||||
chmod 755 "$MODELS"
|
||||
fi
|
||||
|
||||
for d in "$ROOT/storage/users" "$ROOT/storage/logs" "$ROOT/storage/payment"; do
|
||||
sudo -u "$U" test -w "$d" || { echo "FAIL: $d"; exit 1; }
|
||||
done
|
||||
|
||||
echo OK
|
||||
Reference in New Issue
Block a user