Compare commits

..

No commits in common. "main" and "release/v0.1" have entirely different histories.

349 changed files with 11409 additions and 27408 deletions

View File

@ -1,15 +0,0 @@
.git
.github
.next
.contentlayer
node_modules
coverage
dist
build
test-results
*.log
.env
.env.local
.env.*.local
deploy/single-node/.env.runtime
knowledge/.git

View File

@ -1,45 +1,6 @@
# 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=
# Moltbot Service URL
# Defaults to https://moltbot.svc.plus if not set
MOLTBOT_SERVICE_URL=https://moltbot.svc.plus
# Giscus Configuration (GitHub Discussions Integration)
# See https://giscus.app to generate these values
@ -52,23 +13,10 @@ 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 Normal file
View File

@ -0,0 +1,37 @@
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 tagv1.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 Normal file
View File

@ -0,0 +1,90 @@
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 Normal file
View File

@ -0,0 +1,53 @@
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 Normal file
View File

@ -0,0 +1,48 @@
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"

View File

@ -0,0 +1,106 @@
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 Normal file
View File

@ -0,0 +1,76 @@
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 Normal file
View File

@ -0,0 +1,52 @@
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 Executable file
View File

@ -0,0 +1,9 @@
#!/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 Executable file
View File

@ -0,0 +1,28 @@
#!/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 Executable file
View File

@ -0,0 +1,7 @@
#!/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 Executable file
View File

@ -0,0 +1,15 @@
#!/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 Normal file
View File

@ -0,0 +1,296 @@
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 Normal file
View File

@ -0,0 +1,49 @@
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

View File

@ -1,240 +0,0 @@
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
View File

@ -1,7 +1,6 @@
.env
models/
*.tsbuildinfo
knowledge/
# macOS
.DS_Store
@ -19,7 +18,6 @@ public/_build/
public/dl-index/
.contentlayer/
.dev-logs/
.console-state/
# Contentlayer cache
ui/docs/.contentlayer/
@ -56,7 +54,6 @@ coverage/
.env
.env.local
.env.*.local
deploy/single-node/.env.runtime
# Build artifacts
build/

View File

@ -1 +0,0 @@
registry "https://registry.npmjs.org"

View File

@ -4,7 +4,7 @@ enableGlobalCache: false
nodeLinker: node-modules
npmRegistryServer: "https://registry.npmjs.org"
npmRegistryServer: "https://registry.npmmirror.com"
packageExtensions:
"next-contentlayer@*":

View File

