# Runtime Operations

Updated: 2026-05-22 07:38 HKT

## One API Runtime

Directory:

```bash
/www/wwwroot/api.openmagic.ai/oneapi
```

Common commands:

```bash
cd /www/wwwroot/api.openmagic.ai/oneapi
docker compose ps
docker compose logs --tail=100
docker stats --no-stream openmagic-one-api
```

Runtime binding:

```text
127.0.0.1:3000
```

Public API route:

```text
https://api.openmagic.ai/v1/*
```

Nginx routes `/v1/*` through the OpenMagic PHP relay first so the business layer can record realtime request trace and encrypted short-retention payloads. The relay forwards the original method, path, query, body, authorization header, and content type to One API.

## Request Trace And Encrypted Payloads

Purpose:

- Keep realtime operational visibility for API traffic.
- Avoid long-term plaintext conversation storage.
- Allow controlled debug/audit access when a concrete support reason exists.

Tables:

```text
api_openmagic_biz.om_request_trace
api_openmagic_biz.om_request_payload_log
api_openmagic_biz.om_request_payload_access
```

Default behavior:

- `om_request_trace` stores metadata: request id, user id, One API user id, model, status, HTTP status, stream flag, token counts, first-token latency, duration, IP, and user agent.
- `om_request_payload_log` stores request/response bodies encrypted with the OpenMagic secret material.
- Payload retention is controlled by `trace.payload_retention_days`; current production value is 7 days.
- Payload size is capped by `trace.max_payload_bytes`; oversized payloads are truncated before encryption.
- `/admin/trace/` shows the recent realtime flow.
- Payload decryption requires super-admin access, a required reason, and writes `om_request_payload_access`.

Cleanup:

```bash
/usr/bin/php /www/wwwroot/api.openmagic.ai/scripts/purge_expired_payloads.php
```

Cron:

```text
/etc/cron.d/openmagic-payload-purge
```

Migration note:

- The trace layer only depends on configured DB host, One API base URL, and PHP/Nginx routing.
- When `api.openmagic.ai` and `api_openmagic_biz` move to a dedicated server, update `config/app.local.php` instead of hard-coding local addresses.
- If One API is moved off-box too, set `trace.oneapi_base_url` to the private service URL and keep `/v1/*` routed through the relay.

## One API Credentials

Local credential file:

```bash
/www/wwwroot/api.openmagic.ai/oneapi/.root-credential
```

Permissions are set to `600`.

This file currently contains:

- One API root admin credential
- One API smoke test bearer token

Do not expose this file through Nginx or public docs.

## Gateway Smoke Tests

Unauthenticated request:

```bash
curl -i -H 'Host: api.openmagic.ai' http://127.0.0.1/v1/models
```

Expected:

```text
401 Unauthorized
```

Authenticated request:

```bash
curl -i -H 'Host: api.openmagic.ai' \
  -H 'Authorization: Bearer <smoke-token>' \
  http://127.0.0.1/v1/models
```

Expected after the first upstream channel is configured:

```json
{"data":[{"id":"gpt-4o-mini"}],"object":"list"}
```

Public CDN route:

```bash
curl -i https://api.openmagic.ai/v1/models
curl -i -H 'Authorization: Bearer <smoke-token>' https://api.openmagic.ai/v1/models
curl -i -H 'Authorization: Bearer <smoke-token>' \
  -H 'Content-Type: application/json' \
  -X POST https://api.openmagic.ai/v1/chat/completions \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Reply with only OK."}],"max_tokens":10}'
```

The current public smoke result is a real OpenAI response with content `OK`.

## Upstream Channel

The first One API channel is configured from the existing `chat.openmagic.ai` gateway credentials:

- Channel name: `chat.openmagic.ai-openai`
- Channel type: OpenAI-compatible
- Base URL: `https://api.openai.com`
- Model: `gpt-4o-mini`
- Group: `default`

The One API routing table also needs the matching ability row:

```sql
INSERT INTO abilities (`group`, model, channel_id, enabled, priority)
VALUES ('default', 'gpt-4o-mini', <channel_id>, 1, 0)
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled), priority = VALUES(priority);
```

## Exit Node Experiment

First experimental exit node:

| Item | Value |
| --- | --- |
| OpenMagic node code | `free_de_telegram` |
| Source table | `sktvf.serverlist.id=33333` |
| Source node id | `1221` |
| Host label | `telegram.redgate.pet` |
| Direct IP | `199.247.23.168` |
| Region | `de` |
| Agent port | `18787` |
| Agent service | `openmagic-exit-agent` |
| Firewall service | `openmagic-exit-firewall` |
| Agent path | `/opt/openmagic-exit-agent/openmagic_exit_agent.py` |
| Config path | `/etc/openmagic-exit-agent/config.json` |

Business tables:

```text
api_openmagic_biz.om_exit_node
api_openmagic_biz.om_exit_node_route
api_openmagic_biz.om_exit_provider_account
```

Current design:

- One API still handles user auth, quota, billing, and logs.
- The exit node behaves as an OpenAI-compatible upstream channel.
- One API channel `exit-free-de-telegram-openai` currently points to `http://199.247.23.168:18787`.
- Business node registry `om_exit_node.relay_url` uses `http://telegram.redgate.pet:18787` after DNS verification.
- The node validates a relay key, injects the node-bound upstream provider key, and sends traffic from the German node IP.
- The production default group is not switched to the node. The node is isolated under One API group `node-test`.

Security:

- Node relay key is stored in `om_secret_store` as `exit_node.free_de_telegram.relay_key`.
- The provider credential is deployed node-side in `/etc/openmagic-exit-agent/config.json`; the business DB stores only pointer metadata.
- Runtime iptables currently allows `18787/tcp` only from application server `38.54.17.219`, then drops other sources.
- `openmagic-exit-firewall.service` reapplies the two `18787/tcp` rules after reboot before the agent starts.
- `telegram.redgate.pet` was verified on 2026-05-22 to resolve directly to `199.247.23.168` as a DNS-only record. Domain health check on `http://telegram.redgate.pet:18787/health` returned 200.

DNS verification rule:

1. Compare `om_exit_node.host` DNS A result with `om_exit_node.ip`.
2. If they differ, do not switch `relay_url`; ask for DNS correction.
3. After DNS matches, call `http://<host>:18787/health` with the relay key.
4. Only then update `om_exit_node.relay_url` to the domain form.

Validated chain:

```text
client -> api.openmagic.ai -> OpenMagic /v1 relay -> One API node-test channel -> free_de_telegram exit agent -> OpenAI
```

Smoke results:

- Direct node `/health` returned `ok=true`.
- Direct node `/v1/models` returned OpenAI models with `X-OpenMagic-Exit-Node: free_de_telegram`.
- Direct node `/v1/chat/completions` returned `NODE_OK`.
- Full public chain through `https://api.openmagic.ai/v1/chat/completions` using the isolated `node-test` token returned `PUBLIC_NODE_CHAIN_OK`.
- One API log for the full-chain test used `channel_id=2`, confirming traffic exited through the German node channel.

## Upstream Auth Profiles

Business-layer upstream authentication profiles are stored outside One API:

```text
api_openmagic_biz.om_upstream_auth_profile
```

Console page:

```text
/console/upstreams/
```

Backend endpoints:

```text
GET  /backend/upstream/auth-profiles/list/
POST /backend/upstream/auth-profiles/save/
POST /backend/upstream/auth-profiles/refresh/
```

Supported auth profile types:

- `api_key`
- `service_account`
- `oauth_refresh_token`
- `custom_header`

Current OAuth standby record:

- Name: `OpenAI OAuth standby profile`
- Provider: `openai`
- Auth type: `oauth_refresh_token`
- Status: `standby`
- Base URL: `https://api.openai.com`
- Model scope: `gpt-4o-mini`

Important boundary:

- This feature is a reserved capability only.
- It does not currently participate in One API production routing.
- The refresh endpoint only marks a refresh check as `pending_manual_connector`; it does not call a provider token endpoint yet.
- Do not store live OAuth credentials until the provider's terms, token refresh behavior, and secure secret storage are confirmed.

## Billing Mock Flow

List plans:

```bash
curl -s -H 'Host: api.openmagic.ai' \
  http://127.0.0.1/backend/billing/plans/
```

Create an order:

```bash
curl -s -H 'Host: api.openmagic.ai' \
  -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1/backend/billing/order/create/ \
  -d '{"plan_code":"builder_monthly"}'
```

Settle an order in mock mode:

```bash
curl -s -H 'Host: api.openmagic.ai' \
  -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1/backend/payment/mock-settle/ \
  -d '{"order_no":"<order_no>"}'
```

Expected writes:

- `om_order`
- `om_payment`
- `om_balance_ledger`
- `om_subscription` for monthly plans
- `oneapi_core.users.quota` increases for monthly plans

## Yuansfer Payment Flow

Create a Yuansfer dry-run checkout:

```bash
curl -s -H 'Host: api.openmagic.ai' \
  -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1/backend/payment/yuansfer/create/ \
  -d '{"plan_code":"starter_balance","vendor":"alipay","dry_run":true}'
```

The endpoint creates a pending `om_order`, marks `pay_channel=yuansfer`, and returns the exact signed Yuansfer request body without contacting the live cashier when `dry_run=true`.

Yuansfer IPN callback:

```text
https://api.openmagic.ai/backend/payment/yuansfer/ipn/
```

The IPN handler verifies Yuansfer's MD5 signature algorithm inherited from `url.cr`, then calls the same idempotent settlement path used by the mock flow. A local signed success callback was tested and wrote `om_order`, `om_payment`, and `om_balance_ledger`.

## Stripe Payment Flow

OpenMagic currently carries the same two Stripe account separation used by `url.cr`:

| Sender | Account role | Create channel | Webhook |
| --- | --- | --- | --- |
| `redspeed` | Redspeed Stripe account | `/backend/payment/stripe/create/` with `sender=redspeed` | `/backend/payment/stripe/redspeed/webhook/` |
| `redgate` | Redgate Stripe account | `/backend/payment/stripe/create/` with `sender=redgate` | `/backend/payment/stripe/redgate/webhook/` |

Create a Stripe dry-run checkout:

```bash
curl -s -H 'Host: api.openmagic.ai' \
  -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1/backend/payment/stripe/create/ \
  -d '{"plan_code":"starter_balance","sender":"redspeed","vendor":"stripe_card","dry_run":true}'
```

Supported Stripe vendors currently mirror `url.cr`:

- `stripe_card`
- `stripe_wechat`
- `stripe_alipay`
- `stripe_paypal`
- `stripe_crypto`
- `stripe_applepay`
- `stripe_googlepay`

Webhook verification:

- Both Stripe webhooks verify `Stripe-Signature` with the correct account-specific `whsec_*` secret.
- Both only settle `payment_intent.succeeded`.
- The settlement reference is `data.object.metadata.trade_no`.
- The transaction ID is `data.object.id`.

Local signed webhook simulations were tested for both accounts:

- `stripe_redspeed` settled order `OM202605212132402211`.
- `stripe_redgate` settled order `OM202605212132405239`.

## Customer Service Widget

The site footer loads the existing website widget:

```html
<script src="https://url.cr/chat/widget/chat.js"
        data-brand="openmagic"
        data-lang="zh"></script>
```

