Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,6 @@ PAY_MYSQL_PASSWORD=app-pay
# registered executor_url query string, no app-task changes needed)
PAY_EXECUTOR_TOKEN=generate-your-own-token_urlsafe-24

# app-pay-admin console master API token (optional; scripts may call /api/*
# with admin equivalence)
# PAYADMIN__WEBUI__TOKEN=

# ============================================================
# SDK-read variables (exception: these SDKs read env vars only, never YAML)
# ============================================================
Expand All @@ -269,9 +265,7 @@ LANGSMITH_ENDPOINT=https://api.smith.langchain.com
# PAY_MYSQL_PORT=3307 # host-mapped port (local IDE/client debugging only)
# APP_PAY_PORT=8002
# APP_PAY_TEST_PORT=18002
# app-pay-admin
# APP_PAY_ADMIN_PORT=8003
# app-admin(分享审核后台)
# app-admin(统一管理后台:分享审核 + 支付运营 + 沙箱 + 账户 + 审计)
# APP_ADMIN_PORT=8016
# APP_ADMIN_WEB_PORT=3001
# APPADMIN__SECURITY__IP_ALLOWLIST=192.0.2.10/32,10.20.0.0/16
Expand Down Expand Up @@ -331,27 +325,23 @@ LANGSMITH_ENDPOINT=https://api.smith.langchain.com

# app-pay P1 key separation (manually synced with apisix.yaml consumers):
# PAY_OPS_KEY - dedicated to fund-write operations (/internal/pay/grant,
# order refunds); never injected into business containers
# order refunds); injected only into the admin console
# (app-admin-api refund review), never into business containers
# PAY_READONLY_KEY - membership query read-only (/internal/pay/membership/*)
# Generate the same way as APISIX_CONSUMER_KEY (token_urlsafe(36))
# PAY_READONLY_KEY=
# PAY_OPS_KEY=

# pay-admin refund review workbench (P0): calls app-pay internal endpoints via
# the APISIX pay-ops consumer.
# ops_key = value of PAY_OPS_KEY (copy it over; empty = review feature hidden
# in the console).
# PAYADMIN__APP_PAY__OPS_KEY=
# PAYADMIN__APP_PAY__BASE_URL=http://apisix:9080

# ============================================================
# app-admin - share-moderation admin console (standalone Go service)
# app-admin - unified admin console (Go API; share moderation + payment ops
# + sandbox proxy + console accounts + audit)
# ------------------------------------------------------------
# Prefix APPADMIN__; reads the repo-root .env (godotenv); non-sensitive
# config lives in the service's embedded default.yaml (app-go/app-admin).
# Direct-connects the shared bilirag MySQL (same RDBMS__URL as the other
# app-go services - no extra connection string needed); the only write onto
# shared tables is the four moderation columns of cloud_shares.
# app-go services - no extra connection string needed); writes onto shared
# tables are the four moderation columns of cloud_shares plus the controlled
# membership grant in app_pay.
# ============================================================

# Seeded console admin account (insert-once on first boot; only the missing
Expand All @@ -363,3 +353,28 @@ LANGSMITH_ENDPOINT=https://api.smith.langchain.com

# RDBMS__URL: reused as-is (see "Shared secrets" near the top of this file);
# docker-compose maps it into APPADMIN__RDBMS__URL automatically.

# Login security (optional; defaults live in app-go/app-admin/default.yaml:
# device_binding=strict, ip_binding=subnet, 10 fails/min/IP + 10 fails/15min/account).
# The SPA sends a per-browser X-Device-Id header; scripts must do the same after
# logging in, otherwise device-bound sessions are rejected.
# APPADMIN__SESSION__DEVICE_BINDING=strict # strict | id | off
# APPADMIN__SESSION__IP_BINDING=subnet # exact | subnet | off
# APPADMIN__SECURITY__TRUSTED_PROXIES=172.16.0.0/12 # proxy CIDRs allowed to set X-Forwarded-*
# APPADMIN__SECURITY__LOGIN__MAX_FAILS_PER_IP=10
# APPADMIN__SECURITY__LOGIN__ACCOUNT_WINDOW_SECONDS=900

# Payment ops (merged from the retired app-pay-admin, 2026-11-03).
# Second GORM connection to the app_pay database; the pay_* schema stays owned
# by app-pay (Flyway) and is never migrated here. Empty URL = payment pages
# return 503 while share moderation / accounts / sandbox keep working.
# docker-compose already derives this from PAY_MYSQL_*; override only for an
# external app-pay database.
# APPADMIN__PAY_RDBMS__URL=mysql+aiomysql://app_pay:app-pay@app-pay-mysql:3306/app_pay
# Refund review calls app-pay internal endpoints through the APISIX pay-ops
# consumer. Key = PAY_OPS_KEY (copy it over; empty = the refund-review group is
# hidden with 404, everything else keeps working).
# APPADMIN__PAY__OPS__BASE_URL=http://apisix:9080
# APPADMIN__PAY__OPS__KEY=
# Fund audit JSONL (grants / refund confirmations, hash chain, 365 days).
# APPADMIN__PAY__AUDIT_FILE=/app/logs/pay-audit.jsonl
38 changes: 0 additions & 38 deletions .github/workflows/ci-pay-admin.yml