@ -51,20 +51,7 @@ yarn test:e2e path/to/spec.test.ts
---
## 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)
## 2. Repository Mental Model (Read This First)
This repository has **three clearly separated layers**:
@ -104,7 +91,7 @@ Used for build-time or runtime wiring only.
---
## 4. Import & Alias Rules (Critical)
## 3. Import & Alias Rules (Critical)
### Dashboard code (src/\*\*)
@ -125,7 +112,7 @@ import { UserCard } from "@/components/UserCard";
---
## 5. TypeScript & Formatting Rules
## 4. TypeScript & Formatting Rules
- Strict mode enabled
- Use `type` for type definitions, `interface` for object shapes
@ -136,7 +123,7 @@ import { UserCard } from "@/components/UserCard";
---
## 6. Naming Conventions
## 5. Naming Conventions
- Components: PascalCase (`UserProfile.tsx`)
- Files: kebab-case for utilities (`user-utils.ts`), PascalCase for components
@ -146,7 +133,7 @@ import { UserCard } from "@/components/UserCard";
---
## 7. Error Handling & Logging
## 6. Error Handling & Logging
- Use try/catch for async operations
- Return Result types or throw errors consistently
@ -155,7 +142,7 @@ import { UserCard } from "@/components/UserCard";
---
## 8. React Patterns
## 7. React Patterns
- Use `'use client'` directive for client components
- Prefer function components with hooks
@ -164,7 +151,7 @@ import { UserCard } from "@/components/UserCard";
---
## 9. Global State Rules (Dashboard Only)
## 8. Global State Rules (Dashboard Only)
✅ Zustand is the **only** allowed global state mechanism
❌ React Context for shared/global state is forbidden
@ -175,7 +162,7 @@ Rule: If state must survive navigation or be shared → it lives in Zustand.
---
## 10. URL-Synchronized State
## 9. URL-Synchronized State
Anything involving:
@ -192,7 +179,7 @@ MUST be handled inside Zustand slices.
---
## 11. Component State Rules
## 10. Component State Rules
Allowed:
@ -207,7 +194,7 @@ Forbidden:
---
## 12. packages/neurapress Rules (Very Important)
## 11. packages/neurapress Rules (Very Important)
packages/neurapress is treated as a vendored internal library.
@ -227,7 +214,7 @@ MUST NOT:
---
## 13. Testing Guidelines
## 12. Testing Guidelines
- Unit tests: Vitest with jsdom environment
- E2E tests: Playwright
@ -237,7 +224,7 @@ MUST NOT:
---
## 14. Environment & Runtime Config
## 13. Environment & Runtime Config
- No new environment variables without approval
- Runtime config must live in: src/config/runtime-service-config\*.yaml
@ -246,13 +233,13 @@ MUST NOT:
---
## 15. Cursor / Copilot Rules
## 14. Cursor / Copilot Rules
- No `.cursor/rules/`, `.cursorrules`, or `.github/copilot-instructions.md` found
---
## 16. TL;DR for AI Agents
## 15. TL;DR for AI Agents
- dashboard = application
- packages = libraries

View File

@ -4,27 +4,6 @@
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)
@ -33,51 +12,8 @@ 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_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}
NEXT_PRIVATE_TURBOPACK=1
# ---------------------------
# 基础镜像升级到最新
@ -123,6 +59,7 @@ 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
# ---------------------------
# 额外瘦身(可减少 1540 MB

View File

@ -49,6 +49,7 @@ 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:
@ -82,6 +83,7 @@ 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

183
README.md
View File