This is the customer-service entry only. The separate `chat.openmagic.ai` free AI chat remains a low-priority product link, not the customer-service system.

## CDN Reverse Proxy

CDN server:

```text
45.202.210.202:9011
```

Remote config:

```text
/etc/nginx/nginx.conf
```

Current CDN behavior:

- `api.openmagic.ai` HTTP redirects to HTTPS.
- `api.openmagic.ai` HTTPS uses `/etc/nginx/ssl_new/openmagic.ai.crt` and key.
- All paths reverse proxy to app server `38.54.17.219:80`.
- Cache is bypassed for the whole API site using `X-Cache-Status: BYPASS`.
- Remote backup from this change: `/etc/nginx/nginx.conf.bak.api_openmagic_20260522_052754`.

## Current Limits

- Public real-model smoke is working, but only `gpt-4o-mini` is configured.
- Yuansfer live cashier request is implemented but only tested in `dry_run` plus signed local IPN simulation; do not expose live checkout broadly before a small real payment test.
- Mock settlement remains available for build-phase verification only.
- MySQL is currently `read_only=1`; One API uses the high-privilege `remote` DB user as a temporary workaround.
- Console authentication is intentionally not enforced yet, per build-phase testing policy.

## Admin Pages

Build-phase admin pages are available without login for local validation. They must be protected before public launch.

```text
/admin/
/admin/users/
/admin/orders/
/admin/payments/
/admin/plans/
/admin/models/
/admin/upstreams/
/admin/secrets/
/admin/manual-adjust/
```

The manual adjustment endpoint is:

```text
POST /backend/admin/manual-adjust/
```

Smoke-tested with a `+1` quota adjustment for One API user `1`.

## Secret Storage

Payment and upstream credentials now live in encrypted business DB rows:

```text
api_openmagic_biz.om_secret_store
```

Encryption:

- AES-128-CBC
- Base64 ciphertext
- Same general pattern as `url.cr/includes/aes.php`, but with OpenMagic's own key and IV in `config/app.local.php`

Stored secret keys:

- `payment.yuansfer.token`
- `payment.yuansfer.merchant_no`
- `payment.yuansfer.store_no`
- `payment.stripe.redspeed.public_key`
- `payment.stripe.redspeed.secret_key`
- `payment.stripe.redspeed.webhook_secret`
- `payment.stripe.redgate.public_key`
- `payment.stripe.redgate.secret_key`
- `payment.stripe.redgate.webhook_secret`
- `upstream.openai.chat_gateway.api_key`

`PaymentRepository` now resolves Yuansfer and Stripe credentials from `SecretRepository` first.

## Screenshot Delivery

Latest front-end and admin screenshots:

```text
/mnt/OneDrive/cli传递/openmagic_api_screenshots_20260522_055834/
```

## 2026-05-22 Frontend i18n, Visuals, USD Settlement

Frontend changes:

- Added OpenMagic i18n assets:
  - `/assets/i18n/openmagic-i18n.css`
  - `/assets/i18n/openmagic-i18n.js`
- The language switcher follows the Redgate `rs-ext` pattern but uses OpenMagic-specific assets.
- Frontend pages load i18n automatically; `/admin/*` does not load it.
- Supported language switcher options: English, Chinese, Japanese, Korean, Spanish, French, German, Portuguese, Russian, Arabic, Hindi.
- Added a reusable hero visual with model-provider orbit cards to reduce text-only page feel.

Currency changes:

- Public pricing is now USD-only.
- `om_plan.currency` values are now `USD`.
- Yuansfer dry-run now sends `currency=USD`.
- Model catalog columns were changed from CNY naming to USD naming:
  - `input_usd_per_m`
  - `output_usd_per_m`
  - `cache_read_usd_per_m`

Latest screenshot folder:

```text
/mnt/OneDrive/cli传递/openmagic_api_screenshots_i18n_usd_20260522_060618/
```

## 2026-05-22 Admin Operations And Registration

Admin mutation endpoints now exist for build-phase operation:

```text
POST /backend/admin/plan/save/
POST /backend/admin/model/save/
POST /backend/admin/user/save/
POST /backend/admin/upstream/save/
POST /backend/admin/manual-adjust/
```

Admin pages with forms:

- `/admin/plans/` can create/update product plans in USD.
- `/admin/models/` can create/update model catalog rates in USD per million tokens.
- `/admin/users/` can update display name, user type, status, and downstream `rate_multiplier`.
- `/admin/upstreams/` can create/update upstream auth profiles.
- `/admin/manual-adjust/` can grant or deduct quota manually.

Downstream multiplier:

- Stored on `om_user_profile.rate_multiplier`.
- Default is `1.0000`.
- Values above `1` make the user more expensive; values below `1` discount the user.
- The multiplier is stored and editable, but the final token settlement hook still needs to apply it when production billing deduction is implemented.

Registration and email verification:

```text
POST /backend/auth/register/
GET  /backend/auth/verify-email/?token=...
```

Registration now:

- Validates email format and password length.
- Creates a One API user.
- Creates an OpenMagic business profile.
- Stores password hash in `om_user_profile.password_hash`.
- Marks the business profile `email_pending` until verification.
- Generates `verification_token` and returns the verification URL.

Email verification now:

- Clears `verification_token`.
- Sets `email_verified_at`.
- Sets user status to `active`.

Smoke result:

- Registered `smoke1779401551@openmagic.test`.
- Created One API user id `2`.
- Verified email successfully.

## 2026-05-22 Email Gateway Integration

Email verification initially only generated a local verification token and URL. It has now been wired to the existing Tianxun unified mail gateway instead of creating a separate SMTP stack for OpenMagic.

Implementation:

- `lib/MailGateway.php` calls the internal Tianxun mail HTTP endpoint.
- Mail source is marked as `openmagic_api`.
- The internal mail API key is stored encrypted in `api_openmagic_biz.om_secret_store`.
- Secret key name: `mail.tianxun.internal_key`.
- Registration records send status on `om_user_profile.verification_email_sent_at` and `om_user_profile.verification_email_error`.
- `POST /backend/auth/register/` still creates an `email_pending` user if the mail gateway rejects or fails, so the user can be handled later without losing the registration record.

Validation:

- PHP syntax checks passed for `lib/MailGateway.php`, `lib/AuthRepository.php`, and `config/app.local.php`.
- The Tianxun internal mail gateway was reached and authenticated through a smoke call. The smoke used an invalid recipient and received an expected gateway failure instead of an auth failure.

Operational note:

- Launch can reuse the existing Tianxun/Redgate Zoho mail gateway for speed and reliability.
- Before broader public traffic, OpenMagic should have its own sender identity for brand trust and deliverability. The recommended path is not a separate mail stack, but a source-specific OpenMagic sender account wired into the same Tianxun mail gateway.

## 2026-05-22 Admin Auth And Usage Settlement

Admin authentication now reuses the Tianxun admin/customer-service credential table:

- Source DB: `sktvf.wx_vps`
- Admin condition: `agent != 0`
- Login accepts username, email, or mobile plus the same password used by the Tianxun admin console.
- Customer-service profile rows are reused/created in `sktvf.wx_kf`.
- Because `api.openmagic.ai` and `tianxun.xyz` are different domains, browser sessions cannot be shared directly. OpenMagic shares the same credential table and permission model, then creates its own `OM_ADMIN_SESSID` session.

Protected surfaces:

- `/admin/*` now requires Tianxun admin login.
- `/backend/admin/*` mutation endpoints now return `401` without admin login.

Usage multiplier settlement:

- One API still performs the base quota deduction.
- OpenMagic scans `oneapi_core.logs`.
- For each new log, `om_user_profile.rate_multiplier` is applied.
- Formula: `settled_quota = ceil(oneapi_log.quota * rate_multiplier)`.
- Delta formula: `quota_delta = settled_quota - oneapi_log.quota`.
- Positive delta deducts extra quota; negative delta refunds quota.
- Rows are stored in `om_usage_settlement`.
- Checkpoint is stored in `om_usage_settlement_state`.
- Ledger rows are written to `om_balance_ledger` with `change_type = usage_quota`.

Production scheduler:

```text
/etc/cron.d/openmagic-usage-settlement
* * * * * root /usr/bin/php /www/wwwroot/api.openmagic.ai/scripts/settle_usage.php 500 >> /www/wwwroot/api.openmagic.ai/logs/usage-settlement.log 2>&1
```

Validation:

- Unauthenticated `/admin/` returns `401` with OpenMagic admin login form.
- Unauthenticated `/backend/admin/usage-settle/` returns JSON `401`.
- A real `gpt-4o-mini` request was sent through `https://api.openmagic.ai/v1/chat/completions`.
- One API logged base `quota=2`.
- User `oneapi_user_id=1` has `rate_multiplier=1.0500`.
- Settlement wrote `settled_quota=3`, `quota_delta=1`, proving the multiplier now affects actual quota accounting.

Registration UX:

- Public registration remains short: email, password, optional display name.
- Email verification uses the Tianxun mail gateway.
- Google and Apple sign-in are presented as pending production options. They require real Google OAuth client and Apple Developer Service ID/callback approval before enabling.

## 2026-05-22 User Console, Support Identity, And Mail Operations

User authentication:

- Added OpenMagic user session support with `OM_USER_SESSID`.
- `/login/` now accepts verified OpenMagic email/password accounts.
- `/console/*` now requires OpenMagic user login.
- `/console/account/` shows the real OpenMagic user id, One API user id, email, status, and rate multiplier.

Support widget identity:

- Guest website visitors still load the support widget without identity.
- Logged-in OpenMagic users pass support context through the existing widget attributes:
  - `data-username="OpenMagic #<user_id> / OneAPI #<oneapi_user_id> / <display_name>"`
  - `data-email="<account_email>"`
- The existing support `data-token` remains empty for OpenMagic users because the current客服系统 token verifier only trusts `sktvf.wx_vps.chat_token`. OpenMagic should not be forced into the VPN user table. If hard identity binding is needed later, extend the support API to verify OpenMagic tokens explicitly.

Mail operations:

- Added OpenMagic-local mail tables:
  - `om_mail_template`
  - `om_mail_log`
  - `om_mail_inbox`
- Added admin page:
  - `/admin/mail/`
- Added template save endpoint:
  - `POST /backend/admin/mail/template/save/`
- Default templates seeded:
  - `email_verify`
  - `payment_success`
  - `quota_low`
  - `password_reset`
- `MailGateway` now logs every OpenMagic mail locally before sending through the Tianxun gateway.
- Payment settlement now sends the `payment_success` template.

Validation:

- Registered and verified a console smoke user.
- Login created `OM_USER_SESSID`.
- `/console/account/` returned 200 after login.
- Support widget HTML included the logged-in user's OpenMagic id, One API id, and email.
- Created a logged-in user order for `trial_balance`; it belonged to `user_id=3`, `oneapi_user_id=3`.
- Mock settlement sent a `payment_success` email and wrote `om_mail_log`.

Developer docs:

- `/docs/clients/` now includes concrete setup guidance for:
  - OpenAI-compatible SDKs
  - Claude Code-style tools
  - Codex / OpenCode-style CLIs
  - Cursor
  - Cline / Roo Code / Continue