This file was deleted.

4 changes: 0 additions & 4 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,6 @@ jobs:
dockerfile: scripts/minio.Dockerfile
image: atoncooper/mind-base-minio
name: minio
- context: ./app-pay-admin
dockerfile: app-pay-admin/Dockerfile
image: atoncooper/mind-base-app-pay-admin
name: app-pay-admin
- context: ./app-go/app-admin
dockerfile: app-go/app-admin/Dockerfile
image: atoncooper/mind-base-app-admin
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

## [Unreleased] — 2026-11-03

### Changed

- **支付后台并入统一管理后台**:独立服务 `app-pay-admin`(Go + SSR WebUI,:8003,profile `pay-admin`)退役,支付运营能力(订单 / 会员 / 权益事件 / 回调流水 / SKU 查询、会员补偿开通、退款复核)并入 `app-admin`(`app-go/app-admin` API + `frontend-admin` SPA)。统一账户 `admin_user` / `admin_session` / `admin_audit`、统一角色 admin/viewer、统一入口 :3001(API :8016,均仅回环)。app-admin 新增第二 GORM 连接直连 `app_pay`(只读 + 会员补偿开通,唯一资金写);退款复核经 APISIX pay-ops consumer 调 app-pay internal 端点执行。配置迁移 `PAYADMIN__*` → `APPADMIN__PAY_*` / `APPADMIN__PAY__*`;资金审计 JSONL 统一为 `logs/pay-audit.jsonl`(哈希链,365 天)。旧 `payadmin_user` 账户不迁移(运维在「账户」页重建)。
- **部署/CI 同步退役**:compose 删除 `app-pay-admin` 服务与 `app_pay_admin_logs` 卷、移除 `--profile pay-admin`;删除 `deploy/docker/95-app-pay-admin.yml`、`deploy/k8s/30-apps/app-pay-admin.yaml`、`.github/workflows/ci-pay-admin.yml` 与 docker-build 矩阵条目;`deploy/docker/96-app-admin.yml`、k8s `app-admin`、swarm stack 的 app-admin 注入支付库 / ops key / 资金审计路径。
- **文档**:`docs/app-admin.md` 重写为统一后台(分享审核 + 支付运营 + 沙箱 + 统一账户/审计 + 配置/API/启动/迁移说明/红线);删除 `docs/app-pay-admin.md`;同步更新文档索引、架构、配置、部署、功能、API、FAQ 等引用。
- **管理后台登录安全加固**:所有管理端请求携带 `X-Device-Id`,登录会话绑定设备指纹(SHA-256,strict/id/off 可配);会话 IP 绑定(exact/subnet,IPv4 /24、IPv6 /64);可信代理白名单解析真实客户端 IP;IP 级 + 账户级双限流,登录失败/新设备/新 IP/会话设备或 IP 不匹配全部写入审计;CORS 仅接受同源/精确 Origin(拒绝 `*`/`null`,放行 `X-Device-Id`),并增加 CORP/COOP 安全头。

### Documentation

- **根 README 重写为项目介绍**:从「功能清单 + 目录索引 + 接口表」改为定位、核心能力、架构一览、快速开始与文档导航;结构、API、FAQ 分别迁入独立文档,避免与代码漂移。
Expand Down
23 changes: 13 additions & 10 deletions app-go/app-admin/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
# ====== app-admin: share-moderation admin console (Go) ======
# ====== app-admin: unified admin console (Go; share moderation + payment ops) ======
# Multi-stage build: compile static binary, ship on distroless.
# FROM 按 digest 固定:BuildKit 每次都会联网解析 tag(GFW 下 auth.docker.io 超时
# 直接失败),digest 引用命中本地镜像即可离线构建(同 app-pay-admin 的既有做法)。
# 直接失败),digest 引用命中本地镜像即可离线构建(同其它 Go 服务的既有做法)。
# 升级基础镜像时:docker pull 后用 docker images --digests 取新 digest 替换。
FROM golang:1.25-alpine@sha256:1ae0735f00daffa3aaf1363a5184c0d2dc55c78e3db4ec70241cdac97bf84b59 AS builder

WORKDIR /src

# Use China mirror for Go modules (goproxy.cn) with direct fallback.
# Module proxy is a build argument so restricted networks can override it:
# docker compose build --build-arg GOPROXY=https://mirrors.aliyun.com/goproxy/,direct app-admin-api
# GOSUMDB off: sum.golang.org is often unreachable behind GFW.
ENV GOPROXY=https://goproxy.cn,direct
ARG GOPROXY=https://goproxy.cn,direct
ENV GOPROXY=${GOPROXY}
ENV GOSUMDB=off

# Cache deps first
COPY go.mod go.sum* ./
RUN go mod download || true

# Copy source
# Copy source first: go build fetches only the modules imported by the
# production binary (test-only dependencies are not downloaded), which keeps
# the network footprint small on restricted connections. BuildKit cache mounts
# keep modules / compiled objects across retries when a fetch times out.
COPY . .

# Static build (CGO disabled for distroless)
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/app-admin . \
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/app-admin . \
&& mkdir -p /out/empty-logs

# ---- runtime image ----
Expand Down
Loading
Loading