@ -1,138 +1,101 @@
# console.svc.plus
Cloud Neutral Toolkit 的开放云控制面板 (Open Cloud Control Panel).
**工程师 · 开源 · 云中立**
面向 **Ops / Infra / AI** 的统一前端仪表盘,强调技术自由与可迁移性。
关注 **Ops / Infra / AI****技术自由**
🏗️ 热衷于构建“逃生舱”,防止基础设施被厂商锁定。
> A unified dashboard for Ops / Infra / AI, built for technical freedom and portability.
> **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.
## 部署要求 (Deployment Requirements)
---
| 维度 | 要求 / 规格 | 说明 |
| ----------- | ------------------ | ------------------------------------- |
| Node.js | `>=18.17 <25` | 推荐使用 `.nvmrc` |
| 包管理 | Yarn (推荐) 或 npm | Yarn 推荐配合 Corepack |
| Git | 必需 | 用于拉取仓库 |
| 部署 (可选) | Vercel / 自建 | 部署方式见 `docs/usage/deployment.md` |
**console.svc.plus** 是 Cloud Neutral Toolkit 的**开放云控制面板**。
## 快速开始 (Quickstart)
> **console.svc.plus** is the **Open Cloud Control Panel** for the Cloud Neutral Toolkit.
### 一键初始化 (Setup Script)
## 项目简介 (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)
```bash
curl -fsSL "https://raw.githubusercontent.com/x-evor/console.svc.plus/main/scripts/setup.sh?$(date +%s)" \
| bash -s -- console.svc.plus
yarn install
```
### 本地运行 (Local Dev)
### 本地运行 (Running Locally)
启动开发服务器:
> To start the development server:
```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
cp .env.example .env
```
如果你的工作区同时包含 `openclaw-deploy-example`,建议参考 `../openclaw-deploy-example/.env` 填写 AI 助手联调配置,并同时查看 `docs/getting-started/installation.md`
## 主要入口 (Key Routes)
- `/services`:服务导航页,保留现有控制台布局。
- `/xworkmate`:原生 Next.js 的 XWorkmate 在线工作区,底层通过 `xworkmate-bridge``/acp/rpc` 接入。
- `/panel/api`:融合设置与集成页,用于配置和探测 OpenClaw Gateway、Vault Server、APISIX AI Gateway。
## AI 助手与集成能力 (Assistant & Integrations)
当前主页 AI 辅助功能已经基于本仓库原生实现,核心行为如下:
- 侧栏助手模式保留现有交互方式,但 `/xworkmate` 主工作区直接对接 `xworkmate-bridge`
- 最大化助手页面统一收敛到 `/xworkmate`,旧的 `/services/openclaw` 只保留兼容跳转,不再继续使用旧的 control UI 套壳。
- 页面截图通过 assistant chat 附件模式发送,而不是单独的浏览器控制壳。
- `/panel/api` 仍保留旧集成配置入口;`/xworkmate` 主路径不依赖它。
- bridge 地址与令牌从服务端环境变量读取,前端组件不硬编码敏感配置。
## 环境变量 (Environment Variables)
以下变量用于 `/xworkmate` 主工作区的服务端 bridge 代理:
| 变量 | 用途 |
| ------------------- | ------------------------------------- |
| `BRIDGE_SERVER_URL` | XWorkmate bridge 服务根地址 |
| `BRIDGE_AUTH_TOKEN` | XWorkmate bridge bearer token服务端 |
以下变量用于旧助手和集成页的服务端默认值预填:
| 变量 | 用途 |
| ----------------------------- | ------------------------------------ |
| `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)
## 认证配置 (Authentication Configuration)
入口:
有关如何配置 GitHub 和 Google OIDC 认证的详细步骤,请参阅 [OIDC 认证指南](./docs/integrations/oidc-auth.md)。
- EN: `docs/README.md`
- ZH: `docs/zh/README.md`
> For detailed steps on configuring GitHub and Google OIDC authentication, please refer to the [OIDC Authentication Guide](./docs/integrations/oidc-auth.md).
常用链接:
## 统计配置 (Homepage Stats Configuration)
- 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`
首页“注册用户数 / 访问量”所需 Cloudflare 变量说明,请参阅 [Cloudflare Web Analytics 集成配置](./docs/integrations/cloudflare-web-analytics.md)。
其他:
> For Cloudflare variables used by homepage stats, see the [Cloudflare Web Analytics integration guide](./docs/integrations/cloudflare-web-analytics.md).
- Agent rules: `AGENTS.md`
## 开发指南 (Development Guidelines)
有关详细的编码标准、架构规则和 Agent 特定说明,请参阅 [AGENTS.md](./AGENTS.md)。
> For detailed coding standards, architecture rules, and agent-specific instructions, please refer to [AGENTS.md](./AGENTS.md).
## 脚本 (Scripts)
* `dev`: 启动开发服务器。
* `build`: 构建生产版本应用。
* `test`: 使用 Vitest 运行单元测试。
* `test:e2e`: 使用 Playwright 运行端到端测试。
* `lint`: 运行代码检查 (Linter)。

View File

@ -16,12 +16,6 @@ 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/\*\*

View File

@ -1,332 +0,0 @@
# 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."

View File

@ -1,54 +0,0 @@
# 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=

View File

@ -1,28 +0,0 @@
{$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}
}
}

View File

@ -1,55 +0,0 @@
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
View File

@ -1,39 +1,31 @@
▲ 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...
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)
✓ Ready in 2.5s
○ Compiling /services ...
GET /services 200 in 6.8s (compile: 6.4s, render: 327ms)
[runtime-config] Loaded env: PROD
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)
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)

View File

@ -1,14 +0,0 @@
# 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. |

View File