- The page includes base URL, API key, model, curl smoke test, and troubleshooting notes.

## 2026-05-22 Agent Starter And Demand Creation Docs

The public docs now include a demand-creation path for users who do not yet know which AI agent they need.

New public page:

```text
/docs/agents/
```

Purpose:

- Move beyond “paste Base URL and API key”.
- Help beginner users choose a useful AI coding/chat workflow.
- Provide one-line setup commands for macOS/Linux/WSL and Windows.
- Explain safe first tasks, default model choices, and failure boundaries.

New public install helpers:

```text
/assets/install/openmagic-agent-setup.sh
/assets/install/openmagic-agent-setup.ps1
```

Shell helper supports:

- `codex`
- `cline`
- `vscode`
- `roo`
- `cursor`
- `continue`
- `all`

Validation:

- PHP syntax passed for `/docs/agents/` and `/docs/clients/`.
- Shell script passed `bash -n`.
- Shell script test with `OPENMAGIC_API_KEY=sk-test ... vscode` wrote `~/.openmagic/openmagic-vscode-agents.md`.
- Public `/docs/agents/` returns 200.
- Public shell script URL returns 200.
- PowerShell runtime validation was not run because `pwsh` is not installed on the server.

Important routing note:

- Codex, Cline, Roo Code, Continue, Cursor, LobeChat, and NextChat can use OpenAI-compatible base URL patterns when their client version exposes custom provider settings.
- Claude Code is different: official docs support `ANTHROPIC_BASE_URL`, so OpenMagic now exposes an Anthropic-compatible conversion route at `https://api.openmagic.ai/anthropic`.

Current evidence sources reviewed:

- OpenAI Codex CLI install guidance.
- Claude Code install and environment variable docs.
- Cline CLI custom OpenAI base URL docs.
- Continue OpenAI-compatible `apiBase` docs.
- Roo Code OpenAI-compatible provider docs.
- LobeChat / NextChat OpenAI proxy environment guidance.

## 2026-05-22 Anthropic-Compatible Route

OpenMagic now supports a lightweight Anthropic Messages compatibility layer in addition to the existing OpenAI-compatible `/v1` route.

Public routes:

```text
POST /anthropic/v1/messages
GET  /anthropic/v1/models
```

Claude Code configuration:

```text
ANTHROPIC_BASE_URL=https://api.openmagic.ai/anthropic
ANTHROPIC_API_KEY=<OpenMagic API key>
```

Implementation:

- `lib/AnthropicCompat.php`
- `anthropic/v1/messages/index.php`
- `anthropic/v1/models/index.php`
- Nginx exact rewrites for no-trailing-slash POST safety:
  - `/anthropic/v1/messages`
  - `/anthropic/v1/models`

Current behavior:

- Accepts `x-api-key` or `Authorization: Bearer`.
- Accepts Anthropic Messages-style `model`, `system`, `messages`, `max_tokens`, `temperature`, and `top_p`.
- Converts text messages to OpenAI-compatible chat messages.
- Internally calls One API at `127.0.0.1:3000/v1/chat/completions`.
- Converts OpenAI chat response back to Anthropic Messages format.
- Current model aliases map to the available smoke route `gpt-4o-mini` until real Anthropic/Claude upstream channels are added.

Validation:

- PHP syntax checks passed.
- `GET https://api.openmagic.ai/anthropic/v1/models/` returns Anthropic-style model list.
- `POST https://api.openmagic.ai/anthropic/v1/messages` with `x-api-key` returned Anthropic-style response with text `OK`.
- Nginx config test passed and was reloaded with `/www/server/nginx/sbin/nginx -s reload`.

Known next step:

- Real Claude upstream channels are still required before advertising true Claude model quality. The compatibility layer itself now supports non-stream text, streaming text, basic tool-use conversion, and DB-backed model mapping.

## 2026-05-22 Anthropic Compatibility Completion Pass

User requested that everything not blocked by the real upstream environment should be completed instead of waiting.

Completed without needing real Claude upstream:

- Anthropic non-streaming Messages route.
- Anthropic SSE streaming route.
- Basic Anthropic `tools` to OpenAI `tools` conversion.
- Basic OpenAI `tool_calls` to Anthropic `tool_use` conversion.
- Anthropic `tool_result` input to OpenAI `tool` message conversion.
- DB-backed model mapping table:
  - `om_anthropic_model_map`
- Admin page:
  - `/admin/anthropic/`
- Admin save endpoint:
  - `POST /backend/admin/anthropic/model-map/save/`

Validation:

- PHP syntax checks passed.
- `POST /anthropic/v1/messages` non-stream request returned `OK`.
- `POST /anthropic/v1/messages` with `stream=true` returned Anthropic-style SSE events:
  - `message_start`
  - `content_block_start`
  - `content_block_delta`
  - `content_block_stop`
  - `message_delta`
  - `message_stop`
- Tool-use smoke request returned Anthropic content block `type=tool_use`, input `location=Hong Kong`, and `stop_reason=tool_use`.
- `/admin/anthropic/` is protected by admin login and returns `401` when unauthenticated.

Still blocked by real environment:

- True Claude upstream routing and model quality.
- Provider-specific Claude pricing/margins.
- Full production stress test with Claude Code against real Anthropic/Claude upstream.

## 2026-05-22 Agent Tutorial UX Upgrade

The Agent Starter page is not complete for every market tool yet. It has been upgraded from a text-only skeleton into a clearer beginner-facing interactive page.

Updated page:

```text
/docs/agents/
```

Current supported tutorial cards:

- Codex CLI
- Claude Code
- Cline
- Roo Code
- Continue
- Cursor
- LobeChat / NextChat
- Windsurf

UX changes:

