Compare commits
215 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
017c33d8f4 | ||
|
|
76d3d2884f | ||
|
|
64940dfc29 | ||
|
|
53c7fc0154 | ||
|
|
f613ff9c38 | ||
|
|
ad7c76e6e6 | ||
|
|
081bedd637 | ||
|
|
97e7a4a3bb | ||
|
|
239e30472b | ||
|
|
cf1ce8a4db | ||
|
|
a0e6da97b1 | ||
|
|
ddb2a7b627 | ||
|
|
107e9879a6 | ||
|
|
0c6ed2a0c4 | ||
|
|
318f407222 | ||
|
|
5f1b59be70 | ||
|
|
c622d0b1d2 | ||
|
|
65a7555e18 | ||
|
|
d054b35116 | ||
|
|
22e95e5bcb | ||
|
|
37c5788263 | ||
|
|
b8cd175ecc | ||
|
|
c94257e06c | ||
|
|
68102491e2 | ||
|
|
9c6cc4ade5 | ||
|
|
9d3ae1e169 | ||
|
|
03df4c0c2b | ||
|
|
e774ef0794 | ||
|
|
651101c253 | ||
|
|
fe81be2874 | ||
|
|
3d36f8dd30 | ||
| e83e511406 | |||
| 1f0734e7e7 | |||
|
|
1ec1cbf9cc | ||
|
|
4a08ff360f | ||
|
|
d6d891c809 | ||
| 1c643cc022 | |||
| d5ddfd20bd | |||
|
|
bb693ce463 | ||
| f0f6b3ffdb | |||
|
|
b84d0079a6 | ||
|
|
a6fa674ca5 | ||
| 701d790f97 | |||
|
|
f10914bbe7 | ||
|
|
47d132dfd7 | ||
|
|
9cf1c167e8 | ||
|
|
6dfc9454fa | ||
|
|
2eb72e4aea | ||
|
|
69802dace7 | ||
|
|
fa64d666b8 | ||
|
|
5fae20edb3 | ||
|
|
484734352d | ||
| c894924a57 | |||
|
|
5c84390b90 | ||
|
|
343a93864f | ||
|
|
d8d95a14d3 | ||
|
|
41760a0227 | ||
|
|
048665c8fb | ||
|
|
f2b08dba84 | ||
|
|
34f03725c3 | ||
| 8fa9cd34bf | |||
| efe6b988f3 | |||
|
|
52fb1ba23e | ||
|
|
e8dd9d9fe4 | ||
|
|
4031e47cb4 | ||
|
|
ed5a628fa9 | ||
|
|
be0424652c | ||
|
|
4acd8ead70 | ||
|
|
08646c0760 | ||
|
|
986985a63d | ||
|
|
9a822a5874 | ||
|
|
b7dafdd508 | ||
|
|
bf071a2679 | ||
| c720083c2f | |||
|
|
6c0129cab2 | ||
| d8c73a0768 | |||
|
|
75c58a181b | ||
|
|
634614340a | ||
|
|
76131058e0 | ||
|
|
2810be58af | ||
|
|
8a5d6af1d7 | ||
|
|
8c9c83c845 | ||
|
|
1708a233e9 | ||
|
|
d1e0e200c4 | ||
|
|
c36e65de49 | ||
|
|
e09830eeac | ||
|
|
cdcb9c1455 | ||
|
|
122d1186ad | ||
|
|
b5bec9722d | ||
|
|
34231e29ed | ||
|
|
5a90b8e95f | ||
|
|
dde37b6910 | ||
|
|
04fabe7ee3 | ||
|
|
896a1fb711 | ||
|
|
3e8cc23d30 | ||
| 9190e60d13 | |||
|
|
b66caaed3d | ||
|
|
58fbf7e8bd | ||
|
|
a8f7b00efa | ||
|
|
61421dedd0 | ||
| 6c270b45d0 | |||
|
|
fea1ab6640 | ||
| 3dd225c619 | |||
|
|
f7041a1410 | ||
|
|
7e0eb91782 | ||
|
|
feddbc1b4d | ||
|
|
7cb6f2111a | ||
|
|
b2ac63e2b0 | ||
|
|
2831f6028b | ||
|
|
3f4f7d9c92 | ||
|
|
9569df6a27 | ||
|
|
68bf1e2c1e | ||
|
|
55d96d2ecb | ||
|
|
f60e5da99e | ||
|
|
7c0d87b8e0 | ||
|
|
9e452ca464 | ||
|
|
00023b808b | ||
|
|
be30303bc8 | ||
|
|
3aee5aa0bb | ||
|
|
f8c8c36517 | ||
|
|
c2c72f909a | ||
| 0c06383405 | |||
|
|
9d2fcd635c | ||
|
|
70004b0d0f | ||
|
|
3af115cf5b | ||
|
|
d6d062daa9 | ||
|
|
0967ac6d9b | ||
|
|
c15c57204a | ||
|
|
c0b003f108 | ||
|
|
26689d1326 | ||
|
|
79d9cc9d1f | ||
|
|
1769c26093 | ||
| 4311c41bbd | |||
|
|
9f0f56f509 | ||
|
|
4329953274 | ||
|
|
e62df8322c | ||
|
|
5d9de8ed1f | ||
|
|
c3c9436861 | ||
|
|
0c4de4dfcd | ||
|
|
fb9ded514a | ||
|
|
0f4a1a4fbf | ||
|
|
ce53e1cc3b | ||
| 6ed69a0f73 | |||
|
|
d101676c13 | ||
|
|
71b36a628d | ||
|
|
8e207a0e83 | ||
|
|
a41b45e1f9 | ||
|
|
3c1f5ec27d | ||
| bcdd9144af | |||
|
|
00cf5507c2 | ||
|
|
eaa383bb16 | ||
|
|
95290423b8 | ||
|
|
43fd3ed96d | ||
|
|
a55bb7cecd | ||
|
|
2984884fe6 | ||
| 3a1e32f071 | |||
| 7716ce4001 | |||
|
|
6c56ea1ba3 | ||
|
|
0fab89e0bd | ||
|
|
ef9c35ce68 | ||
|
|
9e39cbc5a5 | ||
| ce10082df4 | |||
|
|
f932054f0f | ||
| 889c6afae6 | |||
|
|
c08f4063b0 | ||
|
|
bfd9a9ca63 | ||
|
|
2cb3f4ee88 | ||
| 01277dce9c | |||
| cb0ae08155 | |||
| ea7a45845b | |||
|
|
f6b78cbbc7 | ||
|
|
4a87f17564 | ||
|
|
15e98eb29e | ||
|
|
022478a11b | ||
|
|
7d88275e44 | ||
|
|
10e747a6d6 | ||
|
|
17206d02f8 | ||
|
|
3bdcc0b147 | ||
|
|
4d0534dd47 | ||
|
|
b3d982f8a7 | ||
| f7a9c23b87 | |||
|
|
33862d353b | ||
|
|
87d573c528 | ||
|
|
f83e43ec50 | ||
|
|
346ffe7839 | ||
|
|
593adb0452 | ||
|
|
2ebecc8b43 | ||
|
|
88825f62c3 | ||
|
|
161350c608 | ||
|
|
01181d4385 | ||
|
|
9a915ae080 | ||
|
|
d65ea24956 | ||
|
|
2d2c972e29 | ||
|
|
4ce4147a8a | ||
| 5419021a56 | |||
|
|
53ca618292 | ||
|
|
6fa8bd6814 | ||
| 9da24e7b6b | |||
|
|
86cb79574d | ||
| 3d24d0af1d | |||
|
|
57c40bed97 | ||
|
|
b2cda61dd9 | ||
|
|
c0bc2a04c9 | ||
|
|
90b8a85bb4 | ||
|
|
a6a42018a3 | ||
|
|
4fbe296ca0 | ||
|
|
82975added | ||
| a31f01db5c | |||
|
|
b7c3d143b0 | ||
| e917bce530 | |||
| f784561801 | |||
|
|
713ed3401e | ||
|
|
65f29367bc | ||
|
|
c193ac9302 | ||
|
|
5e126e1294 |
15
.dockerignore
Normal file
15
.dockerignore
Normal file
@ -0,0 +1,15 @@
|
||||
.git
|
||||
.github
|
||||
.next
|
||||
.contentlayer
|
||||
node_modules
|
||||
coverage
|
||||
dist
|
||||
build
|
||||
test-results
|
||||
*.log
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
deploy/single-node/.env.runtime
|
||||
knowledge/.git
|
||||
58
.env.example
58
.env.example
@ -1,6 +1,45 @@
|
||||
# Moltbot Service URL
|
||||
# Defaults to https://moltbot.svc.plus if not set
|
||||
MOLTBOT_SERVICE_URL=https://moltbot.svc.plus
|
||||
# Frontend site base URLs
|
||||
APP_BASE_URL=
|
||||
NEXT_PUBLIC_APP_BASE_URL=
|
||||
NEXT_PUBLIC_SITE_URL=
|
||||
NEXT_PUBLIC_LOGIN_URL=
|
||||
NEXT_PUBLIC_DOCS_BASE_URL=
|
||||
DOCS_SERVICE_URL=https://docs.svc.plus
|
||||
DOCS_SERVICE_INTERNAL_URL=
|
||||
SESSION_COOKIE_SECURE=true
|
||||
NEXT_PUBLIC_SESSION_COOKIE_SECURE=true
|
||||
RUNTIME_HOSTNAME=
|
||||
NEXT_RUNTIME_HOSTNAME=
|
||||
DEPLOYMENT_HOSTNAME=
|
||||
RUNTIME_ENV=prod
|
||||
REGION=cn
|
||||
NEXT_PUBLIC_RUNTIME_ENVIRONMENT=prod
|
||||
NEXT_PUBLIC_RUNTIME_REGION=cn
|
||||
|
||||
# Upstream service endpoints
|
||||
# Use root service origins only. Do not point ACCOUNT_SERVICE_URL at console.svc.plus
|
||||
# and do not include /api/auth or any other path suffix here.
|
||||
ACCOUNT_SERVICE_URL=https://accounts.svc.plus
|
||||
NEXT_PUBLIC_ACCOUNT_SERVICE_URL=https://accounts.svc.plus
|
||||
SERVER_SERVICE_URL=https://api.svc.plus
|
||||
NEXT_PUBLIC_SERVER_SERVICE_URL=https://api.svc.plus
|
||||
SERVER_SERVICE_INTERNAL_URL=
|
||||
|
||||
# XWorkmate bridge runtime
|
||||
# Read server-side by /api/xworkmate/bridge. Do not expose the token as NEXT_PUBLIC_*.
|
||||
BRIDGE_SERVER_URL=https://xworkmate-bridge.svc.plus
|
||||
BRIDGE_AUTH_TOKEN=
|
||||
|
||||
# OpenClaw assistant integrations
|
||||
# Use environment variables to prefill the assistant and integrations page.
|
||||
# Values are read server-side and are not hardcoded into the UI.
|
||||
OPENCLAW_GATEWAY_REMOTE_URL=
|
||||
OPENCLAW_GATEWAY_TOKEN=
|
||||
VAULT_SERVER_URL=
|
||||
VAULT_NAMESPACE=
|
||||
VAULT_TOKEN=
|
||||
APISIX_AI_GATEWAY_URL=
|
||||
AI_GATEWAY_ACCESS_TOKEN=
|
||||
|
||||
# Giscus Configuration (GitHub Discussions Integration)
|
||||
# See https://giscus.app to generate these values
|
||||
@ -13,10 +52,23 @@ NEXT_PUBLIC_GISCUS_CATEGORY_ID=DIC_kwDOQoiZ_s4Clj_q
|
||||
INTERNAL_SERVICE_TOKEN=
|
||||
|
||||
# Cloudflare Web Analytics GraphQL credentials
|
||||
CLOUDFLARE_DNS_API_TOKEN=
|
||||
CLOUDFLARE_DNS_ZONE_TAG=
|
||||
CLOUDFLARE_API_TOKEN=
|
||||
CLOUDFLARE_ACCOUNT_ID=
|
||||
CLOUDFLARE_WEB_ANALYTICS_SITE_TAG=
|
||||
CLOUDFLARE_ZONE_TAG=
|
||||
|
||||
# Root email whitelist for privileged user-creation actions (comma-separated)
|
||||
# Default: admin@svc.plus
|
||||
ROOT_EMAIL_WHITELIST=admin@svc.plus
|
||||
|
||||
# Stripe public price ids used by /prices, product pages, and /panel/subscription
|
||||
# These values are safe to expose to the browser. Use Stripe test-mode price ids for local/dev.
|
||||
NEXT_PUBLIC_PAYPAL_CLIENT_ID=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION=
|
||||
|
||||
37
.github/actions/auto-tag/action.yml
vendored
37
.github/actions/auto-tag/action.yml
vendored
@ -1,37 +0,0 @@
|
||||
name: "Cloud-Neutral Auto Tag"
|
||||
description: "Generate Docker tags for main, release, PR and dev branches"
|
||||
inputs:
|
||||
image:
|
||||
description: "Base image name (e.g. ghcr.io/.../image)"
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
tags:
|
||||
description: "Generated Docker tags"
|
||||
value: ${{ steps.meta.outputs.tags }}
|
||||
labels:
|
||||
description: "Generated Docker labels"
|
||||
value: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Generate metadata (auto tags)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ inputs.image }}
|
||||
|
||||
tags: |
|
||||
# main → latest
|
||||
type=raw,enable=${{ github.ref == 'refs/heads/main' }},value=latest
|
||||
|
||||
# release tag(v1.2.3)
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
# PR → pr-123
|
||||
type=raw,enable=${{ startsWith(github.ref, 'refs/pull/') }},value=pr-${{ github.event.pull_request.number }}
|
||||
|
||||
# dev/feature branches → branch name
|
||||
type=ref,event=branch
|
||||
90
.github/actions/build/action.yml
vendored
90
.github/actions/build/action.yml
vendored
@ -1,90 +0,0 @@
|
||||
name: Build
|
||||
description: Build artifacts for each service and platform with optional container publishing.
|
||||
inputs:
|
||||
service:
|
||||
description: Target service name
|
||||
required: true
|
||||
platform:
|
||||
description: Target platform (e.g., linux/amd64)
|
||||
required: true
|
||||
environment:
|
||||
description: Deployment environment (dev or prod)
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Prepare matrix context
|
||||
id: matrix
|
||||
uses: ../matrix-support
|
||||
with:
|
||||
service: ${{ inputs.service }}
|
||||
platform: ${{ inputs.platform }}
|
||||
environment: ${{ inputs.environment }}
|
||||
enable_docker: 'true'
|
||||
|
||||
- name: Cache build artifacts
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
build/${{ inputs.service }}
|
||||
dashboard/.next
|
||||
key: build-${{ inputs.service }}-${{ inputs.platform }}-${{ hashFiles('**/go.sum', 'dashboard/yarn.lock') }}-${{ inputs.environment }}
|
||||
restore-keys: |
|
||||
build-${{ inputs.service }}-${{ inputs.platform }}-
|
||||
build-${{ inputs.service }}-
|
||||
|
||||
- name: Prepare Go toolchain
|
||||
if: inputs.service != 'dashboard'
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
|
||||
- name: Build Go binaries
|
||||
if: inputs.service != 'dashboard'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
goos="${{ steps.matrix.outputs.goos }}"
|
||||
goarch="${{ steps.matrix.outputs.goarch }}"
|
||||
mkdir -p build/${{ inputs.service }}/"${goos}-${goarch}"
|
||||
declare -a targets
|
||||
if [[ "${{ inputs.service }}" == "rag-server" ]]; then
|
||||
targets=("rag-server/cmd/xcontrol-server" "rag-server/cmd/rag-server-cli")
|
||||
elif [[ "${{ inputs.service }}" == "account" ]]; then
|
||||
targets=("account/cmd/accountsvc")
|
||||
else
|
||||
targets=("./...")
|
||||
fi
|
||||
for target in "${targets[@]}"; do
|
||||
binary_name=$(basename "$target")
|
||||
GOOS="$goos" GOARCH="$goarch" go build -o build/${{ inputs.service }}/"${goos}-${goarch}"/"${binary_name}" "$target"
|
||||
done
|
||||
|
||||
- name: Upload Go artifacts
|
||||
if: inputs.service != 'dashboard'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.service }}-${{ inputs.platform }}-${{ inputs.environment }}
|
||||
path: build/${{ inputs.service }}/
|
||||
|
||||
- name: Install dashboard dependencies
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Build dashboard
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
env:
|
||||
NEXT_PUBLIC_ENV: ${{ inputs.environment }}
|
||||
run: yarn build
|
||||
|
||||
- name: Upload dashboard build output
|
||||
if: inputs.service == 'dashboard'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dashboard-${{ inputs.platform }}-${{ inputs.environment }}
|
||||
path: dashboard/.next
|
||||
53
.github/actions/code-quality/action.yml
vendored
53
.github/actions/code-quality/action.yml
vendored
@ -1,53 +0,0 @@
|
||||
name: Code Quality
|
||||
description: Run linting and basic quality checks per service/platform/environment matrix entry.
|
||||
inputs:
|
||||
service:
|
||||
description: Target service name
|
||||
required: true
|
||||
platform:
|
||||
description: Target platform (e.g., linux/amd64)
|
||||
required: true
|
||||
environment:
|
||||
description: Deployment environment (dev or prod)
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Prepare matrix context
|
||||
id: matrix
|
||||
uses: ./.github/actions/matrix-support
|
||||
with:
|
||||
service: ${{ inputs.service }}
|
||||
platform: ${{ inputs.platform }}
|
||||
environment: ${{ inputs.environment }}
|
||||
|
||||
- name: Install git-secrets
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git clone https://github.com/awslabs/git-secrets.git
|
||||
sudo make install -C git-secrets
|
||||
git secrets --install
|
||||
git secrets --scan
|
||||
|
||||
- name: Go vet
|
||||
if: inputs.service != 'dashboard'
|
||||
shell: bash
|
||||
run: go vet ./...
|
||||
|
||||
- name: Go unit tests (quality gate)
|
||||
if: inputs.service != 'dashboard'
|
||||
shell: bash
|
||||
run: go test ./...
|
||||
|
||||
- name: Install dashboard dependencies
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Dashboard lint
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
run: yarn lint
|
||||
48
.github/actions/deploy/action.yml
vendored
48
.github/actions/deploy/action.yml
vendored
@ -1,48 +0,0 @@
|
||||
name: Deploy
|
||||
description: Coordinate deployments per service/environment.
|
||||
inputs:
|
||||
service:
|
||||
description: Target service name
|
||||
required: true
|
||||
platform:
|
||||
description: Target platform (e.g., linux/amd64)
|
||||
required: true
|
||||
environment:
|
||||
description: Deployment environment (dev or prod)
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Prepare matrix context
|
||||
id: matrix
|
||||
uses: ./.github/actions/matrix-support
|
||||
with:
|
||||
service: ${{ inputs.service }}
|
||||
platform: ${{ inputs.platform }}
|
||||
environment: ${{ inputs.environment }}
|
||||
|
||||
- name: Prepare rollout context
|
||||
id: context
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "service=${{ inputs.service }}" >> "$GITHUB_OUTPUT"
|
||||
echo "environment=${{ inputs.environment }}" >> "$GITHUB_OUTPUT"
|
||||
echo "platform=${{ inputs.platform }}" >> "$GITHUB_OUTPUT"
|
||||
echo "release_channel=${{ steps.matrix.outputs.is_prod == 'true' && 'prod' || 'dev' }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Deploy placeholder
|
||||
shell: bash
|
||||
env:
|
||||
TARGET_ENV: ${{ steps.context.outputs.environment }}
|
||||
TARGET_SERVICE: ${{ steps.context.outputs.service }}
|
||||
TARGET_PLATFORM: ${{ steps.context.outputs.platform }}
|
||||
RELEASE_CHANNEL: ${{ steps.context.outputs.release_channel }}
|
||||
run: |
|
||||
echo "Deploying ${TARGET_SERVICE} (${TARGET_PLATFORM}) to ${TARGET_ENV} namespace via ${RELEASE_CHANNEL} rollout"
|
||||
echo "Hook in Helm/kubectl/ArgoCD rollouts here"
|
||||
|
||||
- name: Rollback plan
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Rollback can be re-run per matrix entry by dispatching with allow_deploy=true"
|
||||
106
.github/actions/matrix-support/action.yml
vendored
106
.github/actions/matrix-support/action.yml
vendored
@ -1,106 +0,0 @@
|
||||
name: Matrix Support
|
||||
description: Common setup for matrix-driven workflows with language and cache bootstrapping.
|
||||
inputs:
|
||||
service:
|
||||
description: Target service name
|
||||
required: true
|
||||
platform:
|
||||
description: Target platform (e.g., linux/amd64)
|
||||
required: true
|
||||
environment:
|
||||
description: Deployment environment (dev or prod)
|
||||
required: true
|
||||
enable_docker:
|
||||
description: Enable Docker buildx/QEMU setup
|
||||
required: false
|
||||
default: 'false'
|
||||
outputs:
|
||||
goos:
|
||||
description: Derived GOOS from the platform input
|
||||
value: ${{ steps.platforms.outputs.goos }}
|
||||
goarch:
|
||||
description: Derived GOARCH from the platform input
|
||||
value: ${{ steps.platforms.outputs.goarch }}
|
||||
is_prod:
|
||||
description: Whether the environment is prod or the ref is a tag
|
||||
value: ${{ steps.flags.outputs.is_prod }}
|
||||
target_platforms:
|
||||
description: Platform list for builds (single in dev, multi-arch in prod)
|
||||
value: ${{ steps.flags.outputs.target_platforms }}
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Derive platform matrix values
|
||||
id: platforms
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
platform="${{ inputs.platform }}"
|
||||
goos="${platform%%/*}"
|
||||
goarch="${platform##*/}"
|
||||
echo "goos=${goos}" >> "$GITHUB_OUTPUT"
|
||||
echo "goarch=${goarch}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Resolve environment flags
|
||||
id: flags
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "${{ inputs.environment }}" == "prod" || "${GITHUB_REF_TYPE:-}" == "tag" ]]; then
|
||||
echo "is_prod=true" >> "$GITHUB_OUTPUT"
|
||||
echo "target_platforms=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "is_prod=false" >> "$GITHUB_OUTPUT"
|
||||
echo "target_platforms=${{ inputs.platform }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Set up Go
|
||||
if: inputs.service != 'dashboard'
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
|
||||
- name: Cache Go build data
|
||||
if: inputs.service != 'dashboard'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: go-${{ inputs.service }}-${{ inputs.platform }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
go-${{ inputs.service }}-${{ inputs.platform }}-
|
||||
go-${{ inputs.service }}-
|
||||
|
||||
- name: Set up Node.js
|
||||
if: inputs.service == 'dashboard'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: yarn
|
||||
cache-dependency-path: dashboard/yarn.lock
|
||||
|
||||
- name: Cache dashboard artifacts
|
||||
if: inputs.service == 'dashboard'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
dashboard/.next/cache
|
||||
~/.cache/yarn
|
||||
key: dashboard-${{ inputs.platform }}-${{ hashFiles('dashboard/yarn.lock') }}
|
||||
restore-keys: |
|
||||
dashboard-${{ inputs.platform }}-
|
||||
dashboard-
|
||||
|
||||
- name: Enable Docker build tooling
|
||||
if: inputs.enable_docker == 'true'
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up buildx
|
||||
if: inputs.enable_docker == 'true'
|
||||
uses: docker/setup-buildx-action@v3
|
||||
76
.github/actions/security/action.yml
vendored
76
.github/actions/security/action.yml
vendored
@ -1,76 +0,0 @@
|
||||
name: Security
|
||||
description: Security scanning per service/platform/environment.
|
||||
inputs:
|
||||
service:
|
||||
description: Target service name
|
||||
required: true
|
||||
platform:
|
||||
description: Target platform (e.g., linux/amd64)
|
||||
required: true
|
||||
environment:
|
||||
description: Deployment environment (dev or prod)
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Prepare matrix context
|
||||
id: matrix
|
||||
uses: ./.github/actions/matrix-support
|
||||
with:
|
||||
service: ${{ inputs.service }}
|
||||
platform: ${{ inputs.platform }}
|
||||
environment: ${{ inputs.environment }}
|
||||
|
||||
- name: Run golangci-lint
|
||||
if: inputs.service != 'dashboard'
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: latest
|
||||
args: ./...
|
||||
|
||||
- name: Install gosec
|
||||
if: inputs.service != 'dashboard'
|
||||
shell: bash
|
||||
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
|
||||
- name: Run gosec
|
||||
if: inputs.service != 'dashboard'
|
||||
shell: bash
|
||||
run: gosec ./...
|
||||
|
||||
- name: Trivy filesystem scan
|
||||
if: inputs.service != 'dashboard'
|
||||
uses: aquasecurity/trivy-action@0.24.0
|
||||
with:
|
||||
scan-type: fs
|
||||
scan-ref: .
|
||||
severity: HIGH,CRITICAL
|
||||
ignore-unfixed: true
|
||||
format: table
|
||||
exit-code: "0"
|
||||
|
||||
- name: Install dashboard dependencies
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run ESLint
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
run: yarn lint
|
||||
|
||||
- name: Semgrep security rules
|
||||
if: inputs.service == 'dashboard'
|
||||
uses: returntocorp/semgrep-action@v1
|
||||
with:
|
||||
config: p/ci
|
||||
paths: dashboard
|
||||
|
||||
- name: npm audit (production)
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
run: npm audit --production
|
||||
continue-on-error: true
|
||||
52
.github/actions/test/action.yml
vendored
52
.github/actions/test/action.yml
vendored
@ -1,52 +0,0 @@
|
||||
name: Test
|
||||
description: Run service-specific tests.
|
||||
inputs:
|
||||
service:
|
||||
description: Target service name
|
||||
required: true
|
||||
platform:
|
||||
description: Target platform (e.g., linux/amd64)
|
||||
required: true
|
||||
environment:
|
||||
description: Deployment environment (dev or prod)
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Prepare matrix context
|
||||
id: matrix
|
||||
uses: ./.github/actions/matrix-support
|
||||
with:
|
||||
service: ${{ inputs.service }}
|
||||
platform: ${{ inputs.platform }}
|
||||
environment: ${{ inputs.environment }}
|
||||
|
||||
- name: Run Go integration tests
|
||||
if: inputs.service != 'dashboard'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
go test ./... -run Integration -count=1
|
||||
|
||||
- name: Install dashboard dependencies
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run dashboard unit tests
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
env:
|
||||
NODE_ENV: ${{ inputs.environment }}
|
||||
run: yarn test:unit
|
||||
|
||||
- name: Run dashboard e2e tests
|
||||
if: inputs.service == 'dashboard'
|
||||
working-directory: dashboard
|
||||
shell: bash
|
||||
env:
|
||||
PORT: 3100
|
||||
NODE_ENV: ${{ inputs.environment }}
|
||||
run: yarn test:e2e
|
||||
9
.github/scripts/cosign/sign.sh
vendored
9
.github/scripts/cosign/sign.sh
vendored
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
REG="ghcr.io/cloud-neutral-toolkit"
|
||||
|
||||
cosign sign --yes "$REG/node-builder@$NODE_BUILDER_DIGEST"
|
||||
cosign sign --yes "$REG/node-runtime@$NODE_RUNTIME_DIGEST"
|
||||
cosign sign --yes "$REG/openresty-geoip@$OPENRESTY_GEOIP_DIGEST"
|
||||
cosign sign --yes "$REG/postgres-runtime@$POSTGRES_RUNTIME_DIGEST"
|
||||
28
.github/scripts/metadata/gen.py
vendored
28
.github/scripts/metadata/gen.py
vendored
@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import json, sys
|
||||
|
||||
if len(sys.argv) < 4:
|
||||
print("Usage: gen.py <image-name> <digest> <tags>")
|
||||
sys.exit(1)
|
||||
|
||||
name = sys.argv[1]
|
||||
digest = sys.argv[2]
|
||||
raw_tags = sys.argv[3]
|
||||
tags = raw_tags.splitlines()
|
||||
|
||||
preferred = next((t for t in tags if t.endswith(":latest")), tags[0] if tags else "")
|
||||
|
||||
metadata = {
|
||||
"name": name,
|
||||
"digest": digest,
|
||||
"tags": tags,
|
||||
"preferred_tag": preferred,
|
||||
"image": f"ghcr.io/cloud-neutral-toolkit/{name}",
|
||||
"image_with_digest": f"ghcr.io/cloud-neutral-toolkit/{name}@{digest}",
|
||||
}
|
||||
|
||||
outfile = f"image-metadata-{name}.json"
|
||||
with open(outfile, "w", encoding="utf-8") as f:
|
||||
json.dump(metadata, f, indent=2)
|
||||
|
||||
print(f"[metadata] Wrote: {outfile}")
|
||||
7
.github/scripts/sbom/generate.sh
vendored
7
.github/scripts/sbom/generate.sh
vendored
@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
IMAGE="$1"
|
||||
OUT="$2"
|
||||
|
||||
anchore-cli sbom generate "$IMAGE" -o "$OUT"
|
||||
15
.github/scripts/utils/preferred-tag.sh
vendored
15
.github/scripts/utils/preferred-tag.sh
vendored
@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
tags="$1"
|
||||
preferred=""
|
||||
|
||||
while IFS= read -r line; do
|
||||
[[ "$line" == *":latest" ]] && preferred="$line" && break
|
||||
done <<< "$tags"
|
||||
|
||||
if [[ -z "$preferred" ]]; then
|
||||
preferred="$(echo "$tags" | head -n 1)"
|
||||
fi
|
||||
|
||||
echo "$preferred"
|
||||
296
.github/workflows/build-images.yml
vendored
296
.github/workflows/build-images.yml
vendored
@ -1,296 +0,0 @@
|
||||
name: Build Dashboard Images
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
push_images:
|
||||
description: "Push service images instead of local builds"
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
dockerhub_namespace:
|
||||
description: "Docker Hub namespace (user/org)"
|
||||
type: string
|
||||
|
||||
skip_security:
|
||||
description: "Skip security scans and signing"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
node_builder_image:
|
||||
type: string
|
||||
default: "node:22-bookworm"
|
||||
|
||||
node_runtime_image:
|
||||
type: string
|
||||
default: "node:22-slim"
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
push_images:
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
dockerhub_namespace:
|
||||
description: "Docker Hub namespace (user/org)"
|
||||
type: string
|
||||
default: "cloudneutral"
|
||||
|
||||
skip_security:
|
||||
description: "Skip security scans and signing"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
node_builder_image:
|
||||
type: string
|
||||
default: "node:22-bookworm"
|
||||
|
||||
node_runtime_image:
|
||||
type: string
|
||||
default: "node:22-slim"
|
||||
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
# ✅ 不硬编码:默认推到 ghcr.io/<当前仓库 owner>/...
|
||||
ORG: ${{ github.repository_owner }}
|
||||
|
||||
SKIP_SECURITY: ${{ inputs.skip_security || github.event.inputs.skip_security || 'false' }}
|
||||
|
||||
NODE_BUILDER_IMAGE: ${{ inputs.node_builder_image || github.event.inputs.node_builder_image || 'node:22-bookworm' }}
|
||||
NODE_RUNTIME_IMAGE: ${{ inputs.node_runtime_image || github.event.inputs.node_runtime_image || 'node:22-slim' }}
|
||||
|
||||
PUSH_IMAGES: ${{ github.event_name == 'push'
|
||||
|| (github.event_name == 'workflow_call' && inputs.push_images)
|
||||
|| (github.event_name == 'workflow_dispatch' && github.event.inputs.push_images == 'true') }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- { platform: linux/amd64, artifact: linux-amd64 }
|
||||
- { platform: linux/arm64, artifact: linux-arm64 }
|
||||
service:
|
||||
- { name: dashboard, workdir: ., dockerfile: Dockerfile }
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Generate Auto Tags
|
||||
id: meta
|
||||
uses: ./.github/actions/auto-tag
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Clone knowledge content
|
||||
run: git clone https://github.com/Cloud-Neutral-Workshop/knowledge.git knowledge
|
||||
|
||||
- name: Build Service Image (per-arch)
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ${{ matrix.service.workdir }}
|
||||
file: ${{ matrix.service.dockerfile }}
|
||||
platforms: ${{ matrix.arch.platform }}
|
||||
push: ${{ env.PUSH_IMAGES }}
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}:build-${{ github.sha }}-${{ matrix.arch.artifact }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
GO_RUNTIME_IMAGE=${{ env.GO_RUNTIME_IMAGE }}
|
||||
NODE_BUILDER_IMAGE=${{ env.NODE_BUILDER_IMAGE }}
|
||||
NODE_RUNTIME_IMAGE=${{ env.NODE_RUNTIME_IMAGE }}
|
||||
CONTENTLAYER_BUILD=true
|
||||
|
||||
- name: Record digest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "${{ steps.build.outputs.digest }}" > digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}.txt
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}
|
||||
path: digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}.txt
|
||||
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: ${{ (github.event_name == 'push' || inputs.push_images == true || github.event.inputs.push_images == 'true') && !((inputs.skip_security == true) || (github.event.inputs.skip_security == 'true')) }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- { platform: linux/amd64, artifact: linux-amd64 }
|
||||
- { platform: linux/arm64, artifact: linux-arm64 }
|
||||
service:
|
||||
- { name: dashboard }
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}
|
||||
|
||||
- name: Load image digest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "IMAGE_DIGEST=$(cat digest-${{ matrix.service.name }}-${{ matrix.arch.artifact }}.txt)" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set image ref
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "IMG=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}:build-${{ github.sha }}-${{ matrix.arch.artifact }}@${{ env.IMAGE_DIGEST }}" >> "$GITHUB_ENV"
|
||||
|
||||
- uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.IMG }}
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom-${{ matrix.service.name }}-${{ matrix.arch.artifact }}
|
||||
path: sbom.spdx.json
|
||||
|
||||
- uses: aquasecurity/trivy-action@0.28.0
|
||||
with:
|
||||
image-ref: ${{ env.IMG }}
|
||||
severity: HIGH,CRITICAL
|
||||
exit-code: '1'
|
||||
|
||||
- uses: sigstore/cosign-installer@v3
|
||||
with:
|
||||
cosign-release: 'v2.4.1'
|
||||
|
||||
- name: Cosign Sign Image
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: "true"
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cosign sign --yes "${{ env.IMG }}"
|
||||
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
- security
|
||||
if: ${{ needs.build.result == 'success' && (github.event_name == 'push' || inputs.push_images == true || github.event.inputs.push_images == 'true') && ((inputs.skip_security == true) || (github.event.inputs.skip_security == 'true') || (needs.security.result == 'success')) }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
registry:
|
||||
- ghcr.io
|
||||
- docker.io
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: digest-dashboard-linux-amd64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: digest-dashboard-linux-arm64
|
||||
|
||||
- name: Load digests
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "AMD_DIGEST=$(cat digest-dashboard-linux-amd64.txt)" >> "$GITHUB_ENV"
|
||||
echo "ARM_DIGEST=$(cat digest-dashboard-linux-arm64.txt)" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Generate Auto Tags
|
||||
id: meta
|
||||
uses: ./.github/actions/auto-tag
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/dashboard
|
||||
|
||||
- uses: docker/login-action@v3
|
||||
if: matrix.registry == 'ghcr.io'
|
||||
with:
|
||||
registry: ${{ matrix.registry }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create & Push Multi-Arch Manifests (GHCR)
|
||||
if: matrix.registry == 'ghcr.io'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
SRC_AMD="${{ env.REGISTRY }}/${{ env.ORG }}/dashboard:build-${{ github.sha }}-linux-amd64@${{ env.AMD_DIGEST }}"
|
||||
SRC_ARM="${{ env.REGISTRY }}/${{ env.ORG }}/dashboard:build-${{ github.sha }}-linux-arm64@${{ env.ARM_DIGEST }}"
|
||||
|
||||
FIRST_TAG=""
|
||||
echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n' | while read -r TAG; do
|
||||
[ -z "$TAG" ] && continue
|
||||
if [ -z "$FIRST_TAG" ]; then FIRST_TAG="$TAG"; fi
|
||||
docker buildx imagetools create -t "$TAG" "$SRC_AMD" "$SRC_ARM"
|
||||
done
|
||||
|
||||
TAG1="$(echo "${{ steps.meta.outputs.tags }}" | tr ',' '\n' | head -n 1)"
|
||||
DIGEST="$(docker buildx imagetools inspect "$TAG1" --format '{{.Digest}}')"
|
||||
echo "MANIFEST_DIGEST=$DIGEST" >> "$GITHUB_ENV"
|
||||
echo "FINAL_TAG=$TAG1" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Clone knowledge content
|
||||
if: matrix.registry == 'ghcr.io'
|
||||
run: git clone https://github.com/Cloud-Neutral-Workshop/knowledge.git knowledge
|
||||
|
||||
- name: Validate blog content mount
|
||||
if: matrix.registry == 'ghcr.io'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
IMAGE="${{ env.REGISTRY }}/${{ env.ORG }}/dashboard@${{ env.MANIFEST_DIGEST }}"
|
||||
docker pull "$IMAGE"
|
||||
docker run --rm \
|
||||
-v "${{ github.workspace }}/knowledge/content:/app/dashboard/src/content/blog:ro" \
|
||||
"$IMAGE" \
|
||||
sh -c 'test -d /app/dashboard/src/content/blog'
|
||||
|
||||
- name: Login to Docker Hub
|
||||
if: matrix.registry == 'docker.io'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Copy Multi-Arch Image to Docker Hub (skopeo)
|
||||
if: matrix.registry == 'docker.io'
|
||||
env:
|
||||
TARGET_NS: ${{ inputs.dockerhub_namespace || github.event.inputs.dockerhub_namespace || 'cloudneutral' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y skopeo
|
||||
|
||||
SRC="docker://ghcr.io/${{ env.ORG }}/dashboard@${{ env.MANIFEST_DIGEST }}"
|
||||
DST="docker://docker.io/${TARGET_NS}/dashboard:latest"
|
||||
|
||||
skopeo login ghcr.io -u "${{ github.actor }}" -p "${{ secrets.GITHUB_TOKEN }}"
|
||||
skopeo login docker.io -u "${{ secrets.DOCKERHUB_USERNAME }}" -p "${{ secrets.DOCKERHUB_TOKEN }}"
|
||||
|
||||
skopeo copy --all "$SRC" "$DST"
|
||||
49
.github/workflows/check-image.yaml
vendored
49
.github/workflows/check-image.yaml
vendored
@ -1,49 +0,0 @@
|
||||
name: Check XControl Image Ready
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
required: false
|
||||
default: latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Authenticate to GHCR
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "$GITHUB_TOKEN" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
|
||||
|
||||
- name: Check images exist and are pullable
|
||||
env:
|
||||
TAG: ${{ inputs.tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
IMAGES=(
|
||||
"ghcr.io/cloud-neutral-toolkit/openresty-geoip"
|
||||
"ghcr.io/cloud-neutral-toolkit/postgres-runtime"
|
||||
"ghcr.io/cloud-neutral-toolkit/account"
|
||||
"ghcr.io/cloud-neutral-toolkit/dashboard"
|
||||
"ghcr.io/cloud-neutral-toolkit/rag-server"
|
||||
"ghcr.io/cloud-neutral-toolkit/xcontrol-init"
|
||||
"docker.io/cloudneutral/openresty-geoip"
|
||||
"docker.io/cloudneutral/postgres-runtime"
|
||||
"docker.io/cloudneutral/account"
|
||||
"docker.io/cloudneutral/dashboard"
|
||||
"docker.io/cloudneutral/rag-server"
|
||||
"docker.io/cloudneutral/xcontrol-init"
|
||||
)
|
||||
|
||||
for IMAGE in "${IMAGES[@]}"; do
|
||||
echo "Checking ${IMAGE}:${TAG}"
|
||||
docker manifest inspect "${IMAGE}:${TAG}" > /dev/null
|
||||
docker pull "${IMAGE}:${TAG}" > /dev/null
|
||||
done
|
||||
240
.github/workflows/pipeline.yaml
vendored
Normal file
240
.github/workflows/pipeline.yaml
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
name: Console Service Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- ".github/workflows/pipeline.yaml"
|
||||
- "Dockerfile"
|
||||
- "deploy/single-node/**"
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
- "scripts/github-actions/build-and-push-frontend-image.sh"
|
||||
- "scripts/github-actions/compute-frontend-release-metadata.sh"
|
||||
- "scripts/github-actions/render-frontend-build-args.sh"
|
||||
- "scripts/github-actions/render-frontend-runtime-env.sh"
|
||||
- "scripts/github-actions/prepare-frontend-build-context.sh"
|
||||
- "scripts/github-actions/run-console-deploy-playbook.sh"
|
||||
- "scripts/github-actions/run-cloudflare-svc-plus-dns-playbook.sh"
|
||||
- "scripts/github-actions/verify-frontend-release-over-ssh.sh"
|
||||
- "scripts/github-actions/verify-frontend-release.sh"
|
||||
- "scripts/prebuild.sh"
|
||||
- "contentlayer.config.ts"
|
||||
- "next.config.js"
|
||||
- "next.config.mjs"
|
||||
- "src/**"
|
||||
- "public/**"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_host:
|
||||
description: Ansible host or alias
|
||||
required: false
|
||||
default: "jp-xhttp-contabo.svc.plus"
|
||||
type: string
|
||||
run_apply:
|
||||
description: Apply deployment
|
||||
required: true
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
concurrency:
|
||||
group: console-pipeline-${{ github.ref_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
CANONICAL_DOMAIN: www.svc.plus
|
||||
SERVED_DOMAINS: www.svc.plus,console.svc.plus
|
||||
APP_BASE_URL: https://www.svc.plus
|
||||
NEXT_PUBLIC_APP_BASE_URL: https://www.svc.plus
|
||||
NEXT_PUBLIC_SITE_URL: https://www.svc.plus
|
||||
RUNTIME_HOSTNAME: www.svc.plus
|
||||
NEXT_RUNTIME_HOSTNAME: www.svc.plus
|
||||
NEXT_PUBLIC_RUNTIME_ENVIRONMENT: prod
|
||||
NEXT_PUBLIC_RUNTIME_REGION: cn
|
||||
ACCOUNT_SERVICE_URL: https://accounts.svc.plus
|
||||
CLOUDFLARE_ZONE_TAG: bf3427f83a2c52c8285ab3d741a6ee27
|
||||
CLOUDFLARE_WEB_ANALYTICS_SITE_TAG: 0973e84ec8872c67c570f8072e92e21b
|
||||
CLOUDFLARE_ACCOUNT_ID: e71be5efb76a6c54f78f008da4404f00
|
||||
GHCR_REGISTRY: ghcr.io
|
||||
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }}
|
||||
GHCR_PASSWORD: ${{ secrets.GHCR_TOKEN }}
|
||||
INTERNAL_SERVICE_TOKEN: ${{ secrets.INTERNAL_SERVICE_TOKEN }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_DNS_API_TOKEN: ${{ secrets.CLOUDFLARE_DNS_API_TOKEN }}
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
name: Prep
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
target_host: ${{ steps.inputs.outputs.target_host }}
|
||||
run_apply: ${{ steps.inputs.outputs.run_apply }}
|
||||
image_tag: ${{ steps.metadata.outputs.image_tag }}
|
||||
image_ref: ${{ steps.metadata.outputs.image_ref }}
|
||||
image_latest_ref: ${{ steps.metadata.outputs.image_latest_ref }}
|
||||
ghcr_namespace: ${{ steps.metadata.outputs.ghcr_namespace }}
|
||||
push_latest: ${{ steps.push.outputs.push_latest }}
|
||||
steps:
|
||||
- name: Check Out Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Resolve Inputs
|
||||
id: inputs
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
INPUT_TARGET_HOST: ${{ inputs.target_host }}
|
||||
INPUT_RUN_APPLY: ${{ inputs.run_apply }}
|
||||
run: bash scripts/github-actions/resolve-workflow-inputs.sh
|
||||
|
||||
- name: Compute Image Metadata
|
||||
id: metadata
|
||||
run: |
|
||||
bash scripts/github-actions/compute-frontend-release-metadata.sh
|
||||
|
||||
- name: Resolve Push Latest
|
||||
id: push
|
||||
env:
|
||||
REF: ${{ github.ref }}
|
||||
run: bash scripts/github-actions/resolve-push-latest.sh
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
needs: prep
|
||||
outputs:
|
||||
image_ref: ${{ steps.publish.outputs.image_ref }}
|
||||
image_tag: ${{ steps.publish.outputs.image_tag }}
|
||||
steps:
|
||||
- name: Check Out Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Set Up Docker Buildx
|
||||
run: bash scripts/github-actions/setup-docker-buildx.sh
|
||||
|
||||
- name: Log In To GHCR
|
||||
env:
|
||||
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: bash scripts/github-actions/login-ghcr.sh
|
||||
|
||||
- name: Publish Frontend Image
|
||||
id: publish
|
||||
env:
|
||||
IMAGE_REF: ${{ needs.prep.outputs.image_ref }}
|
||||
IMAGE_TAG: ${{ needs.prep.outputs.image_tag }}
|
||||
IMAGE_LATEST_REF: ${{ needs.prep.outputs.image_latest_ref }}
|
||||
PUSH_LATEST: ${{ needs.prep.outputs.push_latest }}
|
||||
run: bash scripts/github-actions/publish-frontend-image.sh
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- prep
|
||||
- build
|
||||
env:
|
||||
TARGET_HOST: ${{ needs.prep.outputs.target_host }}
|
||||
RUN_APPLY: ${{ needs.prep.outputs.run_apply }}
|
||||
FRONTEND_IMAGE: ${{ needs.build.outputs.image_ref }}
|
||||
steps:
|
||||
- name: Check Out Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Check Out Playbooks Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
# Intentionally pinned: playbooks@main regressed deploy reliability on 2026-04-12.
|
||||
# Any future bump must pass a full Deploy + Validate run before becoming the default.
|
||||
repository: x-evor/playbooks
|
||||
ref: 80c545a95c3b16459f6494ed13d951faac57bfa8
|
||||
path: playbooks
|
||||
token: ${{ github.token }}
|
||||
|
||||
- name: Set Up Python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install Ansible
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install ansible
|
||||
|
||||
- name: Configure SSH For Deploy Host
|
||||
env:
|
||||
SINGLE_NODE_VPS_SSH_PRIVATE_KEY: ${{ secrets.SINGLE_NODE_VPS_SSH_PRIVATE_KEY }}
|
||||
TARGET_HOST: ${{ needs.prep.outputs.target_host }}
|
||||
run: bash scripts/github-actions/configure-ssh-for-deploy.sh
|
||||
|
||||
- name: Run Deploy Playbook
|
||||
working-directory: playbooks
|
||||
env:
|
||||
ANSIBLE_HOST_KEY_CHECKING: "False"
|
||||
run: bash ../scripts/github-actions/run-console-deploy-playbook.sh
|
||||
|
||||
validate:
|
||||
name: Validate
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- prep
|
||||
- build
|
||||
- deploy
|
||||
if: ${{ always() && needs.deploy.result == 'success' }}
|
||||
env:
|
||||
EXPECTED_FRONTEND_IMAGE: ${{ needs.build.outputs.image_ref }}
|
||||
TARGET_HOST: ${{ needs.prep.outputs.target_host }}
|
||||
SINGLE_NODE_VPS_SSH_PRIVATE_KEY: ${{ secrets.SINGLE_NODE_VPS_SSH_PRIVATE_KEY }}
|
||||
steps:
|
||||
- name: Check Out Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Configure SSH For Validate Host
|
||||
run: bash scripts/github-actions/configure-ssh-for-deploy.sh
|
||||
|
||||
- name: Verify Frontend Release On Host
|
||||
run: bash scripts/github-actions/verify-frontend-release-over-ssh.sh
|
||||
|
||||
update_dns:
|
||||
name: Update DNS
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- prep
|
||||
- build
|
||||
- deploy
|
||||
if: ${{ always() && needs.deploy.result == 'success' }}
|
||||
continue-on-error: true
|
||||
env:
|
||||
TARGET_HOST: ${{ needs.prep.outputs.target_host }}
|
||||
RUN_APPLY: ${{ needs.prep.outputs.run_apply }}
|
||||
FRONTEND_IMAGE: ${{ needs.build.outputs.image_ref }}
|
||||
steps:
|
||||
- name: Check Out Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Check Out Playbooks Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: x-evor/playbooks
|
||||
ref: 80c545a95c3b16459f6494ed13d951faac57bfa8
|
||||
path: playbooks
|
||||
token: ${{ github.token }}
|
||||
|
||||
- name: Set Up Python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install Ansible
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install ansible
|
||||
|
||||
- name: Update Cloudflare svc.plus DNS
|
||||
working-directory: playbooks
|
||||
env:
|
||||
ANSIBLE_HOST_KEY_CHECKING: "False"
|
||||
run: bash ../scripts/github-actions/run-cloudflare-svc-plus-dns-playbook.sh
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
.env
|
||||
models/
|
||||
*.tsbuildinfo
|
||||
knowledge/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
@ -18,6 +19,7 @@ public/_build/
|
||||
public/dl-index/
|
||||
.contentlayer/
|
||||
.dev-logs/
|
||||
.console-state/
|
||||
|
||||
# Contentlayer cache
|
||||
ui/docs/.contentlayer/
|
||||
@ -54,6 +56,7 @@ coverage/
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
deploy/single-node/.env.runtime
|
||||
|
||||
# Build artifacts
|
||||
build/
|
||||
|
||||
@ -4,7 +4,7 @@ enableGlobalCache: false
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
npmRegistryServer: "https://registry.npmmirror.com"
|
||||
npmRegistryServer: "https://registry.npmjs.org"
|
||||
|
||||
packageExtensions:
|
||||
"next-contentlayer@*":
|
||||
|
||||
41
AGENTS.md
41
AGENTS.md
@ -51,7 +51,20 @@ yarn test:e2e path/to/spec.test.ts
|
||||
|
||||
---
|
||||
|
||||
## 2. Repository Mental Model (Read This First)
|
||||
## 2. Release Traceability Default Rule
|
||||
|
||||
For any change touching CI/CD, image tags, deploy contracts, `/api/ping`, or `validate` behavior:
|
||||
|
||||
- Treat `skills/release-traceability/SKILL.md` as the default reference before implementation.
|
||||
- Prefer release metadata that can be traced from `build` to `deploy` to `validate` without manual injection.
|
||||
- Keep the published image reference, runtime version, and validation output aligned.
|
||||
- Do not introduce a deploy path that rebuilds images on the target host.
|
||||
|
||||
When in doubt, follow the skill first and keep the release chain fully auditable end to end.
|
||||
|
||||
---
|
||||
|
||||
## 3. Repository Mental Model (Read This First)
|
||||
|
||||
This repository has **three clearly separated layers**:
|
||||
|
||||
@ -91,7 +104,7 @@ Used for build-time or runtime wiring only.
|
||||
|
||||
---
|
||||
|
||||
## 3. Import & Alias Rules (Critical)
|
||||
## 4. Import & Alias Rules (Critical)
|
||||
|
||||
### Dashboard code (src/\*\*)
|
||||
|
||||
@ -112,7 +125,7 @@ import { UserCard } from "@/components/UserCard";
|
||||
|
||||
---
|
||||
|
||||
## 4. TypeScript & Formatting Rules
|
||||
## 5. TypeScript & Formatting Rules
|
||||
|
||||
- Strict mode enabled
|
||||
- Use `type` for type definitions, `interface` for object shapes
|
||||
@ -123,7 +136,7 @@ import { UserCard } from "@/components/UserCard";
|
||||
|
||||
---
|
||||
|
||||
## 5. Naming Conventions
|
||||
## 6. Naming Conventions
|
||||
|
||||
- Components: PascalCase (`UserProfile.tsx`)
|
||||
- Files: kebab-case for utilities (`user-utils.ts`), PascalCase for components
|
||||
@ -133,7 +146,7 @@ import { UserCard } from "@/components/UserCard";
|
||||
|
||||
---
|
||||
|
||||
## 6. Error Handling & Logging
|
||||
## 7. Error Handling & Logging
|
||||
|
||||
- Use try/catch for async operations
|
||||
- Return Result types or throw errors consistently
|
||||
@ -142,7 +155,7 @@ import { UserCard } from "@/components/UserCard";
|
||||
|
||||
---
|
||||
|
||||
## 7. React Patterns
|
||||
## 8. React Patterns
|
||||
|
||||
- Use `'use client'` directive for client components
|
||||
- Prefer function components with hooks
|
||||
@ -151,7 +164,7 @@ import { UserCard } from "@/components/UserCard";
|
||||
|
||||
---
|
||||
|
||||
## 8. Global State Rules (Dashboard Only)
|
||||
## 9. Global State Rules (Dashboard Only)
|
||||
|
||||
✅ Zustand is the **only** allowed global state mechanism
|
||||
❌ React Context for shared/global state is forbidden
|
||||
@ -162,7 +175,7 @@ Rule: If state must survive navigation or be shared → it lives in Zustand.
|
||||
|
||||
---
|
||||
|
||||
## 9. URL-Synchronized State
|
||||
## 10. URL-Synchronized State
|
||||
|
||||
Anything involving:
|
||||
|
||||
@ -179,7 +192,7 @@ MUST be handled inside Zustand slices.
|
||||
|
||||
---
|
||||
|
||||
## 10. Component State Rules
|
||||
## 11. Component State Rules
|
||||
|
||||
Allowed:
|
||||
|
||||
@ -194,7 +207,7 @@ Forbidden:
|
||||
|
||||
---
|
||||
|
||||
## 11. packages/neurapress Rules (Very Important)
|
||||
## 12. packages/neurapress Rules (Very Important)
|
||||
|
||||
packages/neurapress is treated as a vendored internal library.
|
||||
|
||||
@ -214,7 +227,7 @@ MUST NOT:
|
||||
|
||||
---
|
||||
|
||||
## 12. Testing Guidelines
|
||||
## 13. Testing Guidelines
|
||||
|
||||
- Unit tests: Vitest with jsdom environment
|
||||
- E2E tests: Playwright
|
||||
@ -224,7 +237,7 @@ MUST NOT:
|
||||
|
||||
---
|
||||
|
||||
## 13. Environment & Runtime Config
|
||||
## 14. Environment & Runtime Config
|
||||
|
||||
- No new environment variables without approval
|
||||
- Runtime config must live in: src/config/runtime-service-config\*.yaml
|
||||
@ -233,13 +246,13 @@ MUST NOT:
|
||||
|
||||
---
|
||||
|
||||
## 14. Cursor / Copilot Rules
|
||||
## 15. Cursor / Copilot Rules
|
||||
|
||||
- No `.cursor/rules/`, `.cursorrules`, or `.github/copilot-instructions.md` found
|
||||
|
||||
---
|
||||
|
||||
## 15. TL;DR for AI Agents
|
||||
## 16. TL;DR for AI Agents
|
||||
|
||||
- dashboard = application
|
||||
- packages = libraries
|
||||
|
||||
67
Dockerfile
67
Dockerfile
@ -4,6 +4,27 @@
|
||||
ARG NODE_BUILDER_IMAGE=node:22-bookworm
|
||||
ARG NODE_RUNTIME_IMAGE=node:22-slim
|
||||
ARG CONTENTLAYER_BUILD=true
|
||||
ARG NEXT_PUBLIC_APP_BASE_URL=
|
||||
ARG NEXT_PUBLIC_SITE_URL=
|
||||
ARG NEXT_PUBLIC_LOGIN_URL=
|
||||
ARG NEXT_PUBLIC_DOCS_BASE_URL=
|
||||
ARG NEXT_PUBLIC_RUNTIME_ENVIRONMENT=
|
||||
ARG NEXT_PUBLIC_RUNTIME_REGION=
|
||||
ARG NEXT_PUBLIC_GISCUS_REPO=
|
||||
ARG NEXT_PUBLIC_GISCUS_REPO_ID=
|
||||
ARG NEXT_PUBLIC_GISCUS_CATEGORY=
|
||||
ARG NEXT_PUBLIC_GISCUS_CATEGORY_ID=
|
||||
ARG NEXT_PUBLIC_PAYPAL_CLIENT_ID=
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO=
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION=
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO=
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION=
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO=
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION=
|
||||
ARG NEXT_PUBLIC_RELEASE_IMAGE=
|
||||
ARG NEXT_PUBLIC_RELEASE_TAG=
|
||||
ARG NEXT_PUBLIC_RELEASE_COMMIT=
|
||||
ARG NEXT_PUBLIC_RELEASE_VERSION=
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Stage 1 — Builder (Turbopack + standalone)
|
||||
@ -12,8 +33,51 @@ FROM ${NODE_BUILDER_IMAGE} AS builder
|
||||
|
||||
WORKDIR /app/dashboard
|
||||
|
||||
ARG NEXT_PUBLIC_APP_BASE_URL
|
||||
ARG NEXT_PUBLIC_SITE_URL
|
||||
ARG NEXT_PUBLIC_LOGIN_URL
|
||||
ARG NEXT_PUBLIC_DOCS_BASE_URL
|
||||
ARG NEXT_PUBLIC_RUNTIME_ENVIRONMENT
|
||||
ARG NEXT_PUBLIC_RUNTIME_REGION
|
||||
ARG NEXT_PUBLIC_GISCUS_REPO
|
||||
ARG NEXT_PUBLIC_GISCUS_REPO_ID
|
||||
ARG NEXT_PUBLIC_GISCUS_CATEGORY
|
||||
ARG NEXT_PUBLIC_GISCUS_CATEGORY_ID
|
||||
ARG NEXT_PUBLIC_PAYPAL_CLIENT_ID
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO
|
||||
ARG NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION
|
||||
ARG NEXT_PUBLIC_RELEASE_IMAGE
|
||||
ARG NEXT_PUBLIC_RELEASE_TAG
|
||||
ARG NEXT_PUBLIC_RELEASE_COMMIT
|
||||
ARG NEXT_PUBLIC_RELEASE_VERSION
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED=1 \
|
||||
NEXT_PRIVATE_TURBOPACK=1
|
||||
NEXT_PRIVATE_TURBOPACK=1 \
|
||||
NEXT_PUBLIC_APP_BASE_URL=${NEXT_PUBLIC_APP_BASE_URL} \
|
||||
NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL} \
|
||||
NEXT_PUBLIC_LOGIN_URL=${NEXT_PUBLIC_LOGIN_URL} \
|
||||
NEXT_PUBLIC_DOCS_BASE_URL=${NEXT_PUBLIC_DOCS_BASE_URL} \
|
||||
NEXT_PUBLIC_RUNTIME_ENVIRONMENT=${NEXT_PUBLIC_RUNTIME_ENVIRONMENT} \
|
||||
NEXT_PUBLIC_RUNTIME_REGION=${NEXT_PUBLIC_RUNTIME_REGION} \
|
||||
NEXT_PUBLIC_GISCUS_REPO=${NEXT_PUBLIC_GISCUS_REPO} \
|
||||
NEXT_PUBLIC_GISCUS_REPO_ID=${NEXT_PUBLIC_GISCUS_REPO_ID} \
|
||||
NEXT_PUBLIC_GISCUS_CATEGORY=${NEXT_PUBLIC_GISCUS_CATEGORY} \
|
||||
NEXT_PUBLIC_GISCUS_CATEGORY_ID=${NEXT_PUBLIC_GISCUS_CATEGORY_ID} \
|
||||
NEXT_PUBLIC_PAYPAL_CLIENT_ID=${NEXT_PUBLIC_PAYPAL_CLIENT_ID} \
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO=${NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO} \
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION=${NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION} \
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO=${NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO} \
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION=${NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION} \
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO=${NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO} \
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION=${NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION} \
|
||||
NEXT_PUBLIC_RELEASE_IMAGE=${NEXT_PUBLIC_RELEASE_IMAGE} \
|
||||
NEXT_PUBLIC_RELEASE_TAG=${NEXT_PUBLIC_RELEASE_TAG} \
|
||||
NEXT_PUBLIC_RELEASE_COMMIT=${NEXT_PUBLIC_RELEASE_COMMIT} \
|
||||
NEXT_PUBLIC_RELEASE_VERSION=${NEXT_PUBLIC_RELEASE_VERSION}
|
||||
|
||||
# ---------------------------
|
||||
# 基础镜像升级到最新
|
||||
@ -59,7 +123,6 @@ RUN apt-get update \
|
||||
COPY --from=builder /app/dashboard/.next/standalone ./
|
||||
COPY --from=builder /app/dashboard/.next/static ./static
|
||||
COPY --from=builder /app/dashboard/public ./public
|
||||
COPY --from=builder /app/dashboard/src/content/blog ./src/content/blog
|
||||
|
||||
# ---------------------------
|
||||
# 额外瘦身(可减少 15–40 MB)
|
||||
|
||||
2
Makefile
2
Makefile
@ -49,7 +49,6 @@ init:
|
||||
echo "❌ Unsupported OS. Please install Yarn manually."; exit 1; \
|
||||
fi; \
|
||||
fi
|
||||
yarn config set npmRegistryServer https://registry.npmmirror.com
|
||||
yarn install --immutable
|
||||
|
||||
ensure-deps:
|
||||
@ -83,7 +82,6 @@ test:
|
||||
@yarn test || echo "No tests configured"
|
||||
|
||||
build: init
|
||||
yarn config set npmRegistryServer https://registry.npmmirror.com
|
||||
@if [ -z "$(SKIP_SYNC)" ]; then \
|
||||
$(MAKE) sync-dl-index; \
|
||||
fi
|
||||
|
||||
177
README.md
177
README.md
@ -1,101 +1,138 @@
|
||||
# console.svc.plus
|
||||
|
||||
**工程师 · 开源 · 云中立**
|
||||
Cloud Neutral Toolkit 的开放云控制面板 (Open Cloud Control Panel).
|
||||
|
||||
关注 **Ops / Infra / AI** 与 **技术自由**。
|
||||
🏗️ 热衷于构建“逃生舱”,防止基础设施被厂商锁定。
|
||||
面向 **Ops / Infra / AI** 的统一前端仪表盘,强调技术自由与可迁移性。
|
||||
|
||||
> **Accountable Engineer · Open Source · Cloud Neutral**
|
||||
>
|
||||
> Focus on **Ops / Infra / AI** and **Technical Freedom**.
|
||||
> 🏗️ Passionate about building "escape pods" to prevent infrastructure vendor lock-in.
|
||||
> A unified dashboard for Ops / Infra / AI, built for technical freedom and portability.
|
||||
|
||||
---
|
||||
## 部署要求 (Deployment Requirements)
|
||||
|
||||
**console.svc.plus** 是 Cloud Neutral Toolkit 的**开放云控制面板**。
|
||||
| 维度 | 要求 / 规格 | 说明 |
|
||||
| ----------- | ------------------ | ------------------------------------- |
|
||||
| Node.js | `>=18.17 <25` | 推荐使用 `.nvmrc` |
|
||||
| 包管理 | Yarn (推荐) 或 npm | Yarn 推荐配合 Corepack |
|
||||
| Git | 必需 | 用于拉取仓库 |
|
||||
| 部署 (可选) | Vercel / 自建 | 部署方式见 `docs/usage/deployment.md` |
|
||||
|
||||
> **console.svc.plus** is the **Open Cloud Control Panel** for the Cloud Neutral Toolkit.
|
||||
## 快速开始 (Quickstart)
|
||||
|
||||
## 项目简介 (About The Project)
|
||||
|
||||
本项目是 Cloud Neutral 生态系统的核心可视化界面(前端仪表盘)。它连接各个微服务,为管理云中立基础设施提供统一的控制平面。
|
||||
|
||||
> This repository serves as the central visual interface (Frontend Dashboard) for the Cloud Neutral ecosystem. It connects various micro-services to provide a unified control plane for managing your cloud-neutral infrastructure.
|
||||
|
||||
该生态系统目前包含多个专用的微后端和服务:
|
||||
|
||||
* **console.svc.plus**: (本项目) 主前端仪表盘。
|
||||
* **accounts.svc.plus**: 身份与账户管理服务。
|
||||
* **rag-server.svc.plus**: 检索增强生成 (RAG) 后端。
|
||||
* **postgresql.svc.plus**: 带有专用扩展的 PostgreSQL 数据库服务。
|
||||
* **page-reading-agent-backend**: 页面阅读智能体后端逻辑。
|
||||
* **page-reading-agent-dashboard**: 页面阅读智能体专用仪表盘。
|
||||
* **wechat-to-markdown.svc.plus**: 微信内容转 Markdown 工具服务 (开源引用项目)
|
||||
|
||||
## 技术栈 (Tech Stack)
|
||||
|
||||
本仪表盘使用现代 Web 技术构建:
|
||||
> This dashboard is built using modern web technologies:
|
||||
|
||||
* **框架**: [Next.js](https://nextjs.org/)
|
||||
* **语言**: TypeScript
|
||||
* **样式**: [Tailwind CSS](https://tailwindcss.com/)
|
||||
* **UI 组件**: [Radix UI](https://www.radix-ui.com/)
|
||||
* **内容管理**: [Contentlayer](https://contentlayer.dev/)
|
||||
|
||||
## 快速开始 (Getting Started)
|
||||
|
||||
### 前置要求 (Prerequisites)
|
||||
|
||||
* Node.js (`>=18.17 <25`)
|
||||
* Yarn (推荐) 或 npm
|
||||
|
||||
### 安装 (Installation)
|
||||
### 一键初始化 (Setup Script)
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
curl -fsSL "https://raw.githubusercontent.com/x-evor/console.svc.plus/main/scripts/setup.sh?$(date +%s)" \
|
||||
| bash -s -- console.svc.plus
|
||||
```
|
||||
|
||||
### 本地运行 (Running Locally)
|
||||
|
||||
启动开发服务器:
|
||||
> To start the development server:
|
||||
### 本地运行 (Local Dev)
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
此命令会运行设置脚本 (`scripts/Dev-MCP-Server.sh`) 并启动带有 TurboPack 的 Next.js 开发服务器。
|
||||
> This command runs the setup script (`scripts/Dev-MCP-Server.sh`) and starts the Next.js development server with TurboPack.
|
||||
|
||||
### 构建生产版本 (Building for Production)
|
||||
如果需要环境变量:
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
## 认证配置 (Authentication Configuration)
|
||||
如果你的工作区同时包含 `openclaw-deploy-example`,建议参考 `../openclaw-deploy-example/.env` 填写 AI 助手联调配置,并同时查看 `docs/getting-started/installation.md`。
|
||||
|
||||
有关如何配置 GitHub 和 Google OIDC 认证的详细步骤,请参阅 [OIDC 认证指南](./docs/integrations/oidc-auth.md)。
|
||||
## 主要入口 (Key Routes)
|
||||
|
||||
> For detailed steps on configuring GitHub and Google OIDC authentication, please refer to the [OIDC Authentication Guide](./docs/integrations/oidc-auth.md).
|
||||
- `/services`:服务导航页,保留现有控制台布局。
|
||||
- `/xworkmate`:原生 Next.js 的 XWorkmate 在线工作区,底层通过 `xworkmate-bridge` 的 `/acp/rpc` 接入。
|
||||
- `/panel/api`:融合设置与集成页,用于配置和探测 OpenClaw Gateway、Vault Server、APISIX AI Gateway。
|
||||
|
||||
## 统计配置 (Homepage Stats Configuration)
|
||||
## AI 助手与集成能力 (Assistant & Integrations)
|
||||
|
||||
首页“注册用户数 / 访问量”所需 Cloudflare 变量说明,请参阅 [Cloudflare Web Analytics 集成配置](./docs/integrations/cloudflare-web-analytics.md)。
|
||||
当前主页 AI 辅助功能已经基于本仓库原生实现,核心行为如下:
|
||||
|
||||
> For Cloudflare variables used by homepage stats, see the [Cloudflare Web Analytics integration guide](./docs/integrations/cloudflare-web-analytics.md).
|
||||
- 侧栏助手模式保留现有交互方式,但 `/xworkmate` 主工作区直接对接 `xworkmate-bridge`。
|
||||
- 最大化助手页面统一收敛到 `/xworkmate`,旧的 `/services/openclaw` 只保留兼容跳转,不再继续使用旧的 control UI 套壳。
|
||||
- 页面截图通过 assistant chat 附件模式发送,而不是单独的浏览器控制壳。
|
||||
- `/panel/api` 仍保留旧集成配置入口;`/xworkmate` 主路径不依赖它。
|
||||
- bridge 地址与令牌从服务端环境变量读取,前端组件不硬编码敏感配置。
|
||||
|
||||
## 开发指南 (Development Guidelines)
|
||||
## 环境变量 (Environment Variables)
|
||||
|
||||
有关详细的编码标准、架构规则和 Agent 特定说明,请参阅 [AGENTS.md](./AGENTS.md)。
|
||||
以下变量用于 `/xworkmate` 主工作区的服务端 bridge 代理:
|
||||
|
||||
> For detailed coding standards, architecture rules, and agent-specific instructions, please refer to [AGENTS.md](./AGENTS.md).
|
||||
| 变量 | 用途 |
|
||||
| ------------------- | ------------------------------------- |
|
||||
| `BRIDGE_SERVER_URL` | XWorkmate bridge 服务根地址 |
|
||||
| `BRIDGE_AUTH_TOKEN` | XWorkmate bridge bearer token,服务端 |
|
||||
|
||||
## 脚本 (Scripts)
|
||||
以下变量用于旧助手和集成页的服务端默认值预填:
|
||||
|
||||
* `dev`: 启动开发服务器。
|
||||
* `build`: 构建生产版本应用。
|
||||
* `test`: 使用 Vitest 运行单元测试。
|
||||
* `test:e2e`: 使用 Playwright 运行端到端测试。
|
||||
* `lint`: 运行代码检查 (Linter)。
|
||||
| 变量 | 用途 |
|
||||
| ----------------------------- | ------------------------------------ |
|
||||
| `OPENCLAW_GATEWAY_REMOTE_URL` | OpenClaw gateway 远端 WebSocket 地址 |
|
||||
| `OPENCLAW_GATEWAY_TOKEN` | OpenClaw gateway 访问令牌 |
|
||||
| `VAULT_SERVER_URL` | Vault 服务地址 |
|
||||
| `VAULT_NAMESPACE` | Vault namespace,可选 |
|
||||
| `VAULT_TOKEN` | Vault 探测令牌 |
|
||||
| `APISIX_AI_GATEWAY_URL` | APISIX AI Gateway 地址 |
|
||||
| `AI_GATEWAY_ACCESS_TOKEN` | APISIX AI Gateway 探测令牌 |
|
||||
|
||||
更多说明见 `docs/getting-started/installation.md` 和 `.env.example`。
|
||||
|
||||
## Stripe 配置 (Stripe Billing Setup)
|
||||
|
||||
`/prices`、产品页和账户中心的购买入口现在统一读取前端公开的 Stripe `price_id`:
|
||||
|
||||
| 变量 | 用途 |
|
||||
| -------------------------------------------------- | ------------------- |
|
||||
| `NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO` | Xstream 按量购买 |
|
||||
| `NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION` | Xstream 订阅 |
|
||||
| `NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO` | XScopeHub 按量购买 |
|
||||
| `NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION` | XScopeHub 订阅 |
|
||||
| `NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO` | XCloudFlow 按量购买 |
|
||||
| `NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION` | XCloudFlow 订阅 |
|
||||
|
||||
这些值应填写为 Stripe Dashboard 中对应套餐的 `price_...` 标识。联调步骤见 `docs/integrations/stripe-billing.md`。
|
||||
|
||||
## 核心特性 & 技术栈 (Features & Tech Stack)
|
||||
|
||||
核心特性:
|
||||
|
||||
- 统一控制面:汇聚 Cloud Neutral Toolkit 各微服务入口
|
||||
- 原生 AI 助手工作区:OpenClaw gateway 驱动的聊天、截图附件与会话体验
|
||||
- 融合集成设置:在 `/panel/api` 统一管理 OpenClaw、Vault、APISIX AI Gateway
|
||||
- 文档与内容系统:Contentlayer 驱动的 docs/content pipeline
|
||||
- 可扩展集成:OIDC、Cloudflare Web Analytics 等
|
||||
|
||||
技术栈:
|
||||
|
||||
- Next.js + TypeScript
|
||||
- Tailwind CSS + Radix UI
|
||||
- Zustand
|
||||
- Contentlayer
|
||||
|
||||
## 开发命令 (Useful Commands)
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
yarn build
|
||||
yarn typecheck
|
||||
./node_modules/.bin/eslint . --no-eslintrc --config .eslintrc.json --resolve-plugins-relative-to .
|
||||
```
|
||||
|
||||
## 说明文档 (Docs)
|
||||
|
||||
入口:
|
||||
|
||||
- EN: `docs/README.md`
|
||||
- ZH: `docs/zh/README.md`
|
||||
|
||||
常用链接:
|
||||
|
||||
- OIDC: `docs/integrations/oidc-auth.md`
|
||||
- Cloudflare Web Analytics: `docs/integrations/cloudflare-web-analytics.md`
|
||||
- Stripe billing: `docs/integrations/stripe-billing.md`
|
||||
- Assistant / Integrations env setup: `docs/getting-started/installation.md`
|
||||
- Chinese installation guide: `docs/zh/getting-started/installation.md`
|
||||
|
||||
其他:
|
||||
|
||||
- Agent rules: `AGENTS.md`
|
||||
|
||||
6
agent.md
6
agent.md
@ -16,6 +16,12 @@ You are an AI agent working inside this repository.
|
||||
- Keep changes scoped to the request; avoid unrelated refactors.
|
||||
- Prefer minimal edits that preserve existing behavior and style.
|
||||
|
||||
## Release Traceability Default Rule
|
||||
|
||||
- For changes touching CI/CD, image tags, deploy contracts, `/api/ping`, or `validate`, treat `skills/release-traceability/SKILL.md` as the default reference first.
|
||||
- Keep build output, runtime version, and validate output aligned through the whole release chain.
|
||||
- Do not add a deploy path that rebuilds images on the target host.
|
||||
|
||||
## Repository Constraints (Quick View)
|
||||
|
||||
- App layer: src/app/**, src/components/**, src/lib/**, src/state/**, src/modules/\*\*
|
||||
|
||||
332
config/feature_flags.yaml
Normal file
332
config/feature_flags.yaml
Normal file
@ -0,0 +1,332 @@
|
||||
# Feature flag inventory for the dashboard and public site.
|
||||
# This file is a human-readable catalog of page-level and module-level flags.
|
||||
|
||||
meta:
|
||||
app: console.svc.plus
|
||||
scope:
|
||||
- public-site
|
||||
- dashboard
|
||||
- xworkmate
|
||||
- cloud-iac
|
||||
- docs
|
||||
source:
|
||||
- src/config/feature-toggles.json
|
||||
- src/modules/extensions/builtin
|
||||
- src/app
|
||||
|
||||
runtime:
|
||||
current_implementation:
|
||||
toggles_json: src/config/feature-toggles.json
|
||||
loader: src/lib/featureToggles.ts
|
||||
extension_flags: src/lib/featureFlags.ts
|
||||
notes:
|
||||
- "feature-toggles.json is the active runtime source for path-based gating."
|
||||
- "This YAML is an inventory and planning file; it does not currently drive runtime behavior."
|
||||
|
||||
sections:
|
||||
globalNavigation:
|
||||
enabled: true
|
||||
description: Top-level navigation and auth entry points.
|
||||
default_channel: stable
|
||||
routes:
|
||||
- path: /
|
||||
status: enabled
|
||||
channel: stable
|
||||
- path: /docs
|
||||
status: enabled
|
||||
channel: beta
|
||||
- path: /blogs
|
||||
status: enabled
|
||||
note: Public content listing, not currently toggle-gated in code.
|
||||
- path: /services
|
||||
status: enabled
|
||||
note: Public service directory.
|
||||
- path: /prices
|
||||
status: enabled
|
||||
- path: /support
|
||||
status: enabled
|
||||
- path: /about
|
||||
status: enabled
|
||||
- path: /login
|
||||
status: enabled
|
||||
channel: stable
|
||||
- path: /register
|
||||
status: enabled
|
||||
channel: stable
|
||||
- path: /panel
|
||||
status: enabled
|
||||
channel: stable
|
||||
- path: /panel/management
|
||||
status: enabled
|
||||
note: Shown only to admin/operator users.
|
||||
- path: /cloud_iac
|
||||
status: enabled
|
||||
channel: develop
|
||||
- path: /download
|
||||
status: enabled
|
||||
channel: stable
|
||||
- path: /insight
|
||||
status: enabled
|
||||
channel: develop
|
||||
- path: /xworkmate
|
||||
status: enabled
|
||||
|
||||
appModules:
|
||||
enabled: true
|
||||
description: Path-based module gating used by route handlers and content loaders.
|
||||
routes:
|
||||
- path: /docs
|
||||
status: enabled
|
||||
uses: src/app/docs/page.tsx
|
||||
- path: /docs/[collection]
|
||||
status: enabled
|
||||
uses: src/app/docs/[collection]/page.tsx
|
||||
- path: /docs/[collection]/[...slug]
|
||||
status: enabled
|
||||
uses: src/app/docs/[collection]/[...slug]/page.tsx
|
||||
- path: /download
|
||||
status: enabled
|
||||
uses: src/app/download/page.tsx
|
||||
- path: /download/[...segments]
|
||||
status: enabled
|
||||
uses: src/app/download/[...segments]/page.tsx
|
||||
- path: /cloud_iac
|
||||
status: enabled
|
||||
uses: src/app/cloud_iac/page.tsx
|
||||
- path: /cloud_iac/[provider]
|
||||
status: enabled
|
||||
uses: src/app/cloud_iac/[provider]/page.tsx
|
||||
- path: /cloud_iac/[provider]/[service]
|
||||
status: enabled
|
||||
uses: src/app/cloud_iac/[provider]/[service]/page.tsx
|
||||
- path: /insight
|
||||
status: enabled
|
||||
uses: src/app/services/insight/page.tsx
|
||||
- path: /editor
|
||||
status: enabled
|
||||
uses: src/app/editor/page.tsx
|
||||
- path: /editor/wechat
|
||||
status: enabled
|
||||
- path: /editor/xiaohongshu
|
||||
status: enabled
|
||||
- path: /xworkmate
|
||||
status: enabled
|
||||
uses: src/app/xworkmate/page.tsx
|
||||
- path: /xworkmate/admin
|
||||
status: enabled
|
||||
uses: src/app/xworkmate/admin/page.tsx
|
||||
- path: /xworkmate/integrations
|
||||
status: enabled
|
||||
uses: src/app/xworkmate/integrations/page.tsx
|
||||
|
||||
cmsExperience:
|
||||
enabled: true
|
||||
description: CMS/homepage experience gating.
|
||||
routes:
|
||||
- path: /homepage
|
||||
status: enabled
|
||||
children:
|
||||
- path: /homepage/dynamic
|
||||
status: enabled
|
||||
|
||||
extensions:
|
||||
builtin.user-center:
|
||||
enabled: true
|
||||
description: Core dashboard user center and account management extension.
|
||||
routes:
|
||||
- path: /panel
|
||||
id: dashboard
|
||||
enabled: true
|
||||
sidebar_section: workspace
|
||||
- path: /panel/agent
|
||||
id: agents
|
||||
enabled: true
|
||||
env_var: NEXT_PUBLIC_FEATURE_AGENT_MODULE
|
||||
default_enabled: true
|
||||
sidebar_section: productivity
|
||||
- path: /panel/api
|
||||
id: apis
|
||||
enabled: true
|
||||
env_var: NEXT_PUBLIC_FEATURE_API_MODULE
|
||||
default_enabled: true
|
||||
sidebar_section: productivity
|
||||
- path: /panel/account
|
||||
id: accounts
|
||||
enabled: true
|
||||
sidebar_section: management
|
||||
- path: /panel/subscription
|
||||
id: subscription
|
||||
enabled: true
|
||||
env_var: NEXT_PUBLIC_FEATURE_SUBSCRIPTION_MODULE
|
||||
default_enabled: true
|
||||
sidebar_section: management
|
||||
- path: /panel/ldp
|
||||
id: ldp
|
||||
enabled: true
|
||||
env_var: NEXT_PUBLIC_FEATURE_LDP_MODULE
|
||||
default_enabled: false
|
||||
sidebar_section: management
|
||||
- path: /panel/appearance
|
||||
id: appearance
|
||||
enabled: true
|
||||
sidebar_section: preferences
|
||||
- path: /panel/management
|
||||
id: management
|
||||
enabled: true
|
||||
roles:
|
||||
- admin
|
||||
- operator
|
||||
permissions:
|
||||
- admin.settings.read
|
||||
- admin.users.metrics.read
|
||||
- admin.users.list.read
|
||||
- admin.agents.status.read
|
||||
- admin.blacklist.read
|
||||
sidebar_hidden: true
|
||||
|
||||
builtin.infra:
|
||||
enabled: true
|
||||
description: Infrastructure and ops extension.
|
||||
routes:
|
||||
- path: /panel/deployments
|
||||
id: deployments
|
||||
enabled: true
|
||||
sidebar_section: infra
|
||||
- path: /panel/resources
|
||||
id: resources
|
||||
enabled: true
|
||||
sidebar_section: infra
|
||||
- path: /panel/api-keys
|
||||
id: apiKeys
|
||||
enabled: true
|
||||
sidebar_section: infra
|
||||
- path: /panel/observability
|
||||
id: logs
|
||||
enabled: true
|
||||
sidebar_section: infra
|
||||
- path: /panel/settings
|
||||
id: settings
|
||||
enabled: true
|
||||
sidebar_section: preferences
|
||||
|
||||
pages:
|
||||
public:
|
||||
- path: /
|
||||
component: src/app/page.tsx
|
||||
status: enabled
|
||||
- path: /services
|
||||
component: src/app/services/page.tsx
|
||||
status: enabled
|
||||
- path: /about
|
||||
component: src/app/about/page.tsx
|
||||
status: enabled
|
||||
- path: /prices
|
||||
component: src/app/prices/page.tsx
|
||||
status: enabled
|
||||
- path: /support
|
||||
component: src/app/support/page.tsx
|
||||
status: enabled
|
||||
- path: /support/discussions
|
||||
component: src/app/support/discussions/page.tsx
|
||||
status: enabled
|
||||
- path: /blogs
|
||||
component: src/app/blogs/page.tsx
|
||||
status: enabled
|
||||
- path: /blogs/[...slug]
|
||||
component: src/app/blogs/[...slug]/page.tsx
|
||||
status: enabled
|
||||
- path: /terms
|
||||
component: src/app/terms/page.tsx
|
||||
status: enabled
|
||||
- path: /privacy
|
||||
component: src/app/privacy/page.tsx
|
||||
status: enabled
|
||||
- path: /download
|
||||
component: src/app/download/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /download/[...segments]
|
||||
component: src/app/download/[...segments]/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /docs
|
||||
component: src/app/docs/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /docs/[collection]
|
||||
component: src/app/docs/[collection]/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /docs/[collection]/[...slug]
|
||||
component: src/app/docs/[collection]/[...slug]/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /cloud_iac
|
||||
component: src/app/cloud_iac/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /cloud_iac/[provider]
|
||||
component: src/app/cloud_iac/[provider]/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /cloud_iac/[provider]/[service]
|
||||
component: src/app/cloud_iac/[provider]/[service]/page.tsx
|
||||
status: gated_by_appModules
|
||||
- path: /editor
|
||||
component: src/app/editor/page.tsx
|
||||
status: redirect_external
|
||||
- path: /editor/wechat
|
||||
component: src/app/editor/wechat/page.tsx
|
||||
status: enabled
|
||||
- path: /editor/xiaohongshu
|
||||
component: src/app/editor/xiaohongshu/page.tsx
|
||||
status: enabled
|
||||
- path: /xworkmate
|
||||
component: src/app/xworkmate/page.tsx
|
||||
status: enabled
|
||||
- path: /xworkmate/admin
|
||||
component: src/app/xworkmate/admin/page.tsx
|
||||
status: enabled
|
||||
- path: /xworkmate/integrations
|
||||
component: src/app/xworkmate/integrations/page.tsx
|
||||
status: enabled
|
||||
|
||||
auth:
|
||||
- path: /login
|
||||
component: src/app/(auth)/login/page.tsx
|
||||
status: gated_by_globalNavigation
|
||||
- path: /register
|
||||
component: src/app/(auth)/register/page.tsx
|
||||
status: gated_by_globalNavigation
|
||||
- path: /email-verification
|
||||
component: src/app/(auth)/email-verification/page.tsx
|
||||
status: gated_by_globalNavigation
|
||||
- path: /logout
|
||||
component: src/app/logout/page.tsx
|
||||
status: enabled
|
||||
|
||||
panel:
|
||||
- path: /panel
|
||||
component: src/app/panel/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/account
|
||||
component: src/app/panel/account/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/agent
|
||||
component: src/app/panel/agent/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/api
|
||||
component: src/app/panel/api/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/appearance
|
||||
component: src/app/panel/appearance/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/ldp
|
||||
component: src/app/panel/ldp/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/management
|
||||
component: src/app/panel/management/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/subscription
|
||||
component: src/app/panel/subscription/page.tsx
|
||||
status: extension_route
|
||||
- path: /panel/[...segments]
|
||||
component: src/app/panel/[...segments]/page.tsx
|
||||
status: catch_all_extension
|
||||
|
||||
recommendations:
|
||||
- "If this file is intended to become runtime-configurable, wire it into src/lib/featureToggles.ts and keep feature-toggles.json as the generated artifact."
|
||||
- "If this file is intended only for documentation, keep it synchronized with feature-toggles.json and extension definitions."
|
||||
54
deploy/single-node/.env.runtime.example
Normal file
54
deploy/single-node/.env.runtime.example
Normal file
@ -0,0 +1,54 @@
|
||||
# Compose settings
|
||||
FRONTEND_IMAGE=ghcr.io/cloud-neutral-toolkit/dashboard:replace-me
|
||||
CANONICAL_DOMAIN=www.svc.plus
|
||||
SERVED_DOMAINS=www.svc.plus,console.svc.plus
|
||||
|
||||
# Frontend runtime
|
||||
NODE_ENV=production
|
||||
PORT=3000
|
||||
RUNTIME_ENV=prod
|
||||
REGION=cn
|
||||
APP_BASE_URL=https://www.svc.plus
|
||||
NEXT_PUBLIC_APP_BASE_URL=https://www.svc.plus
|
||||
NEXT_PUBLIC_SITE_URL=https://www.svc.plus
|
||||
NEXT_PUBLIC_LOGIN_URL=https://www.svc.plus/login
|
||||
NEXT_PUBLIC_DOCS_BASE_URL=https://www.svc.plus/docs
|
||||
SESSION_COOKIE_SECURE=true
|
||||
NEXT_PUBLIC_SESSION_COOKIE_SECURE=true
|
||||
RUNTIME_HOSTNAME=www.svc.plus
|
||||
DEPLOYMENT_HOSTNAME=www.svc.plus
|
||||
NEXT_PUBLIC_RUNTIME_ENVIRONMENT=prod
|
||||
NEXT_PUBLIC_RUNTIME_REGION=cn
|
||||
|
||||
# Upstream service URLs
|
||||
ACCOUNT_SERVICE_URL=https://accounts.svc.plus
|
||||
NEXT_PUBLIC_ACCOUNT_SERVICE_URL=https://accounts.svc.plus
|
||||
SERVER_SERVICE_URL=https://api.svc.plus
|
||||
NEXT_PUBLIC_SERVER_SERVICE_URL=https://api.svc.plus
|
||||
SERVER_SERVICE_INTERNAL_URL=
|
||||
|
||||
# Optional integrations
|
||||
OPENCLAW_GATEWAY_REMOTE_URL=
|
||||
OPENCLAW_GATEWAY_TOKEN=
|
||||
VAULT_SERVER_URL=
|
||||
VAULT_NAMESPACE=
|
||||
VAULT_TOKEN=
|
||||
APISIX_AI_GATEWAY_URL=
|
||||
AI_GATEWAY_ACCESS_TOKEN=
|
||||
INTERNAL_SERVICE_TOKEN=
|
||||
CLOUDFLARE_API_TOKEN=
|
||||
CLOUDFLARE_ACCOUNT_ID=
|
||||
CLOUDFLARE_WEB_ANALYTICS_SITE_TAG=
|
||||
CLOUDFLARE_ZONE_TAG=
|
||||
ROOT_EMAIL_WHITELIST=admin@svc.plus
|
||||
NEXT_PUBLIC_PAYPAL_CLIENT_ID=
|
||||
NEXT_PUBLIC_GISCUS_REPO=cloud-neutral-toolkit/console.svc.plus
|
||||
NEXT_PUBLIC_GISCUS_REPO_ID=
|
||||
NEXT_PUBLIC_GISCUS_CATEGORY=General
|
||||
NEXT_PUBLIC_GISCUS_CATEGORY_ID=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO=
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION=
|
||||
28
deploy/single-node/Caddyfile
Normal file
28
deploy/single-node/Caddyfile
Normal file
@ -0,0 +1,28 @@
|
||||
{$SERVED_DOMAINS} {
|
||||
encode zstd gzip
|
||||
|
||||
handle_path /_next/static/* {
|
||||
root * /srv
|
||||
header Cache-Control "public, max-age=31536000, immutable"
|
||||
file_server
|
||||
}
|
||||
|
||||
@public_assets {
|
||||
file {
|
||||
root /srv/public
|
||||
try_files {path}
|
||||
}
|
||||
}
|
||||
handle @public_assets {
|
||||
root * /srv/public
|
||||
header Cache-Control "public, max-age=3600"
|
||||
file_server
|
||||
}
|
||||
|
||||
reverse_proxy dashboard:3000 {
|
||||
header_up Host {host}
|
||||
header_up X-Forwarded-Host {host}
|
||||
header_up X-Forwarded-Proto {scheme}
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
}
|
||||
}
|
||||
55
deploy/single-node/docker-compose.yml
Normal file
55
deploy/single-node/docker-compose.yml
Normal file
@ -0,0 +1,55 @@
|
||||
services:
|
||||
frontend-assets:
|
||||
image: ${FRONTEND_IMAGE:?set FRONTEND_IMAGE in .env.runtime}
|
||||
restart: "no"
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
rm -rf /assets/_next /assets/chunks /assets/public
|
||||
mkdir -p /assets /assets/public
|
||||
cp -R /app/dashboard/static/. /assets/
|
||||
cp -R /app/dashboard/public/. /assets/public
|
||||
volumes:
|
||||
- frontend_static:/assets
|
||||
|
||||
dashboard:
|
||||
image: ${FRONTEND_IMAGE:?set FRONTEND_IMAGE in .env.runtime}
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env.runtime
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: 3000
|
||||
volumes:
|
||||
- frontend_static:/app/dashboard/.next/static:ro
|
||||
networks:
|
||||
- frontend
|
||||
|
||||
caddy:
|
||||
image: caddy:2.10-alpine
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- dashboard
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
environment:
|
||||
SERVED_DOMAINS: ${SERVED_DOMAINS:?set SERVED_DOMAINS in .env.runtime}
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- frontend_static:/srv:ro
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
networks:
|
||||
- frontend
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
frontend_static:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
58
dev.log
58
dev.log
@ -1,31 +1,39 @@
|
||||
▲ Next.js 16.1.6 (Turbopack)
|
||||
|
||||
> dashboard@1.0.0 dev
|
||||
> bash scripts/Dev-MCP-Server.sh && next dev --turbo
|
||||
|
||||
[MCP] Cleaning stale Chrome processes...
|
||||
[MCP] Starting Chrome (remote debugging)...
|
||||
[MCP] Waiting for Chrome DevTools endpoint...
|
||||
[MCP] Chrome DevTools ready on port 9222
|
||||
[MCP] (Optional) Pre-warming chrome-devtools-mcp...
|
||||
[MCP] Done. You can now run: npm run dev
|
||||
▲ Next.js 16.1.2 (Turbopack)
|
||||
- Local: http://localhost:3000
|
||||
- Network: http://192.168.0.2:3000
|
||||
|
||||
✓ Starting...
|
||||
✓ Ready in 2.5s
|
||||
○ Compiling /services ...
|
||||
GET /services 200 in 6.8s (compile: 6.4s, render: 327ms)
|
||||
|
||||
Attention: Next.js now collects completely anonymous telemetry regarding usage.
|
||||
This information is used to shape Next.js' roadmap and prioritize features.
|
||||
|
||||
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
|
||||
https://nextjs.org/telemetry
|
||||
|
||||
|
||||
✓ Ready in 4.4s
|
||||
|
||||
○ Compiling / ...
|
||||
|
||||
GET / 200 in 11.8s (compile: 11.0s, render: 755ms)
|
||||
|
||||
GET / 200 in 513ms (compile: 159ms, render: 354ms)
|
||||
|
||||
GET /api/integrations/defaults 200 in 1276ms (compile: 1242ms, render: 35ms)
|
||||
|
||||
[runtime-config] Loaded env: PROD
|
||||
GET /api/auth/session 200 in 1021ms (compile: 993ms, render: 29ms)
|
||||
GET /services 200 in 87ms (compile: 5ms, render: 82ms)
|
||||
GET /api/auth/session 200 in 11ms (compile: 3ms, render: 7ms)
|
||||
✓ Compiled in 310ms
|
||||
GET /services 200 in 441ms (compile: 149ms, render: 293ms)
|
||||
GET /api/auth/session 200 in 16ms (compile: 5ms, render: 10ms)
|
||||
GET /services 200 in 252ms (compile: 100ms, render: 152ms)
|
||||
GET /api/auth/session 200 in 14ms (compile: 5ms, render: 8ms)
|
||||
GET /services 200 in 251ms (compile: 86ms, render: 165ms)
|
||||
GET /api/auth/session 200 in 13ms (compile: 4ms, render: 8ms)
|
||||
GET /services 200 in 281ms (compile: 94ms, render: 187ms)
|
||||
GET /api/auth/session 200 in 12ms (compile: 4ms, render: 8ms)
|
||||
|
||||
GET /api/auth/session 200 in 2.2s (compile: 2.2s, render: 15ms)
|
||||
|
||||
GET /api/marketing/home-stats 200 in 1435ms (compile: 1425ms, render: 9ms)
|
||||
|
||||
GET / 200 in 150ms (compile: 5ms, render: 145ms)
|
||||
|
||||
GET /api/auth/session 200 in 16ms (compile: 4ms, render: 12ms)
|
||||
|
||||
GET /api/integrations/defaults 200 in 20ms (compile: 12ms, render: 8ms)
|
||||
|
||||
GET /api/marketing/home-stats 200 in 29ms (compile: 22ms, render: 7ms)
|
||||
|
||||
GET /api/blogs/latest?limit=7 200 in 37ms (compile: 29ms, render: 8ms)
|
||||
|
||||
14
docs/DOC_COVERAGE.md
Normal file
14
docs/DOC_COVERAGE.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Documentation Coverage Matrix
|
||||
|
||||
This matrix tracks the bilingual canonical documentation set for `console.svc.plus` and maps it back to the current codebase and older docs.
|
||||
|
||||
该矩阵用于跟踪 `console.svc.plus` 的双语规范文档,并将其与当前代码状态和历史文档对应起来。
|
||||
|
||||
| Category | EN | ZH | Current status | Existing references | Next check |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Architecture | Yes | Yes | Seeded from current codebase and existing docs. | `api/overview.md`<br>`architecture/components.md`<br>`architecture/design-decisions.md`<br>`architecture/overview.md`<br>`architecture/roadmap.md`<br>`development/code-structure.md`<br>`zh/api/overview.md`<br>`zh/architecture/components.md` | Keep diagrams and ownership notes synchronized with actual directories, services, and integration dependencies. |
|
||||
| Design | Yes | Yes | Seeded from current codebase and existing docs. | `SEO-WORK-SUMMARY.md`<br>`architecture/design-decisions.md`<br>`zh/SEO-WORK-SUMMARY.md`<br>`zh/architecture/design-decisions.md` | Promote one-off implementation notes into reusable design records when behavior, APIs, or deployment contracts change. |
|
||||
| Deployment | Yes | Yes | Seeded from current codebase and existing docs. | `development/dev-setup.md`<br>`getting-started/installation.md`<br>`getting-started/quickstart.md`<br>`governance/release-process.md`<br>`operations/runbooks/README.md`<br>`operations/runbooks/rag-server.md`<br>`usage/deployment.md`<br>`zh/development/dev-setup.md` | Verify deployment steps against current scripts, manifests, CI/CD flow, and environment contracts before each release. |
|
||||
| User Guide | Yes | Yes | Seeded from current codebase and existing docs. | `api/overview.md`<br>`architecture/overview.md`<br>`getting-started/concepts.md`<br>`getting-started/installation.md`<br>`getting-started/introduction.md`<br>`getting-started/quickstart.md`<br>`usage/cli.md`<br>`usage/config.md` | Prefer workflow-oriented examples and keep screenshots or terminal snippets aligned with the latest UI or CLI behavior. |
|
||||
| Developer Guide | Yes | Yes | Seeded from current codebase and existing docs. | `api/auth.md`<br>`api/endpoints.md`<br>`api/errors.md`<br>`api/overview.md`<br>`development/code-structure.md`<br>`development/contributing.md`<br>`development/dev-setup.md`<br>`development/testing.md` | Keep setup and test commands tied to actual package scripts, Make targets, or language toolchains in this repository. |
|
||||
| Vibe Coding Reference | Yes | Yes | Seeded from current codebase and existing docs. | `api/auth.md`<br>`api/endpoints.md`<br>`api/errors.md`<br>`api/overview.md`<br>`zh/api/auth.md`<br>`zh/api/endpoints.md`<br>`zh/api/errors.md`<br>`zh/api/overview.md` | Review prompt templates and repo rules whenever the project adds new subsystems, protected areas, or mandatory verification steps. |
|
||||
103
docs/README.md
103
docs/README.md
@ -1,75 +1,42 @@
|
||||
# Documentation
|
||||
# Console Service Plus / 控制台服务
|
||||
|
||||
This directory follows a standard open-source documentation layout and mirrors the code organization of `console.svc.plus`.
|
||||
This `docs/` directory now has a bilingual canonical layer for the current repository state.
|
||||
|
||||
## Structure
|
||||
本 `docs/` 目录现已补齐双语规范层,用于承接当前仓库状态下的核心文档。
|
||||
|
||||
- `getting-started/` — new user path to get running quickly.
|
||||
- `architecture/` — system design, boundaries, and decisions.
|
||||
- `usage/` — configuration and how-to guides.
|
||||
- `api/` — service API references.
|
||||
- `integrations/` — external systems and providers.
|
||||
- `advanced/` — performance, security, scalability, customization.
|
||||
- `development/` — contributor guides and local setup.
|
||||
- `operations/` — logging, monitoring, troubleshooting, runbooks.
|
||||
- `governance/` — license, security policy, release process.
|
||||
- `appendix/` — FAQ, glossary, references.
|
||||
## Quick Entry / 快速入口
|
||||
|
||||
## Codebase Mapping
|
||||
- Coverage checklist / 覆盖检查矩阵: `docs/DOC_COVERAGE.md`
|
||||
- English index / 英文入口: `docs/en/README.md`
|
||||
- 中文入口 / Chinese index: `docs/zh/README.md`
|
||||
|
||||
- App layer (Next.js): `src/app`, `src/components`, `src/lib`, `src/state`, `src/modules`
|
||||
- Library layer (vendored): `packages/neurapress`
|
||||
- Build/runtime glue: `scripts`, `config`, `public`
|
||||
## Canonical Bilingual Pages / 双语规范页
|
||||
|
||||
## Index
|
||||
- `docs/en/architecture.md` / `docs/zh/architecture.md`
|
||||
- `docs/en/design.md` / `docs/zh/design.md`
|
||||
- `docs/en/deployment.md` / `docs/zh/deployment.md`
|
||||
- `docs/en/user-guide.md` / `docs/zh/user-guide.md`
|
||||
- `docs/en/developer-guide.md` / `docs/zh/developer-guide.md`
|
||||
- `docs/en/vibe-coding-reference.md` / `docs/zh/vibe-coding-reference.md`
|
||||
|
||||
- Getting Started
|
||||
- `getting-started/introduction.md`
|
||||
- `getting-started/quickstart.md`
|
||||
- `getting-started/installation.md`
|
||||
- `getting-started/concepts.md`
|
||||
- Architecture
|
||||
- `architecture/overview.md`
|
||||
- `architecture/components.md`
|
||||
- `architecture/design-decisions.md`
|
||||
- `architecture/roadmap.md`
|
||||
- Usage
|
||||
- `usage/cli.md`
|
||||
- `usage/config.md`
|
||||
- `usage/deployment.md`
|
||||
- `usage/examples.md`
|
||||
- API
|
||||
- `api/overview.md`
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- Integrations
|
||||
- `integrations/databases.md`
|
||||
- `integrations/cloud.md`
|
||||
- `integrations/cloudflare-web-analytics.md`
|
||||
- `integrations/ai-providers.md`
|
||||
- Advanced
|
||||
- `advanced/performance.md`
|
||||
- `advanced/security.md`
|
||||
- `advanced/scalability.md`
|
||||
- `advanced/customization.md`
|
||||
- Development
|
||||
- `development/contributing.md`
|
||||
- `development/dev-setup.md`
|
||||
- `development/testing.md`
|
||||
- `development/code-structure.md`
|
||||
- Operations
|
||||
- `operations/logging.md`
|
||||
- `operations/monitoring.md`
|
||||
- `operations/backup.md`
|
||||
- `operations/troubleshooting.md`
|
||||
- `operations/runbooks/README.md`
|
||||
- `operations/runbooks/rag-server.md`
|
||||
- Governance
|
||||
- `governance/license.md`
|
||||
- `governance/security-policy.md`
|
||||
- `governance/release-process.md`
|
||||
- Appendix
|
||||
- `appendix/faq.md`
|
||||
- `appendix/glossary.md`
|
||||
- `appendix/references.md`
|
||||
## Current Repo Context / 当前仓库背景
|
||||
|
||||
- Root README: `console.svc.plus`
|
||||
- Previous docs index: `Documentation`
|
||||
- Manifest evidence / 构建清单: package.json (`dashboard`)
|
||||
- Active code and ops directories / 当前主要目录: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
|
||||
## Existing Docs To Reconcile / 需要继续归并的现有文档
|
||||
|
||||
- `SEO-AUDIT-REPORT.md`
|
||||
- `SEO-WORK-SUMMARY.md`
|
||||
- `advanced/customization.md`
|
||||
- `advanced/performance.md`
|
||||
- `advanced/scalability.md`
|
||||
- `advanced/security.md`
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- `api/overview.md`
|
||||
- `appendix/faq.md`
|
||||
- `appendix/glossary.md`
|
||||
|
||||
@ -214,7 +214,7 @@ export default function NotFound() {
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL('https://console.svc.plus'),
|
||||
metadataBase: new URL('https://www.svc.plus'),
|
||||
title: {
|
||||
default: 'Cloud-Neutral | Unified Cloud Native Tools',
|
||||
template: '%s | Cloud-Neutral',
|
||||
@ -232,7 +232,7 @@ export const metadata: Metadata = {
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
locale: 'en_US',
|
||||
url: 'https://console.svc.plus',
|
||||
url: 'https://www.svc.plus',
|
||||
title: 'Cloud-Neutral | Unified Cloud Native Tools',
|
||||
description: 'Unified tools for your cloud native stack',
|
||||
siteName: 'Cloud-Neutral',
|
||||
@ -274,7 +274,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#6366f1" />
|
||||
<link rel="canonical" href="https://console.svc.plus" />
|
||||
<link rel="canonical" href="https://www.svc.plus" />
|
||||
{/* ... rest of head */}
|
||||
</head>
|
||||
{/* ... rest of layout */}
|
||||
@ -343,7 +343,7 @@ Disallow: /admin/
|
||||
Disallow: /api/
|
||||
Disallow: /internal/
|
||||
|
||||
Sitemap: https://console.svc.plus/sitemap.xml
|
||||
Sitemap: https://www.svc.plus/sitemap.xml
|
||||
```
|
||||
|
||||
---
|
||||
@ -360,11 +360,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Organization',
|
||||
name: 'Cloud-Neutral',
|
||||
url: 'https://console.svc.plus',
|
||||
logo: 'https://console.svc.plus/logo.png',
|
||||
url: 'https://www.svc.plus',
|
||||
logo: 'https://www.svc.plus/logo.png',
|
||||
sameAs: [
|
||||
'https://twitter.com/cloudneutral',
|
||||
'https://github.com/cloud-neutral-toolkit',
|
||||
'https://github.com/x-evor',
|
||||
],
|
||||
}
|
||||
|
||||
@ -372,10 +372,10 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebSite',
|
||||
name: 'Cloud-Neutral',
|
||||
url: 'https://console.svc.plus',
|
||||
url: 'https://www.svc.plus',
|
||||
potentialAction: {
|
||||
'@type': 'SearchAction',
|
||||
target: 'https://console.svc.plus/search?q={search_term_string}',
|
||||
target: 'https://www.svc.plus/search?q={search_term_string}',
|
||||
'query-input': 'required name=search_term_string',
|
||||
},
|
||||
}
|
||||
|
||||
96
docs/architecture/web-console/overview.md
Normal file
96
docs/architecture/web-console/overview.md
Normal file
@ -0,0 +1,96 @@
|
||||
# console.svc.plus Web Console Architecture
|
||||
|
||||
## Scope
|
||||
|
||||
`console.svc.plus` is the browser-facing control plane. It is a Next.js App Router application that combines public pages, docs browsing, account/admin panels, and a BFF layer that forwards requests to downstream services. It never reads PostgreSQL or Prometheus directly for billing or usage.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Pages["src/app pages"]
|
||||
Root["/ -> landing page"]
|
||||
Docs["/docs, /docs/[collection], /docs/[collection]/[...slug]\nDocs reader"]
|
||||
Auth["/login, /register, /email-verification, /logout\nAuth flows"]
|
||||
Panel["/panel/*\nUser / admin console"]
|
||||
Tools["/editor/*, /download/*, /cloud_iac/*, /xworkmate/*\nProduct tools"]
|
||||
Content["/blogs/*, /services/*, /support/*, /prices, /about, /privacy, /terms, /[slug]"]
|
||||
Admin["/dashboard/cms\nCMS/admin entry"]
|
||||
end
|
||||
|
||||
subgraph BFF["src/app/api route handlers"]
|
||||
AuthAPI["/api/auth/*"]
|
||||
AdminAPI["/api/admin/*"]
|
||||
AgentAPI["/api/agent-server/[...segments]\n/api/agent/[...segments]"]
|
||||
RagAPI["/api/rag/query\n/api/askai"]
|
||||
UtilAPI["/api/users\n/api/ping\n/api/content-meta\n/api/render-markdown\n/api/dl-index/*\n/api/marketing/home-stats\n/api/integrations/*\n/api/moltbot/chat\n/api/openclaw/assistant\n/api/task/[...segments]\n/api/xworkmate/profile"]
|
||||
GuestAPI["/api/guest/*"]
|
||||
end
|
||||
|
||||
Accounts["accounts.svc.plus"]
|
||||
Rag["rag-server.svc.plus"]
|
||||
DocsSvc["docs.svc.plus"]
|
||||
Grafana["observability.svc.plus / Grafana"]
|
||||
External["Other upstream services"]
|
||||
Subscription["/panel/subscription\nUsage / billing panel"]
|
||||
|
||||
AuthAPI --> Accounts
|
||||
AdminAPI --> Accounts
|
||||
AgentAPI --> Accounts
|
||||
RagAPI --> Rag
|
||||
UtilAPI --> DocsSvc
|
||||
UtilAPI --> External
|
||||
SandboxAPI --> Accounts
|
||||
Subscription --> Accounts
|
||||
Subscription -.-> Grafana
|
||||
```
|
||||
|
||||
## Frontend Routes
|
||||
|
||||
| Route family | Path | Purpose |
|
||||
| --- | --- | --- |
|
||||
| Home | `/` | Public landing page and site entry |
|
||||
| Docs | `/docs`, `/docs/[collection]`, `/docs/[collection]/[...slug]` | Documentation reader, sidebar, and TOC |
|
||||
| Auth | `/login`, `/register`, `/email-verification`, `/logout` | Sign in / sign up / email verification / session cleanup |
|
||||
| Panel | `/panel`, `/panel/account`, `/panel/agent`, `/panel/api`, `/panel/appearance`, `/panel/ldp`, `/panel/management`, `/panel/subscription`, `/panel/[...segments]` | Signed-in account and admin console |
|
||||
| Tools | `/editor`, `/editor/wechat`, `/editor/xiaohongshu`, `/download`, `/download/[...segments]`, `/cloud_iac`, `/cloud_iac/[provider]`, `/cloud_iac/[provider]/[service]`, `/xworkmate`, `/xworkmate/admin`, `/xworkmate/integrations` | Product tools and service explorers |
|
||||
| Content | `/blogs`, `/blogs/[...slug]`, `/services`, `/services/openclaw`, `/services/insight`, `/support`, `/support/discussions`, `/about`, `/prices`, `/privacy`, `/terms`, `/[slug]` | Marketing / informational pages |
|
||||
| Admin / CMS | `/dashboard/cms` | CMS or content-management entry |
|
||||
| Error pages | `/404`, `/500` | Static error surfaces |
|
||||
|
||||
## BFF / API Routes
|
||||
|
||||
| API family | Path | Purpose | Upstream target |
|
||||
| --- | --- | --- | --- |
|
||||
| Auth | `/api/auth/login`, `/api/auth/register`, `/api/auth/register/send`, `/api/auth/register/verify`, `/api/auth/verify-email`, `/api/auth/verify-email/send`, `/api/auth/session`, `/api/auth/token/exchange` | Login, registration, token exchange, session lookup | `accounts.svc.plus/api/auth/*` |
|
||||
| MFA | `/api/auth/mfa/status`, `/api/auth/mfa/setup`, `/api/auth/mfa/verify`, `/api/auth/mfa/disable` | TOTP setup and verification | `accounts.svc.plus/api/auth/*` |
|
||||
| OAuth / billing | `/api/auth/oauth/login/[provider]`, `/api/auth/stripe/checkout`, `/api/auth/stripe/portal`, `/api/auth/subscriptions`, `/api/auth/subscriptions/cancel` | OAuth redirects and billing actions | `accounts.svc.plus/api/auth/*` |
|
||||
| Admin | `/api/admin/settings`, `/api/admin/homepage-video`, `/api/admin/users/*`, `/api/admin/blacklist/*` | Account admin operations | `accounts.svc.plus/api/*` |
|
||||
| Agent bridge | `/api/agent-server/[...segments]`, `/api/agent/[...segments]` | Agent registry/status and legacy alias | `accounts.svc.plus` |
|
||||
| RAG | `/api/rag/query`, `/api/askai` | Retrieval and answer generation | `rag-server.svc.plus` |
|
||||
| Guest / demo runtime | `/api/guest/binding` | Guest read-only node resolution for demo access | `accounts.svc.plus/api/sandbox/binding` |
|
||||
| Content / docs | `/api/content-meta`, `/api/render-markdown`, `/api/blogs/latest`, `/api/dl-index/*` | Docs/content rendering and download manifests | docs / CDN / download service |
|
||||
| Integrations | `/api/integrations/defaults`, `/api/integrations/probe`, `/api/marketing/home-stats` | Integration defaults, health probes, marketing metrics | config-dependent external services |
|
||||
| Misc | `/api/ping`, `/api/users`, `/api/xworkmate/profile`, `/api/task/[...segments]`, `/api/openclaw/assistant`, `/api/moltbot/chat`, `/api/render-markdown` | Health, user lookup, profile, task and assistant proxies | `accounts.svc.plus`, internal API, task services |
|
||||
|
||||
## Auth and Session Notes
|
||||
|
||||
- Browser calls use the session cookie and BFF logic in `src/server/account/session.ts`.
|
||||
- Service-to-service calls use `INTERNAL_SERVICE_TOKEN` when configured.
|
||||
- `api/agent-server/[...segments]` keeps caller `Authorization` untouched when an agent token is already present.
|
||||
- `api/agent-server/[...segments]` forwards the dashboard session token for browser-driven calls.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `accounts.svc.plus` for identity, profile, sandbox, billing, and admin actions.
|
||||
- `accounts.svc.plus` for authoritative usage and billing summaries sourced from PostgreSQL.
|
||||
- `rag-server.svc.plus` for RAG query and AskAI.
|
||||
- `docs.svc.plus` for docs content and navigation data.
|
||||
- `observability.svc.plus` for Grafana dashboards and operational views only.
|
||||
- CDN / external providers for content, analytics, and integration checks.
|
||||
|
||||
## Notes
|
||||
|
||||
- Route groups in parentheses, such as `(auth)`, are Next.js organizational folders and do not appear in the public URL.
|
||||
- The BFF layer is the main place where console-specific auth shaping, cookie management, and upstream proxying happen.
|
||||
- The subscription panel displays usage and billing data from accounts only and treats Grafana as an embedded observability surface, not a billing source.
|
||||
34
docs/en/README.md
Normal file
34
docs/en/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Console Service Plus Documentation
|
||||
|
||||
This repository primarily delivers a web frontend experience and should document product flows, UI boundaries, and integration touchpoints.
|
||||
|
||||
## Current state snapshot
|
||||
|
||||
- Root README title: `console.svc.plus`
|
||||
- Build/runtime evidence: package.json (`dashboard`)
|
||||
- Primary directories detected: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- Existing docs count: 86
|
||||
|
||||
## Canonical pages
|
||||
|
||||
- [Architecture](architecture.md)
|
||||
- [Design](design.md)
|
||||
- [Deployment](deployment.md)
|
||||
- [User Guide](user-guide.md)
|
||||
- [Developer Guide](developer-guide.md)
|
||||
- [Vibe Coding Reference](vibe-coding-reference.md)
|
||||
|
||||
## Legacy docs to fold in
|
||||
|
||||
- `SEO-AUDIT-REPORT.md`
|
||||
- `SEO-WORK-SUMMARY.md`
|
||||
- `advanced/customization.md`
|
||||
- `advanced/performance.md`
|
||||
- `advanced/scalability.md`
|
||||
- `advanced/security.md`
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- `api/overview.md`
|
||||
- `appendix/faq.md`
|
||||
- `appendix/glossary.md`
|
||||
31
docs/en/architecture.md
Normal file
31
docs/en/architecture.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Architecture
|
||||
|
||||
This repository primarily delivers a web frontend experience and should document product flows, UI boundaries, and integration touchpoints.
|
||||
|
||||
Use this page as the canonical bilingual overview of system boundaries, major components, and repo ownership.
|
||||
|
||||
## Current code-aligned notes
|
||||
|
||||
- Documentation target: `console.svc.plus`
|
||||
- Repo kind: `frontend`
|
||||
- Manifest and build evidence: package.json (`dashboard`)
|
||||
- Primary implementation and ops directories: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- Package scripts snapshot: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## Existing docs to reconcile
|
||||
|
||||
- `api/overview.md`
|
||||
- `architecture/components.md`
|
||||
- `architecture/design-decisions.md`
|
||||
- `architecture/overview.md`
|
||||
- `architecture/roadmap.md`
|
||||
- `development/code-structure.md`
|
||||
- `zh/api/overview.md`
|
||||
- `zh/architecture/components.md`
|
||||
|
||||
## What this page should cover next
|
||||
|
||||
- Describe the current implementation rather than an aspirational future-only design.
|
||||
- Keep terminology aligned with the repository root README, manifests, and actual directories.
|
||||
- Link deeper runbooks, specs, or subsystem notes from the legacy docs listed above.
|
||||
- Keep diagrams and ownership notes synchronized with actual directories, services, and integration dependencies.
|
||||
42
docs/en/deployment.md
Normal file
42
docs/en/deployment.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Deployment
|
||||
|
||||
## Production Baseline
|
||||
|
||||
- Runtime: `Caddy + Docker Compose`
|
||||
- Deploy host: `root@jp-xhttp-contabo.svc.plus`
|
||||
- Public domains:
|
||||
- `www.svc.plus`
|
||||
- `console.svc.plus`
|
||||
- Canonical public origin: `https://www.svc.plus`
|
||||
- Frontend release workflow: `.github/workflows/pipeline.yaml`
|
||||
|
||||
## Operating Model
|
||||
|
||||
The frontend is built in GitHub Actions and shipped as a prebuilt `linux/amd64` image. The host only pulls the image and starts containers; it does not build locally.
|
||||
|
||||
`yarn prebuild` now generates only console-owned marketing artifacts. `/docs` and `/blogs` no longer bundle `knowledge/` or synced markdown content into the frontend image. Those routes fetch rendered content from `docs.svc.plus` at request time through the server-side `docsServiceClient`.
|
||||
|
||||
The stack is static-first:
|
||||
|
||||
- Caddy serves `/_next/static/*` and public assets from a shared read-only volume.
|
||||
- The Next.js standalone container serves dynamic HTML, auth endpoints, and API proxy routes. Static assets and hashed CSS/JS files are extracted by the `frontend-assets` helper task, so the runtime no longer needs to compile anything on the single-node host.
|
||||
- `docs.svc.plus` is the source of truth for rendered docs/blog pages; the browser does not call it directly.
|
||||
|
||||
Releases are orchestrated through `.github/workflows/pipeline.yaml`. That workflow builds/pushes the image, renders `.env.runtime` including `DOCS_SERVICE_URL` / `DOCS_SERVICE_INTERNAL_URL`, and ships `docker-compose.yml`, `Caddyfile`, and the runtime env file to the host. The control-plane DNS automation then updates Cloudflare DNS for the release domains (via `scripts/github-actions/update-release-dns.sh`) so both `www.svc.plus` and `console.svc.plus` resolve to the same environment.
|
||||
|
||||
The release contract now uses:
|
||||
|
||||
- `CANONICAL_DOMAIN=www.svc.plus`
|
||||
- `SERVED_DOMAINS=www.svc.plus,console.svc.plus`
|
||||
|
||||
Validation must pass for both domains. A release is incomplete if either host serves a different runtime version, static asset family, or `dashboardUrl`.
|
||||
|
||||
This baseline is intentional for the weak-IO single-node host `root@jp-xhttp-contabo.svc.plus`. No images are built on the target machine, keeping the deployment lightweight: the host only logs into GHCR, pulls the `dashboard` image, extracts assets into `frontend_static`, and starts `dashboard` plus `caddy` containers via `docker compose`.
|
||||
|
||||
`docs.svc.plus` is now the dedicated docs/blog service for the frontend delivery path.
|
||||
|
||||
## Related Docs
|
||||
|
||||
- `usage/deployment.md`
|
||||
- `governance/release-process.md`
|
||||
- `development/dev-setup.md`
|
||||
27
docs/en/design.md
Normal file
27
docs/en/design.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Design
|
||||
|
||||
This repository primarily delivers a web frontend experience and should document product flows, UI boundaries, and integration touchpoints.
|
||||
|
||||
Use this page to consolidate design decisions, ADR-style tradeoffs, and roadmap-sensitive implementation notes.
|
||||
|
||||
## Current code-aligned notes
|
||||
|
||||
- Documentation target: `console.svc.plus`
|
||||
- Repo kind: `frontend`
|
||||
- Manifest and build evidence: package.json (`dashboard`)
|
||||
- Primary implementation and ops directories: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- Package scripts snapshot: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## Existing docs to reconcile
|
||||
|
||||
- `SEO-WORK-SUMMARY.md`
|
||||
- `architecture/design-decisions.md`
|
||||
- `zh/SEO-WORK-SUMMARY.md`
|
||||
- `zh/architecture/design-decisions.md`
|
||||
|
||||
## What this page should cover next
|
||||
|
||||
- Describe the current implementation rather than an aspirational future-only design.
|
||||
- Keep terminology aligned with the repository root README, manifests, and actual directories.
|
||||
- Link deeper runbooks, specs, or subsystem notes from the legacy docs listed above.
|
||||
- Promote one-off implementation notes into reusable design records when behavior, APIs, or deployment contracts change.
|
||||
31
docs/en/developer-guide.md
Normal file
31
docs/en/developer-guide.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Developer Guide
|
||||
|
||||
This repository primarily delivers a web frontend experience and should document product flows, UI boundaries, and integration touchpoints.
|
||||
|
||||
Use this page to document local setup, project structure, test surfaces, and contribution conventions tied to the current codebase.
|
||||
|
||||
## Current code-aligned notes
|
||||
|
||||
- Documentation target: `console.svc.plus`
|
||||
- Repo kind: `frontend`
|
||||
- Manifest and build evidence: package.json (`dashboard`)
|
||||
- Primary implementation and ops directories: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- Package scripts snapshot: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## Existing docs to reconcile
|
||||
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- `api/overview.md`
|
||||
- `development/code-structure.md`
|
||||
- `development/contributing.md`
|
||||
- `development/dev-setup.md`
|
||||
- `development/testing.md`
|
||||
|
||||
## What this page should cover next
|
||||
|
||||
- Describe the current implementation rather than an aspirational future-only design.
|
||||
- Keep terminology aligned with the repository root README, manifests, and actual directories.
|
||||
- Link deeper runbooks, specs, or subsystem notes from the legacy docs listed above.
|
||||
- Keep setup and test commands tied to actual package scripts, Make targets, or language toolchains in this repository.
|
||||
31
docs/en/user-guide.md
Normal file
31
docs/en/user-guide.md
Normal file
@ -0,0 +1,31 @@
|
||||
# User Guide
|
||||
|
||||
This repository primarily delivers a web frontend experience and should document product flows, UI boundaries, and integration touchpoints.
|
||||
|
||||
Use this page to document primary user/operator tasks, everyday workflows, and navigation to existing how-to material.
|
||||
|
||||
## Current code-aligned notes
|
||||
|
||||
- Documentation target: `console.svc.plus`
|
||||
- Repo kind: `frontend`
|
||||
- Manifest and build evidence: package.json (`dashboard`)
|
||||
- Primary implementation and ops directories: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- Package scripts snapshot: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## Existing docs to reconcile
|
||||
|
||||
- `api/overview.md`
|
||||
- `architecture/overview.md`
|
||||
- `getting-started/concepts.md`
|
||||
- `getting-started/installation.md`
|
||||
- `getting-started/introduction.md`
|
||||
- `getting-started/quickstart.md`
|
||||
- `usage/cli.md`
|
||||
- `usage/config.md`
|
||||
|
||||
## What this page should cover next
|
||||
|
||||
- Describe the current implementation rather than an aspirational future-only design.
|
||||
- Keep terminology aligned with the repository root README, manifests, and actual directories.
|
||||
- Link deeper runbooks, specs, or subsystem notes from the legacy docs listed above.
|
||||
- Prefer workflow-oriented examples and keep screenshots or terminal snippets aligned with the latest UI or CLI behavior.
|
||||
31
docs/en/vibe-coding-reference.md
Normal file
31
docs/en/vibe-coding-reference.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Vibe Coding Reference
|
||||
|
||||
This repository primarily delivers a web frontend experience and should document product flows, UI boundaries, and integration touchpoints.
|
||||
|
||||
Use this page to align AI-assisted coding prompts, repo boundaries, safe edit rules, and documentation update expectations.
|
||||
|
||||
## Current code-aligned notes
|
||||
|
||||
- Documentation target: `console.svc.plus`
|
||||
- Repo kind: `frontend`
|
||||
- Manifest and build evidence: package.json (`dashboard`)
|
||||
- Primary implementation and ops directories: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- Package scripts snapshot: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## Existing docs to reconcile
|
||||
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- `api/overview.md`
|
||||
- `zh/api/auth.md`
|
||||
- `zh/api/endpoints.md`
|
||||
- `zh/api/errors.md`
|
||||
- `zh/api/overview.md`
|
||||
|
||||
## What this page should cover next
|
||||
|
||||
- Describe the current implementation rather than an aspirational future-only design.
|
||||
- Keep terminology aligned with the repository root README, manifests, and actual directories.
|
||||
- Link deeper runbooks, specs, or subsystem notes from the legacy docs listed above.
|
||||
- Review prompt templates and repo rules whenever the project adds new subsystems, protected areas, or mandatory verification steps.
|
||||
@ -2,8 +2,44 @@
|
||||
|
||||
## Purpose
|
||||
|
||||
- TODO: Add content specific to Installation.
|
||||
- Set up the local development environment for `console.svc.plus`.
|
||||
- Define the assistant and integrations defaults without hardcoding gateway values into the UI.
|
||||
|
||||
## Notes
|
||||
## Environment setup
|
||||
|
||||
- TODO: Link to related documents in this section.
|
||||
1. Copy the example file:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
2. Use `/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw-deploy-example/.env` as the reference source for deployment-aligned values when available.
|
||||
|
||||
## Assistant and integrations variables
|
||||
|
||||
These variables are read on the server side and used to prefill:
|
||||
|
||||
- the homepage AI assistant
|
||||
- the sidebar assistant dialog
|
||||
- the `/panel/api` integrations page
|
||||
|
||||
| Variable | Used by | Notes |
|
||||
|---|---|---|
|
||||
| `OPENCLAW_GATEWAY_REMOTE_URL` | OpenClaw assistant | Preferred remote WebSocket endpoint, for example `wss://openclaw.svc.plus:443` |
|
||||
| `OPENCLAW_GATEWAY_TOKEN` | OpenClaw assistant | Gateway token used by the server-side assistant bridge |
|
||||
| `VAULT_SERVER_URL` | Vault integration | Base Vault address for connectivity checks and defaults |
|
||||
| `VAULT_NAMESPACE` | Vault integration | Optional namespace when Vault Enterprise namespaces are used |
|
||||
| `VAULT_TOKEN` | Vault integration | Token used for Vault probe requests |
|
||||
| `APISIX_AI_GATEWAY_URL` | APISIX AI Gateway integration | Base HTTP(S) endpoint for AI gateway probing |
|
||||
| `AI_GATEWAY_ACCESS_TOKEN` | APISIX AI Gateway integration | Access token used for gateway probe requests |
|
||||
|
||||
## Behavior
|
||||
|
||||
- These values are not hardcoded into React components.
|
||||
- UI forms can still be overridden per request or per session when needed.
|
||||
- Empty values simply disable prefill; they do not break the page layout.
|
||||
|
||||
## Related documents
|
||||
|
||||
- `../README.md`
|
||||
- `../usage/config.md`
|
||||
|
||||
@ -1,9 +1,53 @@
|
||||
# Release Process
|
||||
|
||||
## Purpose
|
||||
This page tracks release summaries for published versions of the public web console served under `www.svc.plus` and `console.svc.plus`.
|
||||
|
||||
- TODO: Add content specific to Release Process.
|
||||
## Current Release
|
||||
|
||||
### v0.2
|
||||
|
||||
Release tag: `v0.2`
|
||||
Release branch: `release/v0.2`
|
||||
Published commit: `0fab89e`
|
||||
|
||||
#### Highlights
|
||||
|
||||
- Introduced the new XWorkmate workspace with a denser assistant layout, cleaner shell, and improved entry flow.
|
||||
- Added the OpenClaw assistant workspace and pairing bridge, including configurable origin override and more stable pairing fallback behavior.
|
||||
- Unified navigation and AI entry points with a persistent assistant sidebar and refined panel routing.
|
||||
- Added the latest blog shortcuts on the homepage and improved guest and registration messaging.
|
||||
- Expanded docs with bilingual structure updates, stronger OIDC guidance, and setup/readme cleanup.
|
||||
- Fixed build stability issues, including `next-mdx-remote` vulnerability-related build failures and Yarn dependency metadata alignment.
|
||||
|
||||
#### New Features
|
||||
|
||||
- Launched the XWorkmate workspace and polished its workspace entry and layout.
|
||||
- Added OpenClaw assistant integration, pairing bridge support, integration probe API, and integration defaults handling.
|
||||
- Added XScopeHub MCP visibility on the services page.
|
||||
- Displayed the latest 7 blog article titles in homepage shortcuts.
|
||||
|
||||
#### Improvements
|
||||
|
||||
- Split observability into a tri-view workspace and refined panel assistant routing.
|
||||
- Unified navigation structure and persistent AI sidebar behavior.
|
||||
- Improved login and registration flows by using server-resolved account service URLs.
|
||||
- Guest and demo access must not expose any backing account identity in public UI or session payloads.
|
||||
- Added vault-backed token lookup for integrations.
|
||||
|
||||
#### Docs And Setup
|
||||
|
||||
- Added bilingual docs coverage and restructured the docs entry points.
|
||||
- Rewrote the OIDC authentication guide with fuller setup instructions.
|
||||
- Updated setup guidance and simplified README structure.
|
||||
|
||||
#### Build And Dependency Fixes
|
||||
|
||||
- Updated and aligned `next-mdx-remote` usage for secure builds.
|
||||
- Removed conflicting npm lockfile state and aligned Yarn dependency metadata for reproducible builds.
|
||||
|
||||
## Notes
|
||||
|
||||
- TODO: Link to related documents in this section.
|
||||
- GitHub Release: `https://github.com/x-evor/console.svc.plus/releases/tag/v0.2`
|
||||
- Related docs: `docs/README.md`, `docs/en/README.md`, `docs/zh/README.md`
|
||||
- Release validation must verify both `www.svc.plus` and `console.svc.plus` against the same `releaseImageRef`, `releaseImageTag`, and `releaseCommit`.
|
||||
- `www.svc.plus` is the canonical public domain for metadata, sitemap, `dashboardUrl`, and shared links.
|
||||
|
||||
@ -48,7 +48,7 @@ CLOUDFLARE_WEB_ANALYTICS_SITE_TAG=
|
||||
|
||||
### 本地开发
|
||||
|
||||
写入 `console.svc.plus/.env.local`:
|
||||
写入当前前端仓库的 `.env.local`:
|
||||
|
||||
```bash
|
||||
CLOUDFLARE_API_TOKEN=...
|
||||
@ -58,7 +58,7 @@ CLOUDFLARE_WEB_ANALYTICS_SITE_TAG=...
|
||||
|
||||
### 线上部署
|
||||
|
||||
把同名变量写入 `console.svc.plus` 的部署环境(例如 Vercel/Cloud Run 的环境变量配置)。
|
||||
把同名变量写入前端部署环境。
|
||||
|
||||
> 注意:这些变量属于服务端密钥,不要暴露到 `NEXT_PUBLIC_*`。
|
||||
|
||||
@ -67,7 +67,7 @@ CLOUDFLARE_WEB_ANALYTICS_SITE_TAG=...
|
||||
部署后访问:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://console.svc.plus/api/marketing/home-stats
|
||||
curl -fsSL https://www.svc.plus/api/marketing/home-stats
|
||||
```
|
||||
|
||||
期望返回中 `visits.daily/weekly/monthly` 为数字(非 `null`)。
|
||||
@ -77,4 +77,3 @@ curl -fsSL https://console.svc.plus/api/marketing/home-stats
|
||||
1. token 权限是否包含 Analytics Read
|
||||
2. Account ID 是否与 siteTag 属于同一账号
|
||||
3. 环境变量是否已在当前运行实例生效(重启/重新部署后再测)
|
||||
|
||||
|
||||
@ -1,88 +1,244 @@
|
||||
# OIDC Authentication Configuration Guide
|
||||
|
||||
This guide describes how to configure GitHub and Google OIDC authentication for the Cloud Neutral Toolkit.
|
||||
This guide describes how to configure GitHub and Google OAuth login for the Cloud Neutral Toolkit, enabling any user to sign in with their own GitHub or Google account.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
||||
│ Browser │ │ www.svc.plus │ │accounts.svc.plus │
|
||||
│ (User) │ │ (Frontend) │ │ (Backend) │
|
||||
└──────┬───────┘ └────────┬─────────┘ └────────┬─────────┘
|
||||
│ 1. Click "Login │ │
|
||||
│ with GitHub" │ │
|
||||
│──────────────────────>│ │
|
||||
│ │ │
|
||||
│ 2. Redirect to │ │
|
||||
│ accounts /api/ │ │
|
||||
│ auth/oauth/login/ │ │
|
||||
│ github │ │
|
||||
│<──────────────────────│ │
|
||||
│ │ │
|
||||
│ 3. accounts redirects to GitHub/Google │
|
||||
│ with client_id & callback URL │
|
||||
│<────────────────────────────────────────────────│
|
||||
│ │ │
|
||||
│ 4. User authorizes │ │
|
||||
│ on GitHub/Google │ │
|
||||
│ │ │
|
||||
│ 5. GitHub/Google redirects back to │
|
||||
│ accounts /api/auth/oauth/callback/github │
|
||||
│─────────────────────────────────────────────────>
|
||||
│ │ │
|
||||
│ 6. accounts exchanges code for token, │
|
||||
│ creates/links user, redirects to console │
|
||||
│<────────────────────────────────────────────────│
|
||||
│ │ │
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Access to GitHub Developer Settings.
|
||||
- Access to Google Cloud Console.
|
||||
- Properly configured `accounts.svc.plus` and `console.svc.plus` services.
|
||||
- A GitHub account with access to **Settings > Developer Settings**
|
||||
- A Google account with access to [Google Cloud Console](https://console.cloud.google.com/)
|
||||
- Running `accounts.svc.plus` and the frontend served under `www.svc.plus` / `console.svc.plus`
|
||||
|
||||
---
|
||||
|
||||
## 1. GitHub Configuration
|
||||
## 1. GitHub OAuth App
|
||||
|
||||
### 1.1 Create GitHub OAuth App
|
||||
### 1.1 Create OAuth App
|
||||
|
||||
1. Log in to GitHub and go to **Settings** > **Developer Settings** > **OAuth Apps**.
|
||||
2. Click **New OAuth App**.
|
||||
3. **Application name**: e.g., `Cloud Neutral Console`
|
||||
4. **Homepage URL**: `https://console.svc.plus` (or your actual console domain)
|
||||
5. **Authorization callback URL**: `https://accounts.svc.plus/api/auth/oauth/callback/github`
|
||||
6. Click **Register application**.
|
||||
7. Copy the **Client ID**.
|
||||
8. Click **Generate a new client secret** and copy the **Client Secret**.
|
||||
1. Go to [GitHub Developer Settings > OAuth Apps](https://github.com/settings/developers)
|
||||
2. Click **"OAuth Apps"** tab, then **"New OAuth App"**
|
||||
3. Fill in the form:
|
||||
|
||||
### 1.2 Configure Environment Variables
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Application name** | `Cloud Neutral Console` |
|
||||
| **Homepage URL** | `https://www.svc.plus` |
|
||||
| **Authorization callback URL** | `https://accounts.svc.plus/api/auth/oauth/callback/github` |
|
||||
| **Enable Device Flow** | ☐ (unchecked) |
|
||||
|
||||
Set the following environment variables for **accounts.svc.plus**:
|
||||
4. Click **"Register application"**
|
||||
|
||||
```bash
|
||||
GITHUB_CLIENT_ID=your_github_client_id
|
||||
GITHUB_CLIENT_SECRET=your_github_client_secret
|
||||
# Optional: if you want to override the default callback
|
||||
# GITHUB_REDIRECT_URL=https://accounts.svc.plus/api/auth/oauth/callback/github
|
||||
### 1.2 Generate Client Secret
|
||||
|
||||
1. On the app detail page, copy the **Client ID** (displayed at the top)
|
||||
2. Click **"Generate a new client secret"**
|
||||
3. **Immediately copy the Client Secret** — it will only be shown once
|
||||
|
||||
### 1.3 Record Credentials
|
||||
|
||||
```
|
||||
GitHub Client ID: Ov23li...
|
||||
GitHub Client Secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Callback URL: https://accounts.svc.plus/api/auth/oauth/callback/github
|
||||
```
|
||||
|
||||
> ⚠️ **Security**: Never commit Client Secret to version control. Store it as an environment variable or in a secret manager.
|
||||
|
||||
### 1.4 GitHub OAuth Scopes
|
||||
|
||||
The OAuth App requests these scopes by default:
|
||||
- `user:email` — Read the user's email addresses (used for account binding)
|
||||
|
||||
No additional GitHub permissions are required.
|
||||
|
||||
---
|
||||
|
||||
## 2. Google OAuth Client ID
|
||||
|
||||
### 2.1 Configure OAuth Consent Screen
|
||||
|
||||
> This step is required before creating credentials. If already configured, skip to 2.2.
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Select or create a project
|
||||
3. Navigate to **APIs & Services > OAuth consent screen**
|
||||
4. Choose **External** user type (allows any Google user to sign in)
|
||||
5. Fill in the required fields:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **App name** | `Cloud Neutral Console` |
|
||||
| **User support email** | your email address |
|
||||
| **Developer contact email** | your email address |
|
||||
|
||||
6. Add scopes: `email`, `profile`, `openid`
|
||||
7. Click **Save and Continue** through the remaining steps
|
||||
8. Under **Publishing status**, click **"Publish App"** to move out of testing mode
|
||||
- In testing mode, only manually added test users can sign in
|
||||
|
||||
### 2.2 Create OAuth Client ID
|
||||
|
||||
1. Go to **APIs & Services > Credentials**
|
||||
2. Click **"Create Credentials" > "OAuth client ID"**
|
||||
3. Fill in the form:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Application type** | `Web application` |
|
||||
| **Name** | `Cloud Neutral Console` |
|
||||
| **Authorized JavaScript origins** | `https://www.svc.plus` |
|
||||
| **Authorized redirect URIs** | `https://accounts.svc.plus/api/auth/oauth/callback/google` |
|
||||
|
||||
4. Click **"Create"**
|
||||
5. Copy the **Client ID** and **Client Secret** from the popup
|
||||
|
||||
### 2.3 Record Credentials
|
||||
|
||||
```
|
||||
Google Client ID: xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
|
||||
Google Client Secret: GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
Callback URL: https://accounts.svc.plus/api/auth/oauth/callback/google
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Google Configuration
|
||||
|
||||
### 2.1 Create Google OAuth Client ID
|
||||
|
||||
1. Log in to [Google Cloud Console](https://console.cloud.google.com/).
|
||||
2. Select or create a project.
|
||||
3. Go to **APIs & Services** > **Credentials**.
|
||||
4. Click **Create Credentials** > **OAuth client ID**.
|
||||
5. **Application type**: `Web application`.
|
||||
6. **Name**: e.g., `Cloud Neutral Console`.
|
||||
7. **Authorized JavaScript origins**:
|
||||
- `https://console.svc.plus`
|
||||
8. **Authorized redirect URIs**:
|
||||
- `https://accounts.svc.plus/api/auth/oauth/callback/google`
|
||||
9. Click **Create**.
|
||||
10. Copy the **Client ID** and **Client Secret**.
|
||||
|
||||
### 2.2 Configure Environment Variables
|
||||
## 3. Backend Configuration (accounts.svc.plus)
|
||||
|
||||
Set the following environment variables for **accounts.svc.plus**:
|
||||
|
||||
```bash
|
||||
GOOGLE_CLIENT_ID=your_google_client_id
|
||||
GOOGLE_CLIENT_SECRET=your_google_client_secret
|
||||
# Optional: if you want to override the default callback
|
||||
# GOOGLE_REDIRECT_URL=https://accounts.svc.plus/api/auth/oauth/callback/google
|
||||
```
|
||||
# ── GitHub OAuth ──
|
||||
GITHUB_CLIENT_ID=<your_github_client_id>
|
||||
GITHUB_CLIENT_SECRET=<your_github_client_secret>
|
||||
|
||||
---
|
||||
# ── Google OAuth ──
|
||||
GOOGLE_CLIENT_ID=<your_google_client_id>
|
||||
GOOGLE_CLIENT_SECRET=<your_google_client_secret>
|
||||
|
||||
## 3. General OIDC Environment Variables
|
||||
|
||||
Ensure these are also set for **accounts.svc.plus**:
|
||||
|
||||
```bash
|
||||
# ── General OAuth ──
|
||||
OAUTH_REDIRECT_URL=https://accounts.svc.plus/api/auth/oauth/callback
|
||||
OAUTH_FRONTEND_URL=https://console.svc.plus
|
||||
OAUTH_FRONTEND_URL=https://www.svc.plus
|
||||
```
|
||||
|
||||
**Note**: The backend automatically appends `/{provider}` to `OAUTH_REDIRECT_URL` if a provider-specific redirect URL is not provided.
|
||||
These variables are referenced in `config/account.yaml`:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
oauth:
|
||||
redirectUrl: "${OAUTH_REDIRECT_URL}"
|
||||
frontendUrl: "${OAUTH_FRONTEND_URL:-https://www.svc.plus}"
|
||||
github:
|
||||
clientId: "${GITHUB_CLIENT_ID}"
|
||||
clientSecret: "${GITHUB_CLIENT_SECRET}"
|
||||
google:
|
||||
clientId: "${GOOGLE_CLIENT_ID}"
|
||||
clientSecret: "${GOOGLE_CLIENT_SECRET}"
|
||||
```
|
||||
|
||||
> **Note**: The backend automatically appends `/{provider}` to `OAUTH_REDIRECT_URL` (e.g. `.../callback/github`) if a provider-specific redirect URL is not set.
|
||||
|
||||
---
|
||||
|
||||
## 4. Frontend Configuration
|
||||
## 4. Frontend Configuration (`www.svc.plus` canonical, `console.svc.plus` secondary)
|
||||
|
||||
For **console.svc.plus**, ensure the following is set so it knows where to redirect for the initial OAuth step:
|
||||
The frontend resolves the accounts service URL **server-side** via `getAccountServiceBaseUrl()`, which reads:
|
||||
|
||||
```bash
|
||||
NEXT_PUBLIC_ACCOUNTS_SVC_URL=https://accounts.svc.plus
|
||||
# Set in accounts.svc.plus deployment environment
|
||||
ACCOUNT_SERVICE_URL=https://accounts.svc.plus
|
||||
```
|
||||
|
||||
If not set, the function falls back to a runtime default. **No `NEXT_PUBLIC_*` env var is needed** — the OAuth login URLs are constructed server-side and passed to the client components as props.
|
||||
|
||||
### OAuth Login URLs (auto-generated)
|
||||
|
||||
| Provider | Login URL |
|
||||
|---|---|
|
||||
| GitHub | `{accountServiceBaseUrl}/api/auth/oauth/login/github` |
|
||||
| Google | `{accountServiceBaseUrl}/api/auth/oauth/login/google` |
|
||||
|
||||
### OAuth Callback URLs (handled by accounts.svc.plus)
|
||||
|
||||
| Provider | Callback URL |
|
||||
|---|---|
|
||||
| GitHub | `https://accounts.svc.plus/api/auth/oauth/callback/github` |
|
||||
| Google | `https://accounts.svc.plus/api/auth/oauth/callback/google` |
|
||||
|
||||
---
|
||||
|
||||
## 5. Troubleshooting
|
||||
|
||||
### `undefined/api/auth/oauth/login/github`
|
||||
|
||||
**Cause**: OAuth URLs were using a client-side env var (`NEXT_PUBLIC_ACCOUNTS_SVC_URL`) that was not set.
|
||||
|
||||
**Fix** (applied in commit `4ce4147`): OAuth URLs now use the server-resolved `accountServiceBaseUrl` prop.
|
||||
|
||||
### OAuth login redirects to wrong domain
|
||||
|
||||
Check that `OAUTH_FRONTEND_URL` in accounts.svc.plus matches the canonical public domain where users should be redirected after authentication. The current default is `https://www.svc.plus`.
|
||||
|
||||
### Google "Access blocked: This app's request is invalid"
|
||||
|
||||
Ensure the **Authorized redirect URI** in Google Cloud Console **exactly** matches:
|
||||
```
|
||||
https://accounts.svc.plus/api/auth/oauth/callback/google
|
||||
```
|
||||
Trailing slashes or mismatched protocols will cause this error.
|
||||
|
||||
### GitHub "The redirect_uri MUST match the registered callback URL"
|
||||
|
||||
Ensure the **Authorization callback URL** in GitHub Developer Settings **exactly** matches:
|
||||
```
|
||||
https://accounts.svc.plus/api/auth/oauth/callback/github
|
||||
```
|
||||
|
||||
### Google OAuth in "Testing" mode — only test users can sign in
|
||||
|
||||
Go to **OAuth consent screen > Publishing status** and click **"Publish App"** to allow any Google user to sign in.
|
||||
|
||||
---
|
||||
|
||||
## 6. Quick Reference
|
||||
|
||||
| Item | Value |
|
||||
|---|---|
|
||||
| GitHub OAuth App Settings | https://github.com/settings/developers |
|
||||
| Google Cloud Credentials | https://console.cloud.google.com/apis/credentials |
|
||||
| GitHub Callback URL | `https://accounts.svc.plus/api/auth/oauth/callback/github` |
|
||||
| Google Callback URL | `https://accounts.svc.plus/api/auth/oauth/callback/google` |
|
||||
| Backend Config File | `accounts.svc.plus/config/account.yaml` |
|
||||
| Frontend URL Resolution | `getAccountServiceBaseUrl()` in `src/server/serviceConfig.ts` |
|
||||
|
||||
51
docs/integrations/stripe-billing.md
Normal file
51
docs/integrations/stripe-billing.md
Normal file
@ -0,0 +1,51 @@
|
||||
# Stripe Billing Integration
|
||||
|
||||
This console now routes all purchase entry points through Stripe:
|
||||
|
||||
- `/prices`
|
||||
- product detail pages
|
||||
- `/panel/subscription`
|
||||
|
||||
The browser only needs public Stripe `price_id` values. Secret keys stay in `accounts.svc.plus`.
|
||||
|
||||
## Required Environment Variables
|
||||
|
||||
Set these in `console.svc.plus`:
|
||||
|
||||
```bash
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_PAYGO=price_xxx
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSTREAM_SUBSCRIPTION=price_xxx
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_PAYGO=price_xxx
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XSCOPEHUB_SUBSCRIPTION=price_xxx
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_PAYGO=price_xxx
|
||||
NEXT_PUBLIC_STRIPE_PRICE_XCLOUDFLOW_SUBSCRIPTION=price_xxx
|
||||
```
|
||||
|
||||
If a value is missing, the related purchase button stays visible but reports that Stripe pricing is not configured.
|
||||
|
||||
## Local Integration Checklist
|
||||
|
||||
1. Configure all `NEXT_PUBLIC_STRIPE_PRICE_*` values with Stripe test-mode `price_...` ids.
|
||||
2. Start `accounts.svc.plus` with Stripe server-side settings.
|
||||
3. Start this console with `yarn dev`.
|
||||
4. Sign in with a normal user account.
|
||||
5. Open `/prices` or `/panel/subscription` and start checkout.
|
||||
6. Complete a Stripe test payment.
|
||||
7. Confirm the browser returns to `/panel/subscription?checkout=success...`.
|
||||
8. Confirm the subscription record appears in the subscription panel.
|
||||
9. Open "Manage Stripe billing" and confirm the customer portal opens.
|
||||
|
||||
## Expected Flow
|
||||
|
||||
1. The console calls `/api/auth/stripe/checkout`.
|
||||
2. The BFF proxies the request to `accounts.svc.plus` using the current account session.
|
||||
3. `accounts.svc.plus` creates the Stripe Checkout Session.
|
||||
4. Stripe redirects back to the console.
|
||||
5. Stripe webhooks update the account service subscription record.
|
||||
6. The console reads the final state from `/api/auth/subscriptions`.
|
||||
|
||||
## Notes
|
||||
|
||||
- The console does not store Stripe secret keys.
|
||||
- Sensitive payment methods such as crypto QR flows are intentionally removed from the purchase UI.
|
||||
- Use Stripe test mode first; do not validate this flow against live prices until webhook delivery is confirmed.
|
||||
@ -16,7 +16,7 @@
|
||||
- **区域**: asia-northeast1
|
||||
- **项目 ID**: xzerolab-480008
|
||||
- **服务 URL**: https://rag-server-svc-plus-266500572462.asia-northeast1.run.app
|
||||
- **代码仓库**: https://github.com/cloud-neutral-toolkit/rag-server.svc.plus
|
||||
- **代码仓库**: https://github.com/x-evor/rag-server.svc.plus
|
||||
|
||||
### 服务功能
|
||||
RAG (Retrieval-Augmented Generation) 服务器提供以下功能:
|
||||
@ -68,7 +68,7 @@ rag-server.svc.plus/
|
||||
#### 1. 代码变更
|
||||
```bash
|
||||
# 克隆仓库
|
||||
git clone https://github.com/cloud-neutral-toolkit/rag-server.svc.plus.git
|
||||
git clone https://github.com/x-evor/rag-server.svc.plus.git
|
||||
cd rag-server.svc.plus
|
||||
|
||||
# 创建功能分支
|
||||
@ -407,7 +407,7 @@ gcloud run services update rag-server-svc-plus \
|
||||
- **紧急联系**: [电话]
|
||||
|
||||
### 相关链接
|
||||
- **GitHub**: https://github.com/cloud-neutral-toolkit/rag-server.svc.plus
|
||||
- **GitHub**: https://github.com/x-evor/rag-server.svc.plus
|
||||
- **Cloud Console**: https://console.cloud.google.com/run/detail/asia-northeast1/rag-server-svc-plus
|
||||
- **监控面板**: [Monitoring Dashboard URL]
|
||||
- **文档**: [Documentation URL]
|
||||
|
||||
281
docs/plans/2026-03-18-frontend-single-node-deploy.md
Normal file
281
docs/plans/2026-03-18-frontend-single-node-deploy.md
Normal file
@ -0,0 +1,281 @@
|
||||
# Console Frontend Single-Node Deployment Design
|
||||
|
||||
## Scope
|
||||
|
||||
- Repository: `console.svc.plus`
|
||||
- Target host: `root@cn-console.svc.plus`
|
||||
- Public domains:
|
||||
- `cn-console.svc.plus`
|
||||
- `cn-console.onwalk.net`
|
||||
- Delivery mode: `GitHub Actions + GHCR + Caddy + Docker Compose`
|
||||
|
||||
This document defines the deployment baseline for the China-facing frontend node. The source of truth is this upstream repository. The control-plane repository may consume the repo through git submodule, but should not become the primary place where this deployment design lives.
|
||||
|
||||
## Objective
|
||||
|
||||
Provide an independent frontend deployment pipeline for `console.svc.plus` that fits the current host constraints:
|
||||
|
||||
- the host IO is weak
|
||||
- the host must not build Docker images locally
|
||||
- the frontend should run in a static-first mode where possible
|
||||
- deployment logic should stay in checked-in scripts, not be embedded in GitHub Actions YAML
|
||||
|
||||
The result should support repeatable releases, quick rollback by image tag, and minimal work on the target machine.
|
||||
|
||||
## Constraints
|
||||
|
||||
### Host constraints
|
||||
|
||||
- `cn-console.svc.plus` is a single-node host
|
||||
- deployment user is `root`
|
||||
- local image build on the host is explicitly disallowed
|
||||
- IO pressure should be minimized during release
|
||||
|
||||
### Application constraints
|
||||
|
||||
- `console.svc.plus` is not a purely static site
|
||||
- auth routes, same-origin API proxy routes, and selected dynamic pages still require a running Next.js server
|
||||
- some `NEXT_PUBLIC_*` variables are compiled into the frontend bundle at image build time
|
||||
- `prebuild` pulls documentation and `knowledge` content, so CI must prepare those inputs before building the image
|
||||
|
||||
### Repository constraints
|
||||
|
||||
- workflow YAML should remain orchestration-only
|
||||
- service-local operational notes should remain in this repo
|
||||
- downstream control repos can reference this repo through submodule updates after upstream changes are pushed
|
||||
|
||||
## Recommended Topology
|
||||
|
||||
### 1. CI build on GitHub Actions
|
||||
|
||||
The workflow builds a single `linux/amd64` image in GitHub Actions and pushes it to GHCR.
|
||||
|
||||
Reasons:
|
||||
|
||||
- matches the target host architecture
|
||||
- avoids multi-arch overhead for this single-node release path
|
||||
- avoids local host build IO and CPU pressure
|
||||
- keeps release artifacts immutable and rollback-friendly
|
||||
|
||||
### 2. Runtime on the host
|
||||
|
||||
Use `docker compose` with three services:
|
||||
|
||||
- `dashboard`: Next.js standalone runtime
|
||||
- `frontend-assets`: one-shot container that copies static files from the image into a Docker volume
|
||||
- `caddy`: TLS termination, redirect handling, static file serving, and reverse proxy
|
||||
|
||||
This keeps the host work limited to:
|
||||
|
||||
- image pull
|
||||
- asset extraction from the image
|
||||
- container restart
|
||||
|
||||
### 3. Static-first request flow
|
||||
|
||||
Caddy serves:
|
||||
|
||||
- `/_next/static/*`
|
||||
- checked-in `public/` assets
|
||||
|
||||
Next.js serves:
|
||||
|
||||
- HTML responses
|
||||
- `/api/*` routes
|
||||
- auth/session flows
|
||||
- dynamic pages that still depend on server runtime
|
||||
|
||||
This reduces repeat disk reads and network hops for the bulk of frontend traffic while preserving the dynamic behavior the app still needs.
|
||||
|
||||
## Build-Time vs Runtime Configuration
|
||||
|
||||
### Build-time config
|
||||
|
||||
These values must be available during Docker build because the frontend bundle reads them directly:
|
||||
|
||||
- `NEXT_PUBLIC_APP_BASE_URL`
|
||||
- `NEXT_PUBLIC_SITE_URL`
|
||||
- `NEXT_PUBLIC_LOGIN_URL`
|
||||
- `NEXT_PUBLIC_DOCS_BASE_URL`
|
||||
- `NEXT_PUBLIC_RUNTIME_ENVIRONMENT`
|
||||
- `NEXT_PUBLIC_RUNTIME_REGION`
|
||||
- `NEXT_PUBLIC_GISCUS_*`
|
||||
- `NEXT_PUBLIC_PAYPAL_CLIENT_ID`
|
||||
- `NEXT_PUBLIC_STRIPE_*`
|
||||
|
||||
These are injected in GitHub Actions as Docker build args.
|
||||
|
||||
### Runtime config
|
||||
|
||||
These values are rendered into `.env.runtime` and copied to the host:
|
||||
|
||||
- upstream service URLs such as `ACCOUNT_SERVICE_URL`
|
||||
- tokens used only on the server side
|
||||
- Cloudflare analytics credentials
|
||||
- internal service token
|
||||
- runtime hostname hints
|
||||
|
||||
This separation avoids rebuilding for purely server-side secret or endpoint changes when the public frontend bundle does not change.
|
||||
|
||||
## Knowledge and Docs Handling
|
||||
|
||||
Current decision:
|
||||
|
||||
- `knowledge/` is cloned during CI
|
||||
- the cloned content is included in the image build context
|
||||
- the built image contains the resulting content needed by the current frontend
|
||||
|
||||
Reason:
|
||||
|
||||
- `prebuild` depends on this material
|
||||
- the host should not fetch or generate content during deployment
|
||||
|
||||
Temporary nature:
|
||||
|
||||
- today the frontend still carries docs-related payload
|
||||
- later, when `docs.svc.plus` becomes an API/service, docs delivery should move out of the frontend image
|
||||
- that future change should reduce image size and simplify the runtime responsibilities of `console.svc.plus`
|
||||
|
||||
## Domain Handling
|
||||
|
||||
Primary domain:
|
||||
|
||||
- `cn-console.svc.plus`
|
||||
|
||||
Secondary domain:
|
||||
|
||||
- `cn-console.onwalk.net`
|
||||
|
||||
Current routing decision:
|
||||
|
||||
- Caddy accepts both domains
|
||||
- requests for `cn-console.onwalk.net` are redirected permanently to `cn-console.svc.plus`
|
||||
|
||||
Reason:
|
||||
|
||||
- avoid duplicate canonical origins
|
||||
- keep cookie and login behavior centered on one primary host
|
||||
- simplify SEO and observability interpretation
|
||||
|
||||
## Release Workflow
|
||||
|
||||
### Trigger
|
||||
|
||||
Independent workflow:
|
||||
|
||||
- `.github/workflows/service_release_frontend-deploy.yml`
|
||||
|
||||
### Steps
|
||||
|
||||
1. check out repository
|
||||
2. clone `knowledge`
|
||||
3. build and push `ghcr.io/<owner>/dashboard:<tag>`
|
||||
4. render `.env.runtime`
|
||||
5. upload compose/caddy/env files to the host
|
||||
6. log in to GHCR on the host
|
||||
7. pull the new image
|
||||
8. run `frontend-assets`
|
||||
9. start or refresh `dashboard` and `caddy`
|
||||
10. verify both domains
|
||||
|
||||
### Why separate from the existing image workflow
|
||||
|
||||
The existing image workflow is broader and oriented toward generic image publishing. This single-node frontend workflow needs tighter control over:
|
||||
|
||||
- build-time public env injection
|
||||
- production deployment sequencing
|
||||
- SSH-based single-host rollout
|
||||
- host-specific runtime file rendering
|
||||
|
||||
So the frontend release path should remain explicit and independent.
|
||||
|
||||
## Rollback Model
|
||||
|
||||
Rollback unit:
|
||||
|
||||
- image tag reference in `.env.runtime`
|
||||
|
||||
Rollback steps:
|
||||
|
||||
1. set `FRONTEND_IMAGE` to a previous known-good tag
|
||||
2. rerun `frontend-assets`
|
||||
3. restart `dashboard` and `caddy`
|
||||
4. verify `cn-console.svc.plus`
|
||||
|
||||
This avoids rebuilding and keeps rollback cheap on the weak-IO host.
|
||||
|
||||
## Security and Secret Handling
|
||||
|
||||
Secrets must not be committed to the repo. The workflow should consume:
|
||||
|
||||
- `SINGLE_NODE_VPS_SSH_PRIVATE_KEY`
|
||||
- service tokens
|
||||
- vault tokens
|
||||
- internal service token
|
||||
- optional Cloudflare credentials
|
||||
|
||||
Public defaults and non-secret values belong in checked-in examples or GitHub repository/environment variables. Secret-only values stay in GitHub Secrets and are rendered into the host runtime env during deployment.
|
||||
|
||||
## Operational Risks
|
||||
|
||||
### Risk 1: build-time public env mismatch
|
||||
|
||||
If GitHub environment variables are incomplete, the image may build successfully but the frontend can render wrong links or lose third-party integration IDs.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- keep `.env.example` aligned
|
||||
- document required GitHub `vars`
|
||||
- keep the build args list explicit
|
||||
|
||||
### Risk 2: image layout drift
|
||||
|
||||
If the Docker image no longer contains `/app/dashboard/static` or `/app/dashboard/public`, the `frontend-assets` step fails.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- keep asset extraction paths documented
|
||||
- update deploy scripts whenever Dockerfile output layout changes
|
||||
|
||||
### Risk 3: docs payload growth
|
||||
|
||||
Bundling docs and `knowledge` into the frontend image increases image size.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- accept it temporarily
|
||||
- revisit once `docs.svc.plus` is externalized
|
||||
|
||||
### Risk 4: single-node blast radius
|
||||
|
||||
The host handles both reverse proxy and app runtime. Misconfiguration affects the whole frontend surface.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- keep compose simple
|
||||
- keep Caddy config minimal
|
||||
- use image-tag rollback
|
||||
|
||||
## Future Follow-Up
|
||||
|
||||
### Near term
|
||||
|
||||
- populate required GitHub `vars` and `secrets`
|
||||
- run the workflow against `root@cn-console.svc.plus`
|
||||
- validate DNS, TLS, static assets, login flow, and upstream API proxy behavior
|
||||
|
||||
### Later
|
||||
|
||||
- move docs delivery out of the frontend image after `docs.svc.plus` is service/API based
|
||||
- consider splitting static assets to object storage or CDN if traffic grows
|
||||
- evaluate whether the host should keep only Caddy plus one app container, or whether docs can be removed entirely from this runtime
|
||||
|
||||
## Source of Truth Rule
|
||||
|
||||
For this deployment design:
|
||||
|
||||
- upstream repo source of truth: `console.svc.plus`
|
||||
- service-local design note location: `docs/plans/`
|
||||
- control-plane repo role: consume via git submodule after upstream commit is pushed
|
||||
|
||||
Do not move the primary design ownership to the control-plane repository.
|
||||
5
docs/plans/README.md
Normal file
5
docs/plans/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Plans
|
||||
|
||||
This directory stores service-local design notes and implementation plans for `console.svc.plus`.
|
||||
|
||||
The source of truth stays in this upstream repository. Control-plane repositories may reference these documents through git submodule updates after upstream changes are pushed.
|
||||
218
docs/ui-refactor-proposal.md
Normal file
218
docs/ui-refactor-proposal.md
Normal file
@ -0,0 +1,218 @@
|
||||
# UI 主题与风格重构方案
|
||||
|
||||
作为资深 Web UI 设计师和前端工程师,针对我们 SaaS 控制台当前的 Next.js + Tailwind CSS 架构,结合 WCAG 可访问性标准和跨端响应式需求,特制定此 UI 重构方案。方案旨在提升整体视觉一致性、深色模式的可访问性,并优化桌面与移动端的用户体验(特别是 iOS/Android 浏览器的触控和渲染差异)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 审查现有界面
|
||||
|
||||
在审查当前的界面代码(如 `tailwind.config.js`, `src/app/globals.css`, `src/components/theme/` 及 `Navbar.tsx`)后,我发现了以下改进点:
|
||||
|
||||
* **色彩硬编码与对比度**:在部分文件(如 `designTokens.ts` 和 `Navbar.tsx` 的内联类名)中仍然存在类似 `#3467e9`, `bg-[#f6f7f9]` 的硬编码颜色,这破坏了主题切换的完整性。同时,深色模式下的次级文本(如 `text-muted` `#cbd5f5`)在深色背景(`#0f172a`)上的对比度可能无法满足 WCAG AA 级 4.5:1 的标准。
|
||||
* **语义化不足**:`Navbar.tsx` 中的菜单项过度使用了 `<div>` 和普通的 `<a>` 标签,缺少 `<nav>`, `<ul>`, `<li>` 结构,并且缺乏管理下拉/折叠状态的 `aria-expanded` 属性。
|
||||
* **触控目标尺寸**:移动端的某些交互元素(如链接和图标按钮)没有保证至少 44px × 44px 的物理点击区域,这在 iOS/Android 设备上容易造成误触。
|
||||
* **深色模式层级**:深色模式主要依赖背景色区分层级(如 `surface-muted`),缺乏细微的边框(Border)或发光阴影(Glow/Shadow)来凸显浮动面板(如 Dropdown 菜单)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 定义设计系统 Token
|
||||
|
||||
我们需要收敛硬编码颜色,改用语义化的 CSS 变量(Token),并对深/浅色模式设定严格的对比度要求。
|
||||
|
||||
### 颜色 Token 规划
|
||||
|
||||
* **背景色**:
|
||||
* 浅色:纯白 `#ffffff` (Surface) 或极浅灰 `#f8fafc` (Background)。
|
||||
* 深色:避免纯黑,使用 `#0f172a` (Background) 和微亮的暗灰 `#1e293b` (Surface),减轻视觉疲劳。
|
||||
* **文本色**:
|
||||
* 主要文本 (`--color-text`):浅色模式 `#0f172a`,深色模式 `#f8fafc`。
|
||||
* 次要文本 (`--color-text-muted`):确保在深浅背景下对比度均大于 4.5:1。浅色推荐 `#475569`,深色推荐 `#94a3b8`。
|
||||
* **主色与交互色**:
|
||||
* `--color-primary`:统一使用高对比度的主题蓝(如 `#2563eb`),确保按钮上的白色文字(`--color-primary-foreground`)对比度达标。
|
||||
|
||||
### Tailwind / CSS 变量伪代码
|
||||
|
||||
```css
|
||||
/* src/app/globals.css 补充与覆盖 */
|
||||
:root {
|
||||
/* 基础结构色 */
|
||||
--bg-color: #f8fafc;
|
||||
--surface-color: #ffffff;
|
||||
/* 文本色 */
|
||||
--text-color: #0f172a;
|
||||
--secondary-color: #475569;
|
||||
/* 主色调 */
|
||||
--primary: #2563eb;
|
||||
--primary-foreground: #ffffff;
|
||||
/* 边框与分隔线 */
|
||||
--border-color: #e2e8f0;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"],
|
||||
.dark {
|
||||
--bg-color: #0f172a;
|
||||
--surface-color: #1e293b;
|
||||
--text-color: #f8fafc;
|
||||
--secondary-color: #94a3b8; /* 保证对比度 > 4.5:1 */
|
||||
--primary: #3b82f6; /* 在深色背景下稍微提亮主色 */
|
||||
--primary-foreground: #ffffff;
|
||||
--border-color: #334155;
|
||||
/* 深色模式下的特殊视觉补偿 */
|
||||
--shadow-elevation: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -2px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 设计排版体系
|
||||
|
||||
排版需兼顾多语言(中英文混合)和多端阅读体验。
|
||||
|
||||
* **字体选择**:保留现有的 `Geist`,同时后备配置 `Inter` 或 `Noto Sans SC` 以优化中文显示:
|
||||
`font-family: var(--font-geist-sans), 'Inter', 'Noto Sans SC', sans-serif;`
|
||||
* **字号范围 (Fluid Typography / 断点响应)**:
|
||||
* **移动端**:基础字号 16px(防止 iOS Safari 输入框自动缩放),正文 `16px - 18px`,大标题约 `24px - 28px`。
|
||||
* **桌面端**:正文 `16px - 20px`,大标题可达 `32px - 48px`。
|
||||
* **行高与间距**:正文行高 `1.5` 至 `1.6`(150%-160%),段落间距使用 `margin-bottom: 1.5em`。标题行高缩紧至 `1.2`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 构建全局样式与主题切换
|
||||
|
||||
当前系统已通过 Zustand (`store.ts`) 和 `ThemeProvider.tsx` 实现了基于 `localStorage` 和 `data-theme` 的切换。
|
||||
|
||||
* **优化防闪烁 (FOUC)**:由于在 Next.js 中客户端 Hydration 会有延迟,需要确保在 `<head>` 中注入一个同步脚本读取 `localStorage` 和 `prefers-color-scheme`,在 React 渲染前就应用 `dark` 类或 `data-theme`。
|
||||
* **深色模式下的层级分离**:避免仅仅改变背景色。对于弹窗、Dropdown 等元素,在深色模式下增加一个极细的亮色边框:
|
||||
```css
|
||||
.dark .surface-elevated {
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
box-shadow: var(--shadow-elevation);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 响应式布局策略
|
||||
|
||||
* **断点定义**:
|
||||
* 移动端:`< 768px` (Tailwind 默认 `md` 以下)。
|
||||
* 平板/桌面端:`>= 768px` (`md` 及以上)。
|
||||
* **移动端 (iOS/Android) 策略**:
|
||||
* 隐藏复杂的侧边栏(Sidebar),顶部导航精简为 Logo 和汉堡菜单。
|
||||
* 所有的按钮 (`button`, `a`) 必须拥有至少 `min-h-[44px] min-w-[44px]` 的触控区域(可以使用 padding 撑开)。
|
||||
* **桌面端策略**:
|
||||
* 最大化利用横向空间,采用 Sidebar + Main Content 或全宽 Header 的多列布局。
|
||||
|
||||
---
|
||||
|
||||
## 6. 重构导航菜单 (示例)
|
||||
|
||||
当前 `Navbar.tsx` 使用了平铺的链接。我们需要使用语义化标签,并通过 `aria-expanded` 增强可访问性,并分离移动端的汉堡菜单和桌面端菜单。
|
||||
|
||||
### 菜单组件伪代码
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function SemanticNavbar() {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-50 w-full bg-surface border-b border-border">
|
||||
<nav className="max-w-7xl mx-auto px-4 min-h-[64px] flex items-center justify-between" aria-label="Main Navigation">
|
||||
{/* Logo */}
|
||||
<div className="flex-shrink-0">
|
||||
<a href="/" className="font-bold text-text-color text-lg flex items-center min-h-[44px]">Logo</a>
|
||||
</div>
|
||||
|
||||
{/* Desktop Menu */}
|
||||
<ul className="hidden md:flex items-center gap-6">
|
||||
<li>
|
||||
<a href="/dashboard" className="text-secondary-color hover:text-text-color transition-colors py-2">
|
||||
控制台
|
||||
</a>
|
||||
</li>
|
||||
<li className="relative group">
|
||||
{/* 父菜单如果是功能性展开按钮,使用 button */}
|
||||
<button
|
||||
aria-expanded={isDropdownOpen}
|
||||
aria-controls="services-dropdown"
|
||||
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
|
||||
className="flex items-center gap-1 text-secondary-color hover:text-text-color py-2"
|
||||
>
|
||||
服务 <ChevronDownIcon />
|
||||
</button>
|
||||
{/* Dropdown 弹窗 */}
|
||||
<ul
|
||||
id="services-dropdown"
|
||||
className={`absolute top-full left-0 mt-2 w-48 bg-surface-elevated border border-border rounded-md shadow-md ${isDropdownOpen ? 'block' : 'hidden'}`}
|
||||
>
|
||||
<li>
|
||||
{/* 保证键盘 Tab 键能聚焦到这里 */}
|
||||
<a href="/service/1" className="block px-4 py-3 text-text-color hover:bg-surface-hover">服务一</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{/* Mobile Hamburger Button */}
|
||||
<div className="md:hidden">
|
||||
<button
|
||||
aria-controls="mobile-menu"
|
||||
aria-expanded={isMobileMenuOpen}
|
||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
className="p-2 min-w-[44px] min-h-[44px] text-text-color"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<HamburgerIcon />
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Mobile Menu Panel */}
|
||||
<div
|
||||
id="mobile-menu"
|
||||
className={`md:hidden overflow-hidden transition-[max-height] duration-300 ease-in-out ${isMobileMenuOpen ? 'max-h-screen' : 'max-h-0'}`}
|
||||
>
|
||||
<ul className="px-4 pb-4 space-y-2 bg-surface">
|
||||
<li>
|
||||
<a href="/dashboard" className="block py-3 text-text-color">控制台</a>
|
||||
</li>
|
||||
{/* 移动端子菜单可以直接平铺或使用手风琴折叠 */}
|
||||
<li>
|
||||
<span className="block py-3 text-secondary-color font-semibold">服务</span>
|
||||
<ul className="pl-4 space-y-2 border-l-2 border-border ml-2">
|
||||
<li><a href="/service/1" className="block py-3 text-text-color">服务一</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 针对移动端和桌面端的优化差异
|
||||
|
||||
* **iOS/Android 浏览器差异处理**:
|
||||
* **iOS Safari 底部安全区**:在主内容区底部增加 `padding-bottom: env(safe-area-inset-bottom);`,避免按钮被 Home Indicator 遮挡。
|
||||
* **字体抗锯齿 (Anti-aliasing)**:在 `globals.css` 中的 `body` 标签已设置 `-webkit-font-smoothing: antialiased;`,在深色模式下这能让细小的亮色文字边缘更加平滑,没有晕影。
|
||||
* **长文本限制**:在博客或文档页面,容器设置 `max-w-prose` (相当于 `max-width: 65ch`),确保每行不超过 60 个字符,提升阅读体验。
|
||||
* **桌面端强化**:
|
||||
* 可利用 Hover 状态提供丰富的反馈(如背景变色、细微的 `transform: translateY(-1px)`)。
|
||||
* 在宽屏上显示侧边栏和次要信息列(多列网格布局)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 可访问性测试与迭代流程
|
||||
|
||||
为确保重构后的界面符合标准,开发团队应在提交代码前进行以下检查:
|
||||
|
||||
1. **对比度扫描**:使用 Chrome DevTools 的 Lighthouse 或 WebAIM 对比度检查器,确保所有的正文/背景对比度 >= 4.5:1,大号文本 >= 3.0:1。
|
||||
2. **重排与缩放测试**:使用浏览器的缩放功能放大页面到 `200%` 和 `400%`。确保在 `400%` 下页面自动转为单列移动端布局,且文字不出现截断或相互重叠(开启 CSS 文本重排 `text-wrap: balance` 或避免固定高度)。
|
||||
3. **键盘导航测试**:不使用鼠标,仅用 `Tab` 和 `Enter` 遍历界面。确保所有交互元素有明显的 `:focus-visible` 外框线(Tailwind `focus-visible:ring-2 focus-visible:ring-primary`)。二级菜单不能在 Tab 聚焦到父元素时自动弹出(除非是用按钮触发),以避免用户被迫穿过无数个子菜单才能到达下一个主栏目。
|
||||
4. **屏幕阅读器体验**:开启 VoiceOver (Mac/iOS) 或 TalkBack (Android),验证 `aria-expanded`, `aria-controls` 等状态是否能被正确播报。
|
||||
@ -1,9 +1,154 @@
|
||||
# Deployment
|
||||
# Deployment Runbook
|
||||
|
||||
## Purpose
|
||||
## Scope
|
||||
|
||||
- TODO: Add content specific to Deployment.
|
||||
- Runtime: `console.svc.plus`
|
||||
- Topology: `Caddy + Docker Compose + GitHub Actions`
|
||||
- Deploy host: `root@jp-xhttp-contabo.svc.plus`
|
||||
- Public domains:
|
||||
- `https://www.svc.plus`
|
||||
- `https://console.svc.plus`
|
||||
- Canonical public origin: `https://www.svc.plus`
|
||||
|
||||
## Notes
|
||||
## Current Delivery Model
|
||||
|
||||
- TODO: Link to related documents in this section.
|
||||
The production frontend is deployed as a prebuilt container image from GitHub Actions.
|
||||
|
||||
- The target host does not build images locally.
|
||||
- The workflow builds an `linux/amd64` image and pushes it to `ghcr.io/<owner>/dashboard:<sha>`.
|
||||
- The host only performs `docker login`, `docker compose pull`, static asset extraction, and `docker compose up`.
|
||||
- `/docs` and `/blogs` fetch their content from `docs.svc.plus` at runtime; the frontend image no longer packs `knowledge/` or synced markdown payloads.
|
||||
- Static assets are extracted from the image into a shared Docker volume so Caddy can serve `/_next/static/*` and checked-in public files directly.
|
||||
|
||||
This is intentionally static-first for the current weak-IO single-node host. Dynamic HTML, auth routes, and API proxy routes still run through the Next.js container, but docs/blog content delivery is now delegated to `docs.svc.plus`.
|
||||
|
||||
## Control Plane & DNS Stage
|
||||
|
||||
The control repo (`github-org-x-evor`) tracks `console.svc.plus` through `console.svc.plus.code-workspace` and keeps the `subrepos/accounts.svc.plus` pointer in sync via `skills/cross-repo-upstream-submodule-sync`. Releases resolve metadata with that workspace and the `config/single-node-release` manifests. After `.github/workflows/pipeline.yaml` finishes pushing the new image, the control-plane DNS automation calls `scripts/github-actions/update-release-dns.sh` to update Cloudflare DNS so the new endpoint is reachable through the current production host `jp-xhttp-contabo.svc.plus`.
|
||||
|
||||
## Runtime Layout
|
||||
|
||||
Remote directory:
|
||||
|
||||
```bash
|
||||
/opt/console-svc-plus
|
||||
```
|
||||
|
||||
Files deployed there:
|
||||
|
||||
```bash
|
||||
docker-compose.yml
|
||||
Caddyfile
|
||||
.env.runtime
|
||||
```
|
||||
|
||||
Containers:
|
||||
|
||||
- `dashboard`: Next.js standalone runtime on port `3000`
|
||||
- `frontend-assets`: one-shot task that copies `static/` and `public/` into a shared volume
|
||||
- `caddy`: TLS termination and reverse proxy
|
||||
|
||||
## GitHub Actions Inputs
|
||||
|
||||
Workflow:
|
||||
|
||||
```text
|
||||
.github/workflows/pipeline.yaml
|
||||
```
|
||||
|
||||
Secrets required:
|
||||
|
||||
- `SINGLE_NODE_VPS_SSH_PRIVATE_KEY`
|
||||
- `OPENCLAW_GATEWAY_TOKEN` if used
|
||||
- `VAULT_TOKEN` if used
|
||||
- `AI_GATEWAY_ACCESS_TOKEN` if used
|
||||
- `INTERNAL_SERVICE_TOKEN` if used
|
||||
- `CLOUDFLARE_DNS_API_TOKEN` for the Cloudflare DNS stage
|
||||
- `CLOUDFLARE_API_TOKEN` if homepage Cloudflare analytics are enabled at runtime
|
||||
|
||||
Repository/environment variables recommended:
|
||||
|
||||
- `CANONICAL_DOMAIN`
|
||||
- `SERVED_DOMAINS`
|
||||
- `APP_BASE_URL`
|
||||
- `NEXT_PUBLIC_APP_BASE_URL`
|
||||
- `NEXT_PUBLIC_SITE_URL`
|
||||
- `NEXT_PUBLIC_LOGIN_URL`
|
||||
- `NEXT_PUBLIC_DOCS_BASE_URL`
|
||||
- `ACCOUNT_SERVICE_URL`
|
||||
- `NEXT_PUBLIC_ACCOUNT_SERVICE_URL`
|
||||
- `SERVER_SERVICE_URL`
|
||||
- `NEXT_PUBLIC_SERVER_SERVICE_URL`
|
||||
- `RUNTIME_HOSTNAME`
|
||||
- `DEPLOYMENT_HOSTNAME`
|
||||
- `DOCS_SERVICE_URL`
|
||||
- `DOCS_SERVICE_INTERNAL_URL`
|
||||
- `NEXT_PUBLIC_RUNTIME_ENVIRONMENT`
|
||||
- `NEXT_PUBLIC_RUNTIME_REGION`
|
||||
- `NEXT_PUBLIC_GISCUS_*`
|
||||
- `NEXT_PUBLIC_STRIPE_*`
|
||||
- `NEXT_PUBLIC_PAYPAL_CLIENT_ID`
|
||||
- `CLOUDFLARE_ZONE_TAG` if homepage Cloudflare analytics are enabled at runtime
|
||||
- `CLOUDFLARE_DNS_ZONE_TAG` only for single-domain manual DNS override; the GitHub Actions DNS stage resolves zones from each domain automatically
|
||||
|
||||
## Release Flow
|
||||
|
||||
1. GitHub Actions checks out the repo.
|
||||
2. Docker builds the frontend image with the public `NEXT_PUBLIC_*` values needed at build time.
|
||||
3. The image is pushed to GHCR.
|
||||
4. The workflow updates Cloudflare DNS for the release domain.
|
||||
5. The workflow renders `.env.runtime`, including the canonical public origin and both served frontend domains.
|
||||
6. The workflow uploads `docker-compose.yml`, `Caddyfile`, and `.env.runtime` to the host.
|
||||
7. The host pulls the new image, refreshes the static asset volume, and starts `dashboard + caddy`.
|
||||
8. The workflow verifies both `www.svc.plus` and `console.svc.plus`, and fails the release if either domain serves a different runtime version.
|
||||
|
||||
## Verification Commands
|
||||
|
||||
Local syntax checks:
|
||||
|
||||
```bash
|
||||
cd /Users/shenlan/workspaces/cloud-neutral-toolkit/console.svc.plus
|
||||
bash -n scripts/github-actions/render-frontend-runtime-env.sh
|
||||
bash -n scripts/github-actions/deploy-frontend-single-node.sh
|
||||
cp deploy/single-node/.env.runtime.example deploy/single-node/.env.runtime
|
||||
docker compose -f deploy/single-node/docker-compose.yml --env-file deploy/single-node/.env.runtime config >/tmp/console-compose.rendered.yaml
|
||||
rm -f deploy/single-node/.env.runtime
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
yaml.safe_load(Path('.github/workflows/pipeline.yaml').read_text())
|
||||
print('workflow yaml ok')
|
||||
PY
|
||||
```
|
||||
|
||||
Remote checks:
|
||||
|
||||
```bash
|
||||
ssh root@jp-xhttp-contabo.svc.plus "cd /opt/console-svc-plus && docker compose --env-file .env.runtime ps"
|
||||
ssh root@jp-xhttp-contabo.svc.plus "curl -fsSI -H 'Host: www.svc.plus' http://127.0.0.1/"
|
||||
ssh root@jp-xhttp-contabo.svc.plus "curl -fsSI -H 'Host: console.svc.plus' http://127.0.0.1/"
|
||||
curl -fsSIL https://www.svc.plus
|
||||
curl -fsSIL https://console.svc.plus
|
||||
```
|
||||
|
||||
## Failure Signatures
|
||||
|
||||
- `docker login ghcr.io` fails
|
||||
The workflow token or package visibility is wrong.
|
||||
- `frontend-assets` fails
|
||||
The image layout changed and no longer contains `/app/dashboard/static` or `/app/dashboard/public`.
|
||||
- `www.svc.plus` or `console.svc.plus` returns `502`
|
||||
Caddy is up, but the `dashboard` container failed or is not reachable on port `3000`.
|
||||
|
||||
## Rollback
|
||||
|
||||
1. Re-run the workflow with a previous known-good image tag.
|
||||
2. Or update `/opt/console-svc-plus/.env.runtime` and set `FRONTEND_IMAGE=ghcr.io/<owner>/dashboard:<previous-tag>`.
|
||||
3. Restart the services:
|
||||
|
||||
```bash
|
||||
ssh root@jp-xhttp-contabo.svc.plus "cd /opt/console-svc-plus && docker compose --env-file .env.runtime run --rm frontend-assets"
|
||||
ssh root@jp-xhttp-contabo.svc.plus "cd /opt/console-svc-plus && docker compose --env-file .env.runtime up -d dashboard caddy"
|
||||
```
|
||||
|
||||
4. Verify `https://www.svc.plus` and `https://console.svc.plus` again before closing the incident.
|
||||
|
||||
34
docs/zh/README.md
Normal file
34
docs/zh/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# 控制台服务 文档
|
||||
|
||||
该仓库以 Web 前端体验为主,文档需要覆盖产品流程、界面边界与集成触点。
|
||||
|
||||
## 当前状态快照
|
||||
|
||||
- 根 README 标题: `console.svc.plus`
|
||||
- 构建与运行时证据: package.json (`dashboard`)
|
||||
- 自动识别的主要目录: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- 现有文档数量: 86
|
||||
|
||||
## 核心双语文档
|
||||
|
||||
- [架构](architecture.md)
|
||||
- [设计](design.md)
|
||||
- [部署](deployment.md)
|
||||
- [使用手册](user-guide.md)
|
||||
- [开发手册](developer-guide.md)
|
||||
- [Vibe Coding 参考](vibe-coding-reference.md)
|
||||
|
||||
## 待归并的历史文档
|
||||
|
||||
- `SEO-AUDIT-REPORT.md`
|
||||
- `SEO-WORK-SUMMARY.md`
|
||||
- `advanced/customization.md`
|
||||
- `advanced/performance.md`
|
||||
- `advanced/scalability.md`
|
||||
- `advanced/security.md`
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- `api/overview.md`
|
||||
- `appendix/faq.md`
|
||||
- `appendix/glossary.md`
|
||||
11
docs/zh/SEO-AUDIT-REPORT.md
Normal file
11
docs/zh/SEO-AUDIT-REPORT.md
Normal file
@ -0,0 +1,11 @@
|
||||
# SEO Audit Report - console.svc.plus (ZH)
|
||||
|
||||
> English: `../SEO-AUDIT-REPORT.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/SEO-WORK-SUMMARY.md
Normal file
11
docs/zh/SEO-WORK-SUMMARY.md
Normal file
@ -0,0 +1,11 @@
|
||||
# SEO 优化工作总结 (ZH)
|
||||
|
||||
> English: `../SEO-WORK-SUMMARY.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/advanced/customization.md
Normal file
11
docs/zh/advanced/customization.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Customization (ZH)
|
||||
|
||||
> English: `../../advanced/customization.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/advanced/performance.md
Normal file
11
docs/zh/advanced/performance.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Performance (ZH)
|
||||
|
||||
> English: `../../advanced/performance.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/advanced/scalability.md
Normal file
11
docs/zh/advanced/scalability.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Scalability (ZH)
|
||||
|
||||
> English: `../../advanced/scalability.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/advanced/security.md
Normal file
11
docs/zh/advanced/security.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Security (ZH)
|
||||
|
||||
> English: `../../advanced/security.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/api/auth.md
Normal file
11
docs/zh/api/auth.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Auth (ZH)
|
||||
|
||||
> English: `../../api/auth.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/api/endpoints.md
Normal file
11
docs/zh/api/endpoints.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Endpoints (ZH)
|
||||
|
||||
> English: `../../api/endpoints.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/api/errors.md
Normal file
11
docs/zh/api/errors.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Errors (ZH)
|
||||
|
||||
> English: `../../api/errors.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/api/overview.md
Normal file
11
docs/zh/api/overview.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Overview (ZH)
|
||||
|
||||
> English: `../../api/overview.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/appendix/faq.md
Normal file
11
docs/zh/appendix/faq.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Faq (ZH)
|
||||
|
||||
> English: `../../appendix/faq.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/appendix/glossary.md
Normal file
11
docs/zh/appendix/glossary.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Glossary (ZH)
|
||||
|
||||
> English: `../../appendix/glossary.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/appendix/references.md
Normal file
11
docs/zh/appendix/references.md
Normal file
@ -0,0 +1,11 @@
|
||||
# References (ZH)
|
||||
|
||||
> English: `../../appendix/references.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
31
docs/zh/architecture.md
Normal file
31
docs/zh/architecture.md
Normal file
@ -0,0 +1,31 @@
|
||||
# 架构
|
||||
|
||||
该仓库以 Web 前端体验为主,文档需要覆盖产品流程、界面边界与集成触点。
|
||||
|
||||
本页作为系统边界、核心组件与仓库职责的双语总览入口。
|
||||
|
||||
## 与当前代码对齐的说明
|
||||
|
||||
- 文档目标仓库: `console.svc.plus`
|
||||
- 仓库类型: `frontend`
|
||||
- 构建与运行依据: package.json (`dashboard`)
|
||||
- 主要实现与运维目录: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- `package.json` 脚本快照: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## 需要继续归并的现有文档
|
||||
|
||||
- `api/overview.md`
|
||||
- `architecture/components.md`
|
||||
- `architecture/design-decisions.md`
|
||||
- `architecture/overview.md`
|
||||
- `architecture/roadmap.md`
|
||||
- `development/code-structure.md`
|
||||
- `zh/api/overview.md`
|
||||
- `zh/architecture/components.md`
|
||||
|
||||
## 本页下一步应补充的内容
|
||||
|
||||
- 先描述当前已落地实现,再补充未来规划,避免只写愿景不写现状。
|
||||
- 术语需要与仓库根 README、构建清单和实际目录保持一致。
|
||||
- 将上方列出的历史 runbook、spec、子系统说明逐步链接并归并到本页。
|
||||
- 随着目录结构、服务关系和集成依赖变化,持续同步图示与职责说明。
|
||||
11
docs/zh/architecture/components.md
Normal file
11
docs/zh/architecture/components.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Components (ZH)
|
||||
|
||||
> English: `../../architecture/components.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/architecture/design-decisions.md
Normal file
11
docs/zh/architecture/design-decisions.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Documentation Page Redesign Specification (ZH)
|
||||
|
||||
> English: `../../architecture/design-decisions.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/architecture/overview.md
Normal file
11
docs/zh/architecture/overview.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Overview (ZH)
|
||||
|
||||
> English: `../../architecture/overview.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/architecture/roadmap.md
Normal file
11
docs/zh/architecture/roadmap.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Roadmap (ZH)
|
||||
|
||||
> English: `../../architecture/roadmap.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
42
docs/zh/deployment.md
Normal file
42
docs/zh/deployment.md
Normal file
@ -0,0 +1,42 @@
|
||||
# 部署
|
||||
|
||||
## 生产基线
|
||||
|
||||
- 运行拓扑: `Caddy + Docker Compose`
|
||||
- 目标主机: `root@jp-xhttp-contabo.svc.plus`
|
||||
- 域名:
|
||||
- `www.svc.plus`
|
||||
- `console.svc.plus`
|
||||
- 公开首选域名: `www.svc.plus`
|
||||
- 前端独立发布流水线: `.github/workflows/pipeline.yaml`
|
||||
|
||||
## 运行方式
|
||||
|
||||
前端镜像在 GitHub Actions 中完成构建并推送到镜像仓库,目标主机只负责拉取镜像和启动容器,不在机器上本地构建。
|
||||
|
||||
`yarn prebuild` 现在只生成 console 自己的营销内容工件。`/docs` 与 `/blogs` 不再把 `knowledge/` 或 Markdown 文档打进前端镜像,而是在请求时通过服务端 `docsServiceClient` 从 `docs.svc.plus` 拉取渲染后的内容。
|
||||
|
||||
当前方案尽量以静态模式运行:
|
||||
|
||||
- Caddy 直接服务 `/_next/static/*` 与 `public/` 里的静态资源,并配合 `frontend_static` 共享卷。
|
||||
- Next.js standalone 容器只承接动态页面、认证接口和代理接口,`frontend-assets` 任务会把所有静态文件(包括哈希后的 CSS/JS)拷贝到 `frontend_static`。
|
||||
- `docs.svc.plus` 是 docs/blog 的运行时内容源,浏览器不会直接访问它。
|
||||
|
||||
发布由 `.github/workflows/pipeline.yaml` 驱动,CI 构建/推送镜像、渲染包含 `DOCS_SERVICE_URL` / `DOCS_SERVICE_INTERNAL_URL` 的 `.env.runtime`,然后将 `docker-compose.yml`、`Caddyfile` 与运行时环境文件发送到主机。随后控制平面 DNS 自动化会通过 `scripts/github-actions/update-release-dns.sh` 更新 Cloudflare DNS,使当前生产主机 `jp-xhttp-contabo.svc.plus` 承载更新后的环境。
|
||||
|
||||
这是针对弱 IO 单机主机 `root@jp-xhttp-contabo.svc.plus` 的部署权衡:主机不会在本地构建镜像,只需登录 GHCR、拉取 `dashboard` 镜像、解包静态资源到 `frontend_static`,再通过 `docker compose` 启动 `dashboard` 与 `caddy`。
|
||||
|
||||
`docs.svc.plus` 已经是前端 docs/blog 内容的独立服务。
|
||||
|
||||
当前发布合同要求:
|
||||
|
||||
- `CANONICAL_DOMAIN=www.svc.plus`
|
||||
- `SERVED_DOMAINS=www.svc.plus,console.svc.plus`
|
||||
- 流水线必须同时校验两个域名的首页静态资源与 `/api/ping` 版本元数据完全一致
|
||||
- `dashboardUrl`、canonical、structured data 与 sitemap 默认统一输出 `https://www.svc.plus`
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `usage/deployment.md`
|
||||
- `governance/release-process.md`
|
||||
- `development/dev-setup.md`
|
||||
27
docs/zh/design.md
Normal file
27
docs/zh/design.md
Normal file
@ -0,0 +1,27 @@
|
||||
# 设计
|
||||
|
||||
该仓库以 Web 前端体验为主,文档需要覆盖产品流程、界面边界与集成触点。
|
||||
|
||||
本页用于汇总设计决策、类似 ADR 的权衡记录,以及与路线图相关的实现说明。
|
||||
|
||||
## 与当前代码对齐的说明
|
||||
|
||||
- 文档目标仓库: `console.svc.plus`
|
||||
- 仓库类型: `frontend`
|
||||
- 构建与运行依据: package.json (`dashboard`)
|
||||
- 主要实现与运维目录: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- `package.json` 脚本快照: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## 需要继续归并的现有文档
|
||||
|
||||
- `SEO-WORK-SUMMARY.md`
|
||||
- `architecture/design-decisions.md`
|
||||
- `zh/SEO-WORK-SUMMARY.md`
|
||||
- `zh/architecture/design-decisions.md`
|
||||
|
||||
## 本页下一步应补充的内容
|
||||
|
||||
- 先描述当前已落地实现,再补充未来规划,避免只写愿景不写现状。
|
||||
- 术语需要与仓库根 README、构建清单和实际目录保持一致。
|
||||
- 将上方列出的历史 runbook、spec、子系统说明逐步链接并归并到本页。
|
||||
- 当行为、API 或部署契约发生变化时,把一次性实现笔记提升为可复用设计记录。
|
||||
31
docs/zh/developer-guide.md
Normal file
31
docs/zh/developer-guide.md
Normal file
@ -0,0 +1,31 @@
|
||||
# 开发手册
|
||||
|
||||
该仓库以 Web 前端体验为主,文档需要覆盖产品流程、界面边界与集成触点。
|
||||
|
||||
本页用于记录本地开发环境、项目结构、测试面与贴合当前代码库的贡献约定。
|
||||
|
||||
## 与当前代码对齐的说明
|
||||
|
||||
- 文档目标仓库: `console.svc.plus`
|
||||
- 仓库类型: `frontend`
|
||||
- 构建与运行依据: package.json (`dashboard`)
|
||||
- 主要实现与运维目录: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- `package.json` 脚本快照: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## 需要继续归并的现有文档
|
||||
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- `api/overview.md`
|
||||
- `development/code-structure.md`
|
||||
- `development/contributing.md`
|
||||
- `development/dev-setup.md`
|
||||
- `development/testing.md`
|
||||
|
||||
## 本页下一步应补充的内容
|
||||
|
||||
- 先描述当前已落地实现,再补充未来规划,避免只写愿景不写现状。
|
||||
- 术语需要与仓库根 README、构建清单和实际目录保持一致。
|
||||
- 将上方列出的历史 runbook、spec、子系统说明逐步链接并归并到本页。
|
||||
- 持续让环境搭建与测试命令对应真实存在的脚本、Make 目标或语言工具链。
|
||||
11
docs/zh/development/code-structure.md
Normal file
11
docs/zh/development/code-structure.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Code Structure (ZH)
|
||||
|
||||
> English: `../../development/code-structure.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/development/contributing.md
Normal file
11
docs/zh/development/contributing.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Contributing (ZH)
|
||||
|
||||
> English: `../../development/contributing.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/development/dev-setup.md
Normal file
11
docs/zh/development/dev-setup.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Development Setup (ZH)
|
||||
|
||||
> English: `../../development/dev-setup.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/development/testing.md
Normal file
11
docs/zh/development/testing.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Testing (ZH)
|
||||
|
||||
> English: `../../development/testing.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/getting-started/concepts.md
Normal file
11
docs/zh/getting-started/concepts.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Concepts (ZH)
|
||||
|
||||
> English: `../../getting-started/concepts.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
47
docs/zh/getting-started/installation.md
Normal file
47
docs/zh/getting-started/installation.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Installation (ZH)
|
||||
|
||||
> English: `../../getting-started/installation.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- 为 `console.svc.plus` 准备本地运行环境。
|
||||
- 用环境变量给 AI 助手和集成功能做默认值预填,而不是把网关配置写死在 UI 里。
|
||||
|
||||
## 环境准备
|
||||
|
||||
1. 复制示例文件:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
2. 如有联调环境,优先参考 `/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw-deploy-example/.env` 中对应值。
|
||||
|
||||
## AI 助手与集成变量
|
||||
|
||||
下面这些变量会由服务端读取,并用于以下场景的默认值预填:
|
||||
|
||||
- 首页 AI 助手
|
||||
- 侧栏 AI 助手
|
||||
- `/panel/api` 集成页
|
||||
|
||||
| 变量 | 用途 | 说明 |
|
||||
|---|---|---|
|
||||
| `OPENCLAW_GATEWAY_REMOTE_URL` | OpenClaw 助手 | 远端 WebSocket 地址,例如 `wss://openclaw.svc.plus:443` |
|
||||
| `OPENCLAW_GATEWAY_TOKEN` | OpenClaw 助手 | 服务端桥接 OpenClaw gateway 时使用的令牌 |
|
||||
| `VAULT_SERVER_URL` | Vault 集成 | Vault 服务地址,用于默认值和连通性探测 |
|
||||
| `VAULT_NAMESPACE` | Vault 集成 | Vault Enterprise namespace,可选 |
|
||||
| `VAULT_TOKEN` | Vault 集成 | Vault 探测请求使用的令牌 |
|
||||
| `APISIX_AI_GATEWAY_URL` | APISIX AI Gateway 集成 | AI gateway 的 HTTP(S) 地址 |
|
||||
| `AI_GATEWAY_ACCESS_TOKEN` | APISIX AI Gateway 集成 | AI gateway 探测请求使用的访问令牌 |
|
||||
|
||||
## 行为说明
|
||||
|
||||
- 这些变量不会被硬编码进前端 React 组件。
|
||||
- 页面中的输入项仍然支持会话级覆盖。
|
||||
- 变量留空只会取消默认值预填,不会影响现有布局。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `../README.md`
|
||||
- `../usage/config.md`
|
||||
11
docs/zh/getting-started/introduction.md
Normal file
11
docs/zh/getting-started/introduction.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Introduction (ZH)
|
||||
|
||||
> English: `../../getting-started/introduction.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/getting-started/quickstart.md
Normal file
11
docs/zh/getting-started/quickstart.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Quickstart (ZH)
|
||||
|
||||
> English: `../../getting-started/quickstart.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/governance/license.md
Normal file
11
docs/zh/governance/license.md
Normal file
@ -0,0 +1,11 @@
|
||||
# License (ZH)
|
||||
|
||||
> English: `../../governance/license.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
55
docs/zh/governance/release-process.md
Normal file
55
docs/zh/governance/release-process.md
Normal file
@ -0,0 +1,55 @@
|
||||
# Release Process (ZH)
|
||||
|
||||
> English: `../../governance/release-process.md`
|
||||
|
||||
本页用于记录公开控制台在 `www.svc.plus` 与 `console.svc.plus` 下发布版本的说明与变更摘要。
|
||||
|
||||
## 当前版本
|
||||
|
||||
### v0.2
|
||||
|
||||
发布标签:`v0.2`
|
||||
发布分支:`release/v0.2`
|
||||
发布提交:`0fab89e`
|
||||
|
||||
#### 亮点
|
||||
|
||||
- 引入新的 XWorkmate 工作区,助手布局更紧凑,工作区外壳更统一,入口流程也更顺滑。
|
||||
- 新增 OpenClaw assistant workspace 与 pairing bridge,支持可配置的 origin override,并改进了配对失败时的回退行为。
|
||||
- 统一导航与 AI 入口,加入持久化 assistant sidebar,并梳理 panel 路由。
|
||||
- 首页增加最新博客快捷入口,同时优化游客模式与注册引导文案。
|
||||
- 双语文档结构继续补齐,OIDC 接入文档和安装说明也更完整。
|
||||
- 修复构建稳定性问题,包括 `next-mdx-remote` 相关的漏洞拦截构建错误,以及 Yarn 依赖元数据对齐问题。
|
||||
|
||||
#### 新特性
|
||||
|
||||
- 上线 XWorkmate 工作区,并完善其入口与界面布局。
|
||||
- 增加 OpenClaw assistant 集成、pairing bridge、integration probe API,以及 integration defaults 处理能力。
|
||||
- 在服务页加入 XScopeHub MCP 服务可见性。
|
||||
- 首页快捷区展示最新 7 篇博客文章标题。
|
||||
|
||||
#### 体验改进
|
||||
|
||||
- 将 observability 工作区拆分为 tri-view,并优化 panel 助手路由。
|
||||
- 统一导航结构与持久化 AI sidebar 行为。
|
||||
- 登录与注册流程改为使用服务端解析后的 account service URL。
|
||||
- 体验与演示模式不得在公开 UI 或会话载荷中暴露其后端承载账号身份。
|
||||
- 为集成配置增加基于 vault 的 token 查询能力。
|
||||
|
||||
#### 文档与安装
|
||||
|
||||
- 增补双语文档覆盖,并整理文档入口结构。
|
||||
- 重写 OIDC 认证接入文档,补充更完整的配置说明。
|
||||
- 更新安装指导并精简 README 结构。
|
||||
|
||||
#### 构建与依赖修复
|
||||
|
||||
- 对齐并升级 `next-mdx-remote` 使用方式,确保构建安全。
|
||||
- 移除冲突的 npm 锁文件状态,并整理 Yarn 依赖元数据,提升构建可复现性。
|
||||
|
||||
## 备注
|
||||
|
||||
- GitHub Release:`https://github.com/x-evor/console.svc.plus/releases/tag/v0.2`
|
||||
- 发布校验必须同时验证 `www.svc.plus` 与 `console.svc.plus` 的 `releaseImageRef`、`releaseImageTag`、`releaseCommit` 完全一致。
|
||||
- `www.svc.plus` 是 metadata、sitemap、`dashboardUrl` 与公开分享链接的首选域名。
|
||||
- 相关文档:`docs/README.md`、`docs/en/README.md`、`docs/zh/README.md`
|
||||
11
docs/zh/governance/security-policy.md
Normal file
11
docs/zh/governance/security-policy.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Security Policy (ZH)
|
||||
|
||||
> English: `../../governance/security-policy.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/integrations/ai-providers.md
Normal file
11
docs/zh/integrations/ai-providers.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Ai Providers (ZH)
|
||||
|
||||
> English: `../../integrations/ai-providers.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/integrations/cloud.md
Normal file
11
docs/zh/integrations/cloud.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Cloud (ZH)
|
||||
|
||||
> English: `../../integrations/cloud.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/integrations/cloudflare-web-analytics.md
Normal file
11
docs/zh/integrations/cloudflare-web-analytics.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Cloudflare Web Analytics 集成配置 (ZH)
|
||||
|
||||
> English: `../../integrations/cloudflare-web-analytics.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/integrations/databases.md
Normal file
11
docs/zh/integrations/databases.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Databases (ZH)
|
||||
|
||||
> English: `../../integrations/databases.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/integrations/oidc-auth.md
Normal file
11
docs/zh/integrations/oidc-auth.md
Normal file
@ -0,0 +1,11 @@
|
||||
# OIDC Authentication Configuration Guide (ZH)
|
||||
|
||||
> English: `../../integrations/oidc-auth.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/operations/backup.md
Normal file
11
docs/zh/operations/backup.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Backup (ZH)
|
||||
|
||||
> English: `../../operations/backup.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/operations/logging.md
Normal file
11
docs/zh/operations/logging.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Logging (ZH)
|
||||
|
||||
> English: `../../operations/logging.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/operations/monitoring.md
Normal file
11
docs/zh/operations/monitoring.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Monitoring (ZH)
|
||||
|
||||
> English: `../../operations/monitoring.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/operations/runbooks/README.md
Normal file
11
docs/zh/operations/runbooks/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Runbooks (ZH)
|
||||
|
||||
> English: `../../../operations/runbooks/README.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/operations/runbooks/rag-server.md
Normal file
11
docs/zh/operations/runbooks/rag-server.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Cloud-Neutral Toolkit - RAG Server Runbook (ZH)
|
||||
|
||||
> English: `../../../operations/runbooks/rag-server.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/operations/troubleshooting.md
Normal file
11
docs/zh/operations/troubleshooting.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Troubleshooting (ZH)
|
||||
|
||||
> English: `../../operations/troubleshooting.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/usage/cli.md
Normal file
11
docs/zh/usage/cli.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Cli (ZH)
|
||||
|
||||
> English: `../../usage/cli.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/usage/config.md
Normal file
11
docs/zh/usage/config.md
Normal file
@ -0,0 +1,11 @@
|
||||
# 📊 配置文件系统汇总报告 (ZH)
|
||||
|
||||
> English: `../../usage/config.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/usage/deployment.md
Normal file
11
docs/zh/usage/deployment.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Deployment (ZH)
|
||||
|
||||
> English: `../../usage/deployment.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
11
docs/zh/usage/examples.md
Normal file
11
docs/zh/usage/examples.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Examples (ZH)
|
||||
|
||||
> English: `../../usage/examples.md`
|
||||
|
||||
## 目的
|
||||
|
||||
- TODO: 补充中文内容。
|
||||
|
||||
## 备注
|
||||
|
||||
- TODO: 链接到本章节相关文档。
|
||||
31
docs/zh/user-guide.md
Normal file
31
docs/zh/user-guide.md
Normal file
@ -0,0 +1,31 @@
|
||||
# 使用手册
|
||||
|
||||
该仓库以 Web 前端体验为主,文档需要覆盖产品流程、界面边界与集成触点。
|
||||
|
||||
本页用于记录主要用户或运维角色的日常任务、常见流程,以及现有操作文档入口。
|
||||
|
||||
## 与当前代码对齐的说明
|
||||
|
||||
- 文档目标仓库: `console.svc.plus`
|
||||
- 仓库类型: `frontend`
|
||||
- 构建与运行依据: package.json (`dashboard`)
|
||||
- 主要实现与运维目录: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- `package.json` 脚本快照: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## 需要继续归并的现有文档
|
||||
|
||||
- `api/overview.md`
|
||||
- `architecture/overview.md`
|
||||
- `getting-started/concepts.md`
|
||||
- `getting-started/installation.md`
|
||||
- `getting-started/introduction.md`
|
||||
- `getting-started/quickstart.md`
|
||||
- `usage/cli.md`
|
||||
- `usage/config.md`
|
||||
|
||||
## 本页下一步应补充的内容
|
||||
|
||||
- 先描述当前已落地实现,再补充未来规划,避免只写愿景不写现状。
|
||||
- 术语需要与仓库根 README、构建清单和实际目录保持一致。
|
||||
- 将上方列出的历史 runbook、spec、子系统说明逐步链接并归并到本页。
|
||||
- 优先提供面向流程的示例,并确保截图或终端片段与最新 UI/CLI 行为一致。
|
||||
31
docs/zh/vibe-coding-reference.md
Normal file
31
docs/zh/vibe-coding-reference.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Vibe Coding 参考
|
||||
|
||||
该仓库以 Web 前端体验为主,文档需要覆盖产品流程、界面边界与集成触点。
|
||||
|
||||
本页用于统一 AI 辅助开发提示词、仓库边界、安全编辑规则与文档同步要求。
|
||||
|
||||
## 与当前代码对齐的说明
|
||||
|
||||
- 文档目标仓库: `console.svc.plus`
|
||||
- 仓库类型: `frontend`
|
||||
- 构建与运行依据: package.json (`dashboard`)
|
||||
- 主要实现与运维目录: `src/`, `scripts/`, `tests/`, `config/`, `public/`
|
||||
- `package.json` 脚本快照: `dev`, `prebuild`, `build`, `build:static`, `start`, `lint`
|
||||
|
||||
## 需要继续归并的现有文档
|
||||
|
||||
- `api/auth.md`
|
||||
- `api/endpoints.md`
|
||||
- `api/errors.md`
|
||||
- `api/overview.md`
|
||||
- `zh/api/auth.md`
|
||||
- `zh/api/endpoints.md`
|
||||
- `zh/api/errors.md`
|
||||
- `zh/api/overview.md`
|
||||
|
||||
## 本页下一步应补充的内容
|
||||
|
||||
- 先描述当前已落地实现,再补充未来规划,避免只写愿景不写现状。
|
||||
- 术语需要与仓库根 README、构建清单和实际目录保持一致。
|
||||
- 将上方列出的历史 runbook、spec、子系统说明逐步链接并归并到本页。
|
||||
- 当项目新增子系统、受保护目录或强制验证步骤时,同步更新提示模板与仓库规则。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user