@ -1,42 +1,75 @@
# Console Service Plus / 控制台服务
# Documentation
This `docs/` directory now has a bilingual canonical layer for the current repository state.
This directory follows a standard open-source documentation layout and mirrors the code organization of `console.svc.plus`.
`docs/` 目录现已补齐双语规范层,用于承接当前仓库状态下的核心文档。
## Structure
## Quick Entry / 快速入口
- `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.
- Coverage checklist / 覆盖检查矩阵: `docs/DOC_COVERAGE.md`
- English index / 英文入口: `docs/en/README.md`
- 中文入口 / Chinese index: `docs/zh/README.md`
## Codebase Mapping
## Canonical Bilingual Pages / 双语规范页
- 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`
- `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`
## Index
## 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`
- 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`

View File

@ -214,7 +214,7 @@ export default function NotFound() {
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://www.svc.plus'),
metadataBase: new URL('https://console.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://www.svc.plus',
url: 'https://console.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://www.svc.plus" />
<link rel="canonical" href="https://console.svc.plus" />
{/* ... rest of head */}
</head>
{/* ... rest of layout */}
@ -343,7 +343,7 @@ Disallow: /admin/
Disallow: /api/
Disallow: /internal/
Sitemap: https://www.svc.plus/sitemap.xml
Sitemap: https://console.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://www.svc.plus',
logo: 'https://www.svc.plus/logo.png',
url: 'https://console.svc.plus',
logo: 'https://console.svc.plus/logo.png',
sameAs: [
'https://twitter.com/cloudneutral',
'https://github.com/x-evor',
'https://github.com/cloud-neutral-toolkit',
],
}
@ -372,10 +372,10 @@ export default function RootLayout({ children }: { children: React.ReactNode })
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'Cloud-Neutral',
url: 'https://www.svc.plus',
url: 'https://console.svc.plus',
potentialAction: {
'@type': 'SearchAction',
target: 'https://www.svc.plus/search?q={search_term_string}',
target: 'https://console.svc.plus/search?q={search_term_string}',
'query-input': 'required name=search_term_string',
},
}

View File

@ -1,96 +0,0 @@
# 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.

View File

@ -1,34 +0,0 @@
# 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`

View File

@ -1,31 +0,0 @@
# 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.

View File

@ -1,42 +0,0 @@
# 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`

View File

@ -1,27 +0,0 @@
# 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.

View File

@ -1,31 +0,0 @@
# 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.

View File

@ -1,31 +0,0 @@
# 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.

View File

@ -1,31 +0,0 @@
# 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.

View File