- Adds an explicit status warning: the Agent tutorial is not fully complete yet.
- Adds installation strategy section:
  - Platform priority is Windows PowerShell first, macOS second, Linux/WSL third.
  - Use official npm/GitHub packages first.
  - OpenMagic provides bootstrap scripts and config snippets.
  - Do not distribute modified third-party packages yet.
  - Later stage can add cache mirrors, version locks, hash checks, and preconfigured templates.
- Adds prominent cards and tool tabs.
- Adds Copy buttons for macOS/Linux/WSL, Windows PowerShell, manual config, and first-task prompt templates.
- Adds safe first-prompt templates and security boundaries.

Validation:

- PHP syntax check passed for `/docs/agents/index.php`.
- Public `/docs/agents/` returns 200.
- Page contains copy controls and expected tool cards.
- Public page renders Windows PowerShell before macOS and Linux/WSL for each tool card.

Remaining tutorial work:

- Full Chinese/English/multilingual copy coverage for every new Agent section.
- Screenshot-level walkthroughs.
- Version-specific notes for Cursor/Windsurf custom provider support.
- Official source mirror/cache design for slow GitHub/npm regions.
- Hash verification and pinned versions for any local mirrored package.

## 2026-05-22 Admin Operations And Mobile Funnel

新增后台运维能力：

- `/admin/exit-nodes/`
  - 查看出口节点总数、健康节点、Provider account、路由规则数量。
  - 查看节点 host/IP/relay URL/status/health/weight/account/route。
  - 支持后台触发 DNS 校验和 health 校验。
  - 支持编辑节点基础字段：name、region、host、ip、relay_url、relay_key_secret、status、weight。
- `/admin/reports/`
  - 查看今日/7日充值收入、30日已支付订单、新用户、落地页访问、转化率、API 成功率、节点健康。
  - 查看充值明细，用于对账 Yuansfer 和两个 Stripe 账号。
  - 查看落地页 funnel：source/channel、访问、CTA 点击、注册、支付事件、访客数、访问到注册转化率。
  - 查看系统稳定性：24h 请求量、错误量、平均耗时、节点健康。

新增接口：

- `POST /backend/admin/exit-node/dns-check/`
- `POST /backend/admin/exit-node/health/`
- `POST /backend/admin/exit-node/save/`
- `POST /backend/analytics/landing/`

新增公共落地页统计：

- 非后台公共页面会记录 `page_view` 和 `cta_click`。
- 记录 `utm_source`、`utm_medium`、visitor id、path、referrer、lang、viewport。
- 默认 campaign 为 `api_openmagic_main`。

移动端适配：

- 公共页增加移动端底部营销 CTA：`Agent setup` 和 `Start now`。
- 手机宽度下导航横向滚动，主要按钮保持可点击。
- Hero 标题、按钮、视觉卡片、表格容器做移动端布局压缩。
- 后台不再加载前台客服脚本，避免运维页被悬浮客服按钮遮挡。

验证：

- PHP syntax check passed for updated/new PHP files.
- Public homepage returns 200 and contains mobile CTA + analytics script.
- Analytics endpoint accepts public page event and writes `om_campaign_event`.
- `/admin/exit-nodes/` and `/admin/reports/` require admin login when unauthenticated.
- Temporary admin session rendered both new admin pages with HTTP 200.
- Node DNS check: `telegram.redgate.pet -> 199.247.23.168`, matched stored IP.
- Node health check: relay URL `http://telegram.redgate.pet:18787`, HTTP 200, `ok=true`.
- Mobile screenshots saved:
  - `/www/wwwroot/tmp/aikf_screens/api-openmagic-mobile-home-20260522-v2.png`
  - `/www/wwwroot/tmp/aikf_screens/api-openmagic-mobile-admin-reports-20260522-v3.png`
  - `/www/wwwroot/tmp/aikf_screens/api-openmagic-mobile-admin-exit-nodes-20260522-v2.png`

## 2026-05-23 Singapore Exit Node And Multi-Node Admin

用户要求：

- 把 `S哥1 / 新加坡1号` 服务器也作为网页授权/出口节点候选。
- 必须复用免费节点上的同一套 agent/service/config 结构，不允许每个节点一套做法。
- 不破坏节点上现有 Nginx/V2Ray 服务。
- 管理后台要能管理多个节点、节点绑定账号、节点路由和状态。

节点来源：

- `sktvf.serverlist.id=2219`
- `node_id=1131`
- `name=SG 19`
- `area=sg`
- `ip=64.176.82.173`
- `host=vu-sg-01.redgate.pet`
- SSH port `1472`

已部署：

- SSH 使用现有节点私钥登录成功。
- 原有 `nginx`、`v2ray` 保持 active，未修改配置。
- 从免费节点复制并复用：
  - `/opt/openmagic-exit-agent/openmagic_exit_agent.py`
  - `/etc/systemd/system/openmagic-exit-agent.service`
  - `/etc/openmagic-exit-agent/config.json`
- 新加坡节点配置：
  - `node_id=sg_vu_01`
  - `source_node_id=1131`
  - `region=sg`
  - `bind=0.0.0.0`
  - `port=18787`
  - `provider=openai`
  - `upstream=https://api.openai.com`
- systemd 服务：
  - `openmagic-exit-agent`
  - enabled + active
  - listening on `*:18787`

数据库配置：

- `om_exit_node`
  - `node_code=sg_vu_01`
  - `relay_url=http://64.176.82.173:18787`
  - `callback_base_url=https://vu-sg-01.redgate.pet`
  - `oauth_redirect_path=/oauth/callback/openai`
  - `status=testing`
