9.6 KiB
System Service Control
This document defines the fixed mapping between admin control-plane actions and
the existing planet.sh service-management commands.
The goal is to reuse the current operational script semantics without exposing arbitrary shell execution to the frontend or API callers.
Scope
- This mapping is for admin-side operational controls only.
- The control plane must submit a fixed action name, not a raw shell command.
- The backend is responsible for translating an allowed action into a fixed
planet.shinvocation.
Design Rules
- Only whitelist actions may be executed.
- The frontend must never send arbitrary shell strings.
- The backend must build command arguments from a fixed mapping table.
- High-risk actions should be restricted to
super_admin. - Prefer partial restarts over full-stack restarts when UI continuity matters.
Action Mapping
| Action name | Intended use | planet.sh command |
Notes |
|---|---|---|---|
restart-backend |
Restart backend API only | ./planet.sh restart -b |
Recommended first implementation for UI-triggered restart flows. |
restart-database |
Restart PostgreSQL and Redis containers | ./planet.sh restart -d |
Useful when database/cache services need a controlled bounce without restarting the UI. |
restart-system |
Restart the whole application stack | ./planet.sh restart |
Frontend continuity breaks briefly; UI should switch to guided recovery mode. |
restart-frontend |
Restart frontend dev server only | ./planet.sh restart -f |
Use with caution; UI continuity is weaker than backend-only restart. |
restart-backend-port |
Restart backend on a specific port | ./planet.sh restart -b <port> |
Port must be backend-validated before execution. |
restart-frontend-port |
Restart frontend on a specific port | ./planet.sh restart -f <port> |
Port must be backend-validated before execution. |
health-check |
Read current service health | ./planet.sh health |
Safe read-only operational action. |
show-logs-backend |
Inspect backend logs | ./planet.sh log -b |
Best used for CLI/operator tooling, not normal Web UI streaming. |
show-logs-frontend |
Inspect frontend logs | ./planet.sh log -f |
Best used for CLI/operator tooling, not normal Web UI streaming. |
Not Exposed In UI By Default
The following existing script capabilities should not be exposed directly in the Web UI unless there is an explicit product need and an additional safety review:
./planet.sh restart./planet.sh start./planet.sh stop./planet.sh createuser- any future raw shell passthrough
Reason:
- full restart can break the current control session;
- stop/start have larger blast radius;
- user creation is not a service-control operation;
- raw shell passthrough creates unnecessary privilege risk.
Recommended First-Phase UI Contract
Frontend action payload
{
"action": "restart-backend"
}
Backend command resolution
restart-backend -> ["./planet.sh", "restart", "-b"]
restart-database -> ["./planet.sh", "restart", "-d"]
restart-system -> ["./planet.sh", "restart"]
restart-frontend -> ["./planet.sh", "restart", "-f"]
health-check -> ["./planet.sh", "health"]
API Draft
Primary Endpoint
POST /api/v1/system/restart-tasks
Purpose:
- create a controlled restart task;
- resolve a whitelist action into a fixed
planet.shcommand; - hand execution off to an external runner or detached subprocess.
Request Body
{
"action": "restart-backend"
}
Optional future shape:
{
"action": "restart-backend-port",
"port": 8000
}
Response
{
"task_id": "restart_20260331_153000_ab12cd",
"action": "restart-backend",
"status": "queued",
"stage": "accepted",
"message": "Restart task accepted"
}
Task Query Endpoint
GET /api/v1/system/restart-tasks/{task_id}
Response shape:
{
"task_id": "restart_20260331_153000_ab12cd",
"action": "restart-backend",
"status": "queued",
"stage": "accepted",
"message": "Waiting for execution",
"requested_by": {
"id": 1,
"username": "admin"
},
"created_at": "2026-03-31T15:30:00+08:00",
"updated_at": "2026-03-31T15:30:02+08:00"
}
Optional Log Endpoint
GET /api/v1/system/restart-tasks/{task_id}/logs
Suggested response:
{
"task_id": "restart_20260331_153000_ab12cd",
"lines": [
"accepted restart-backend request",
"spawning restart command",
"waiting for backend shutdown",
"waiting for backend health recovery"
]
}
This log endpoint is optional for phase one. The first version can work with
task state plus /health polling alone.
Task State Model
Status
queuedrunningsucceededfailedtimeout
Stage
acceptedspawningstoppingstartingwaiting_for_healthhealthyfailed
Interpretation
statusis the high-level terminal or non-terminal state.stageis the operator-facing execution phase for the UI.messageis the short human-readable line shown in the modal or full-screen overlay.
Permission Model
restart-backendshould requiresuper_admin.- Permission checks should follow the same role pattern already used in users.py.
- Frontend visibility may hide controls for non-
super_admin, but backend must still enforce authorization.
Storage Model
Recommended first implementation:
- store restart task state in Redis;
- keep task lifetime short;
- keep recent logs as a bounded list.
Suggested keys:
system:restart_task:{task_id}system:restart_task:{task_id}:logs
Suggested stored fields:
task_idactionstatusstagemessagerequested_by_idrequested_by_usernamecreated_atupdated_at
Execution Model
The request-handling API process should not depend on itself surviving long enough to stream the whole restart output.
Recommended execution flow:
- validate caller and action
- create task state in Redis
- resolve action to fixed
planet.shargv - spawn detached executor
- return
task_id - executor updates task state while restart is in progress
- frontend polls health and/or task state until recovery
Recommended command resolution examples:
restart-backend -> ["./planet.sh", "restart", "-b"]
restart-frontend -> ["./planet.sh", "restart", "-f"]
restart-backend-port -> ["./planet.sh", "restart", "-b", "<port>"]
health-check -> ["./planet.sh", "health"]
Frontend Polling Flow
Recommended first-phase UX:
- user clicks
重启后端 - confirmation modal explains temporary unavailability
- frontend calls
POST /api/v1/system/restart-tasks - UI enters blocking restart state
- frontend polls
/healthevery1-2s - temporary request failures are treated as expected
- after
2-3consecutive successful health checks, frontend reloads page
Optional richer polling:
- poll task status endpoint while backend is still reachable
- switch to
/healthrecovery polling after disconnect begins - refresh page after health recovery
Frontend State Machine
idleconfirmingsubmittingwaiting_for_shutdownwaiting_for_recoveryrecoveredfailedtimeout
Suggested UI messages:
已发送重启指令正在停止后端服务正在等待服务恢复服务已恢复,正在刷新页面恢复超时,请手动检查服务状态
Phase-One Recommendation
Implement only the following in phase one:
restart-backendsuper_adminpermission gate- task creation endpoint
- Redis-backed task state
- frontend confirmation modal
- frontend
/healthpolling - automatic page reload after recovery
Do not implement in phase one:
- full
./planet.sh restart - raw shell command passthrough
- arbitrary service control
- full terminal stdout streaming
- multi-action concurrent restart queueing
Implementation Checklist
Backend
- add a dedicated system-control API module under
backend/app/api/v1/ - add a whitelist-based action resolver for
planet.sh - store restart task state in Redis
- add detached restart-runner script execution
- expose:
POST /api/v1/system/restart-tasksGET /api/v1/system/restart-tasks/{task_id}- optional task log endpoint
- enforce
super_adminpermission on all restart-task endpoints
Frontend
- add a
重启后端control on the dashboard forsuper_admin - show a confirmation modal before dispatch
- after submission, switch modal into blocking restart state
- poll
/healthuntil backend recovery is confirmed - auto-refresh page after consecutive successful health checks
- show short stage-oriented logs instead of raw terminal streaming
Operational Notes
- phase one should target backend-only restart
- frontend restart should remain out of scope initially
- command execution must always originate from repository root
- only fixed action names may cross the API boundary
Validation Requirements
- Reject any action not present in the whitelist.
- If a port-bearing action is added, validate the port as an integer in
1..65535. - Resolve commands from the repository root so
planet.shruns with a stable working directory. - Record the requested action, operator identity, execution start time, and result.
Implementation Guidance
- For UI-triggered restart flows, prefer
restart-backendfirst. - Do not rely on the current API request process to stream full restart output after it triggers its own restart.
- Use a task record plus polling/health-check recovery flow instead of raw terminal streaming as the primary UX.