@ -2,44 +2,8 @@
## Purpose
- Set up the local development environment for `console.svc.plus`.
- Define the assistant and integrations defaults without hardcoding gateway values into the UI.
- TODO: Add content specific to Installation.
## Environment setup
## Notes
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`
- TODO: Link to related documents in this section.

View File

@ -1,53 +1,9 @@
# Release Process
This page tracks release summaries for published versions of the public web console served under `www.svc.plus` and `console.svc.plus`.
## Purpose
## 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.
- TODO: Add content specific to Release Process.
## Notes
- 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.
- TODO: Link to related documents in this section.

View File

@ -48,7 +48,7 @@ CLOUDFLARE_WEB_ANALYTICS_SITE_TAG=
### 本地开发
写入当前前端仓库的 `.env.local`
写入 `console.svc.plus/.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://www.svc.plus/api/marketing/home-stats
curl -fsSL https://console.svc.plus/api/marketing/home-stats
```
期望返回中 `visits.daily/weekly/monthly` 为数字(非 `null`)。
@ -77,3 +77,4 @@ curl -fsSL https://www.svc.plus/api/marketing/home-stats
1. token 权限是否包含 Analytics Read
2. Account ID 是否与 siteTag 属于同一账号
3. 环境变量是否已在当前运行实例生效(重启/重新部署后再测)

View File

@ -1,244 +1,88 @@
# OIDC Authentication Configuration Guide
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 │
<────────────────────────────────────────────────│
│ │ │
```
This guide describes how to configure GitHub and Google OIDC authentication for the Cloud Neutral Toolkit.
## Prerequisites
- 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`
- Access to GitHub Developer Settings.
- Access to Google Cloud Console.
- Properly configured `accounts.svc.plus` and `console.svc.plus` services.
---
## 1. GitHub OAuth App
## 1. GitHub Configuration
### 1.1 Create OAuth App
### 1.1 Create GitHub OAuth App
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. 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**.
| 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) |
4. Click **"Register application"**
### 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
```
---
## 3. Backend Configuration (accounts.svc.plus)
### 1.2 Configure Environment Variables
Set the following environment variables for **accounts.svc.plus**:
```bash
# ── 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>
# ── General OAuth ──
OAUTH_REDIRECT_URL=https://accounts.svc.plus/api/auth/oauth/callback
OAUTH_FRONTEND_URL=https://www.svc.plus
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
```
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 (`www.svc.plus` canonical, `console.svc.plus` secondary)
## 2. Google Configuration
The frontend resolves the accounts service URL **server-side** via `getAccountServiceBaseUrl()`, which reads:
### 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
Set the following environment variables for **accounts.svc.plus**:
```bash
# Set in accounts.svc.plus deployment environment
ACCOUNT_SERVICE_URL=https://accounts.svc.plus
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
```
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
## 3. General OIDC Environment Variables
### `undefined/api/auth/oauth/login/github`
Ensure these are also set for **accounts.svc.plus**:
**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
```bash
OAUTH_REDIRECT_URL=https://accounts.svc.plus/api/auth/oauth/callback
OAUTH_FRONTEND_URL=https://console.svc.plus
```
### 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.
**Note**: The backend automatically appends `/{provider}` to `OAUTH_REDIRECT_URL` if a provider-specific redirect URL is not provided.
---
## 6. Quick Reference
## 4. Frontend Configuration
| 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` |
For **console.svc.plus**, ensure the following is set so it knows where to redirect for the initial OAuth step:
```bash
NEXT_PUBLIC_ACCOUNTS_SVC_URL=https://accounts.svc.plus
```

View File

@ -1,51 +0,0 @@
# 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.

View File

@ -16,7 +16,7 @@
- **区域**: asia-northeast1
- **项目 ID**: xzerolab-480008
- **服务 URL**: https://rag-server-svc-plus-266500572462.asia-northeast1.run.app
- **代码仓库**: https://github.com/x-evor/rag-server.svc.plus
- **代码仓库**: https://github.com/cloud-neutral-toolkit/rag-server.svc.plus
### 服务功能
RAG (Retrieval-Augmented Generation) 服务器提供以下功能:
@ -68,7 +68,7 @@ rag-server.svc.plus/
#### 1. 代码变更
```bash
# 克隆仓库
git clone https://github.com/x-evor/rag-server.svc.plus.git
git clone https://github.com/cloud-neutral-toolkit/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/x-evor/rag-server.svc.plus
- **GitHub**: https://github.com/cloud-neutral-toolkit/rag-server.svc.plus
- **Cloud Console**: https://console.cloud.google.com/run/detail/asia-northeast1/rag-server-svc-plus
- **监控面板**: [Monitoring Dashboard URL]
- **文档**: [Documentation URL]

View File

@ -1,281 +0,0 @@
# 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.

View File

@ -1,5 +0,0 @@
# 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.

View File

@ -1,218 +0,0 @@
# 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` 等状态是否能被正确播报。

View File

@ -1,154 +1,9 @@
# Deployment Runbook
# Deployment
## Scope
## Purpose
- 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`
- TODO: Add content specific to Deployment.
## Current Delivery Model
## Notes
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.
- TODO: Link to related documents in this section.

View File

@ -1,34 +0,0 @@
# 控制台服务 文档
该仓库以 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`

View File