- `om_exit_provider_account`
  - `sg_vu_01_openai_01` / `openai` / `api_key` / `testing`
  - `sg_vu_01_openai_oauth_01` / `openai` / `oauth_refresh_token` / `standby`
  - `sg_vu_01_apple_oauth_01` / `apple` / `oauth_refresh_token` / `standby`
  - `sg_vu_01_google_oauth_01` / `google` / `oauth_refresh_token` / `standby`
- `om_exit_node_route`
  - `node_test_sg_vu_01_gpt4omini`
  - `oneapi_user_id=4`
  - `provider=openai`
  - `model_pattern=gpt-4o-mini`
  - `status=testing`

后台补齐：

- `/admin/exit-nodes/`
  - 增加“节点账号矩阵”，按节点展示 Relay、OAuth Redirect、账号绑定和路由规则。
  - 节点表保留 DNS/健康检查操作。
  - 增加“保存上游账号绑定”表单。
  - 增加“保存路由规则”表单。
- 新增接口：
  - `POST /backend/admin/exit-node/account/save/`
  - `POST /backend/admin/exit-node/route/save/`

验证：

- PHP syntax checks passed:
  - `/lib/ExitNodeRepository.php`
  - `/admin/exit-nodes/index.php`
  - `/backend/admin/exit-node/account/save/index.php`
  - `/backend/admin/exit-node/route/save/index.php`
- 管理后台 `/admin/exit-nodes/` 使用临时管理员 session 返回 HTTP 200。
- 后台页面能看到 `sg_vu_01`、`vu-sg-01.redgate.pet`、OpenAI/Apple/Google 账号槽位、OAuth Redirect、测试路由。
- 账号保存接口幂等保存 `sg_vu_01_openai_01` 成功。
- 路由保存接口幂等保存 `node_test_sg_vu_01_gpt4omini` 成功。
- DNS check:
  - `vu-sg-01.redgate.pet -> 64.176.82.173`
  - `matched=true`
- Health check:
  - `http://64.176.82.173:18787/health`
  - HTTP 200
  - `ok=true`
  - latency about `6ms`
- SG 节点真实上游 smoke test：
  - 通过 relay key 请求 `/v1/models`
  - 返回 OpenAI model list

当前边界：

- 节点 agent 当前支持 `/health` 和 `/v1/*` 代理。
- OAuth/web 授权账号槽位、callback URL 和 state secret 已建好，但完整 OAuth callback/token exchange 还未接入 provider 真实 OAuth client。
- 如果后续要让 callback 也落到节点侧，需要在 agent 中增加 `/oauth/callback/{provider}` 处理器，或者由主站统一接 callback 后按节点写入凭证。

## 2026-05-23 CCProxy / CCConnector Research

用户提到的名称更接近 `CCProxy`，当前可分为两类：

- Orchestre `ccproxy`
  - 定位：Claude Code 本地代理，把 Anthropic/Claude Code 请求转到 OpenAI、Gemini、DeepSeek、OpenRouter 等供应商。
  - 使用方式：本地启动 `ccproxy`，再设置 `ANTHROPIC_BASE_URL=http://localhost:3456`。
  - 重点能力：模型路由、SSE 流式、函数调用、健康检查、日志、Docker 部署。
  - 限制：它不会给 Claude Code 增加模型本身没有的能力，本质是协议转换和路由。
- CaddyGlow `ccproxy-api`
  - 定位：本地插件式反向代理，统一 Claude/Codex/GitHub Copilot 等 provider。
  - 特点：支持 Claude SDK/API、Codex OAuth、Copilot；有插件、日志、trace、metrics/analytics；可复用本地 Claude/Codex token 文件或通过 CLI 做 OAuth。

对 OpenMagic 的判断：

- 不建议把 CCProxy 放到 OpenMagic 服务端主链路替代 One API。
- 它更适合放在用户教程和安装脚本里，作为“Claude Code / Codex 本地高级适配器”。
- 我们服务端仍保持：
  - 用户只认 `https://api.openmagic.ai`
  - OpenAI-compatible `/v1`
  - Anthropic-compatible `/anthropic`
  - 后台节点路由决定实际出口节点和上游账号
- 后续可以提供一个 OpenMagic 预设的本地配置模板：
  - Windows PowerShell 优先。
  - 自动写入 `ANTHROPIC_BASE_URL=https://api.openmagic.ai/anthropic`
  - 自动写入 `OPENAI_BASE_URL=https://api.openmagic.ai/v1`
  - 不在用户本地保存我们的上游真实 key，只保存用户自己的 OpenMagic key。

## 2026-05-25 Launch Operations Dashboard And Front Docs Pass

用户要求：

- 自查距离上线运营还缺什么。
- 能做的先做完，包括前台、后台、营销、接口、底层、监控大屏。
- 后台首页大屏不能只看几个总数，要看到收入、Token、用户、复购、模型、供应商、节点和异常。
- 前台说明要详细、准确、多语适配。
- 最后给出需要用户配合的清单。

已完成：

- 新增 `lib/OpsDashboardRepository.php`。
- 后台首页 `/admin/` 改为运营监控大屏。
- 新增后台 JSON 接口：
  - `GET /backend/admin/dashboard/`

大屏当前指标：

- 核心指标：
  - 今日收入
  - 今日请求
  - 今日 Token
  - 今日额度消耗
  - 今日新增用户
  - 今日复购用户
  - 24h API 成功率
  - 健康节点
- 趋势：
  - 14 日收入趋势
  - 14 日 One API 用量趋势
- 分布：
  - 最近 7 天模型用量
  - 最近 7 天供应商/通道用量
  - 最近 7 天出口节点用量
- 经营：
  - 用户与复购健康
  - 最近支付