@ -1,11 +0,0 @@
# SEO Audit Report - console.svc.plus (ZH)
> English: `../SEO-AUDIT-REPORT.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# SEO 优化工作总结 (ZH)
> English: `../SEO-WORK-SUMMARY.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Customization (ZH)
> English: `../../advanced/customization.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Performance (ZH)
> English: `../../advanced/performance.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Scalability (ZH)
> English: `../../advanced/scalability.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Security (ZH)
> English: `../../advanced/security.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Auth (ZH)
> English: `../../api/auth.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Endpoints (ZH)
> English: `../../api/endpoints.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Errors (ZH)
> English: `../../api/errors.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Overview (ZH)
> English: `../../api/overview.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Faq (ZH)
> English: `../../appendix/faq.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Glossary (ZH)
> English: `../../appendix/glossary.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# References (ZH)
> English: `../../appendix/references.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,31 +0,0 @@
# 架构
该仓库以 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、子系统说明逐步链接并归并到本页。
- 随着目录结构、服务关系和集成依赖变化,持续同步图示与职责说明。

View File

@ -1,11 +0,0 @@
# Components (ZH)
> English: `../../architecture/components.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Documentation Page Redesign Specification (ZH)
> English: `../../architecture/design-decisions.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Overview (ZH)
> English: `../../architecture/overview.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Roadmap (ZH)
> English: `../../architecture/roadmap.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,42 +0,0 @@
# 部署
## 生产基线
- 运行拓扑: `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`

View File

@ -1,27 +0,0 @@
# 设计
该仓库以 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 或部署契约发生变化时,把一次性实现笔记提升为可复用设计记录。

View File

@ -1,31 +0,0 @@
# 开发手册
该仓库以 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 目标或语言工具链。

View File

@ -1,11 +0,0 @@
# Code Structure (ZH)
> English: `../../development/code-structure.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Contributing (ZH)
> English: `../../development/contributing.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Development Setup (ZH)
> English: `../../development/dev-setup.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Testing (ZH)
> English: `../../development/testing.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Concepts (ZH)
> English: `../../getting-started/concepts.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,47 +0,0 @@
# 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`

View File

@ -1,11 +0,0 @@
# Introduction (ZH)
> English: `../../getting-started/introduction.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Quickstart (ZH)
> English: `../../getting-started/quickstart.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# License (ZH)
> English: `../../governance/license.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,55 +0,0 @@
# 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`

View File

@ -1,11 +0,0 @@
# Security Policy (ZH)
> English: `../../governance/security-policy.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Ai Providers (ZH)
> English: `../../integrations/ai-providers.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Cloud (ZH)
> English: `../../integrations/cloud.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Cloudflare Web Analytics 集成配置 (ZH)
> English: `../../integrations/cloudflare-web-analytics.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Databases (ZH)
> English: `../../integrations/databases.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# OIDC Authentication Configuration Guide (ZH)
> English: `../../integrations/oidc-auth.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Backup (ZH)
> English: `../../operations/backup.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Logging (ZH)
> English: `../../operations/logging.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Monitoring (ZH)
> English: `../../operations/monitoring.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Runbooks (ZH)
> English: `../../../operations/runbooks/README.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Cloud-Neutral Toolkit - RAG Server Runbook (ZH)
> English: `../../../operations/runbooks/rag-server.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Troubleshooting (ZH)
> English: `../../operations/troubleshooting.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Cli (ZH)
> English: `../../usage/cli.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# 📊 配置文件系统汇总报告 (ZH)
> English: `../../usage/config.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Deployment (ZH)
> English: `../../usage/deployment.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,11 +0,0 @@
# Examples (ZH)
> English: `../../usage/examples.md`
## 目的
- TODO: 补充中文内容。
## 备注
- TODO: 链接到本章节相关文档。

View File

@ -1,31 +0,0 @@
# 使用手册
该仓库以 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 行为一致。

View File

@ -1,31 +0,0 @@
# 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