- 运维：
  - 最近错误
  - One API 可用渠道
  - One API 可用 Key
  - 出口节点健康
  - 待处理企业线索
  - 最近 7 天邮件失败
  - 可解密短期载荷数量

数据来源：

- `api_openmagic_biz`
  - `om_payment`
  - `om_order`
  - `om_user_profile`
  - `om_subscription`
  - `om_exit_node`
  - `om_request_trace`
  - `om_request_payload_log`
  - `om_mail_log`
  - `om_enterprise_lead`
- `oneapi_core`
  - `logs`
  - `channels`
  - `tokens`

前台说明更新：

- `/docs/quickstart/`
  - 改为生产接入路径。
  - 明确注册、充值/套餐、创建 Key、Base URL。
  - 增加 curl 和 Python 可复制请求。
  - 明确 `/v1` 和 `/anthropic` 两套 endpoint。
  - 增加正式使用前 checklist。
- `/docs/billing/`
  - 改为生产计费说明。
  - 明确钱包余额、月度额度、团队/企业三种模式。
  - 明确订单、支付、额度、API key、推荐奖励在用户控制台可见。
  - 明确 USD 计价、模型倍率、公平使用、退款对账等运营规则。
- `/models/`
  - 增加 provider routing policy。
  - 明确官方优先供给、节点绑定账号、用户无感 fallback。
- `assets/i18n/openmagic-i18n.js`
  - 增加新增前台核心文案的多语词条，继续沿用浏览器语言自动适配。

验证：

- PHP syntax checks passed:
  - `lib/OpsDashboardRepository.php`
  - `admin/index.php`
  - `backend/admin/dashboard/index.php`
  - `docs/quickstart/index.php`
  - `docs/billing/index.php`
  - `models/index.php`
- JS syntax check passed:
  - `assets/i18n/openmagic-i18n.js`
- 后台 HTML：
  - `/admin/` 使用临时管理员 session 返回 HTTP 200。
  - 页面包含运营监控大屏、今日收入、模型用量、出口节点用量、最近错误。
- 后台 JSON：
  - `/backend/admin/dashboard/` 使用临时管理员 session 返回 HTTP 200。
  - JSON `ok=true`，返回 8 个核心 stats。
- 前台页面：
  - `/docs/quickstart/` 返回 HTTP 200。
  - `/docs/billing/` 返回 HTTP 200。
  - `/models/` 返回 HTTP 200。

仍需生产配合：

- 真实支付网关账号和 webhook 在网关后台确认。
- 真实模型上游账号、OAuth client、provider 回调权限确认。
- Cloudflare/CDN 最终路由切换确认。
- 正式邮箱域名、发件信誉、模板内容确认。
- 投流渠道、主站 WordPress 导流策略、客服品牌入口确认。

## 2026-05-25 OpenMagic Stripe Account Wiring

参考 `url.cr`：

- Stripe 创建链路：
  - `pay/ios.ashx` 创建 `wx_trade` pending order。
  - Stripe vendor 跳转到 `pay/stripe_checkout.aspx?sender=...&vendor=...&trade_no=...`。
  - 前端调用 `/api/stripecheckout` 创建 Stripe Checkout Session。
  - metadata 写入 `trade_no`。
- Stripe webhook：
  - `api/stripewebhook_redgate20231016.ashx`
  - `api/stripewebhook_redspeed20231016.ashx`
  - 验证 `Stripe-Signature`。
  - 只处理 `payment_intent.succeeded`。
  - 从 `data.object.metadata.trade_no` 取订单号，从 `data.object.id` 取 transaction id。
  - 最终调用 `payFinish(trade_no, transaction_id)`。

OpenMagic 对应实现：

- 默认 Stripe sender 改为 `openmagic`。
- OpenMagic 不需要区分 RedGate / RedSpeed sender。
- 新增无 sender webhook：
  - `https://api.openmagic.ai/backend/payment/stripe/webhook/`
- 保留旧兼容 webhook：
  - `/backend/payment/stripe/redgate/webhook/`
  - `/backend/payment/stripe/redspeed/webhook/`
- `PaymentRepository::createStripeCheckout()` metadata 新增：
  - `trade_no`
  - `product_id`
  - `openmagic_product_id`
  - `openmagic_sender`
  - `openmagic_vendor`
- `PaymentRepository::handleStripeWebhook('openmagic', ...)` 成功后调用：
  - `BillingRepository::settleGatewayPayment(order_no, 'stripe', transaction_id, event)`

小额测试产品：

- 新增 plan：
  - `stripe_smoke_099`
  - `Stripe Smoke Test`
  - `$0.99 USD`
  - active

新增导入脚本：

```text
php scripts/import_stripe_openmagic_keys.php /mnt/OneDrive/cli传递/openmagic_stripe_keys.json
```

支持 JSON 字段：

```json
{
  "publishable_key": "pk_live_...",
  "secret_key": "sk_live_...",
  "webhook_secret": "whsec_..."
}
```

支持 ENV 字段：

```text
STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
```

验证：

- PHP syntax passed：
  - `lib/PaymentRepository.php`
  - `backend/payment/stripe/create/index.php`
  - `backend/payment/stripe/webhook/index.php`
  - `scripts/import_stripe_openmagic_keys.php`
- `$0.99` dry-run checkout 创建成功：
  - plan_code `stripe_smoke_099`
  - order amount `$0.99`
  - webhook URL `https://api.openmagic.ai/backend/payment/stripe/webhook/`
  - metadata product_id `stripe_smoke_099`
- 当前阻塞真实 Stripe Checkout：
  - 传递目录尚未发现包含 `pk_live/sk_live/whsec` 的文本 key 文件。
  - 加密密钥库中 `payment.stripe.openmagic.public_key`、`secret_key`、`webhook_secret` 仍为 missing。
