Go to file
dev bdce02d9ed web: give a tool its own page instead of sharing the index 2026-10-01 11:31:26 +08:00
content web: fix the outline anchors, level the outline, and fold the sidebar chapters 2026-10-01 11:00:09 +08:00
docs web: give a tool its own page instead of sharing the index 2026-10-01 11:31:26 +08:00
frontend web: give a tool its own page instead of sharing the index 2026-10-01 11:31:26 +08:00
scripts web: add the apsis-web service, content, and frontend 2026-09-27 00:53:20 +08:00
src web: fix the outline anchors, level the outline, and fold the sidebar chapters 2026-10-01 11:00:09 +08:00
tests web: correct the asset cache policy, serve the flow index, and drop a stray artifact 2026-10-01 07:35:56 +08:00
.gitignore web: correct the asset cache policy, serve the flow index, and drop a stray artifact 2026-10-01 07:35:56 +08:00
Cargo.lock web: add the apsis-web service, content, and frontend 2026-09-27 00:53:20 +08:00
Cargo.toml web: add the apsis-web service, content, and frontend 2026-09-27 00:53:20 +08:00
LICENSE web: add the apsis-web service, content, and frontend 2026-09-27 00:53:20 +08:00
README.md web: name assets with a content hash so a stale bundle cannot be served 2026-10-01 09:06:10 +08:00
build.rs web: add the apsis-web service, content, and frontend 2026-09-27 00:53:20 +08:00
rust-toolchain.toml web: add the apsis-web service, content, and frontend 2026-09-27 00:53:20 +08:00

README.md

apsis-web

The web service layer of ApsisRS. It presents the ApsisRS computational kernels for commercial spaceflight and satellite internet systems in a browser: the concept documentation, a knowledge graph, the interface documentation extracted from the library source, and an online tool set that runs the kernels on parameters the user supplies.

The service builds to a single binary that embeds every asset it serves. It does not read a content directory or a frontend build at run time, and it does not need either to be present next to the binary.

What it serves

Section Content Route prefix
Concepts Documents on the time scales, the reference frames, the element formats, and the propagation models, with the units and the applicable range of each /api/docs
Knowledge graph The concepts and their relationships, plus the crate structure of the library and the algorithm flow graphs /api/graph
Interface The public interface of the ApsisRS layers the service builds against, extracted from the source doc comments /api/api
Online tools TLE parsing, SGP4 propagation, track sampling, time scale conversion, coordinate conversion, frame rotation, Keplerian conversion, and Hohmann transfer planning /api/tools

Design constraints

The service follows the constraints of the workspace it belongs to.

  • One runtime dependency. The only entry in [dependencies] is apsis-rs, through a path dependency. The HTTP server, the JSON codec, the router, the Markdown renderer, and the graph model are all written against the standard library.
  • No unsafe. The crate does not contain an unsafe block.
  • No panic in a request path. A malformed request, a bad parameter, or a failing computation produces a response, not a panic. The worker that serves a request catches a panic in the handler as a final guard and answers with a server error.
  • Self-contained comments. Every comment explains the code, the algorithm, the interface, or the project. No comment refers to a private document, an instruction, or a plan.

Building

The frontend must be built before the release binary so that its output can be embedded. A release build does this automatically.

Every built asset carries a content hash in its name, so replacing the binary replaces those names. A browser therefore cannot be holding a stale bundle: the new bundle is requested under a URL it has never seen. The entry point is served with no-cache, must-revalidate, and hashed assets with public, max-age=31536000, immutable. The service registers no service worker.

# Development: a debug build embeds whatever is in frontend/dist and does
# not run the frontend build.
cargo build

# Release: build.rs builds the frontend and embeds the result.
cargo build --release

The binary is at target/release/apsis-web.

Environment variables:

Variable Effect
APSIS_WEB_HOST Interface to bind, default 127.0.0.1
APSIS_WEB_PORT Port to bind, default 8080
APSIS_WEB_ADDRESS Bind address as HOST:PORT, overriding the two above
APSIS_WEB_WORKERS Worker threads, default 4
APSIS_WEB_SKIP_FRONTEND Set to 1 to skip the frontend build in a release build
APSIS_WEB_FRONTEND_DIR Frontend directory, default frontend

Command line options override the environment:

# Bind every interface on port 8080.
apsis-web --host 0.0.0.0 --port 8080

# The combined form is equivalent.
apsis-web --address 0.0.0.0:8080

--host and --port may be given together. --address cannot be combined with either of them, because the order in which they would apply is not defined. A host may be a literal address, an IPv6 literal in brackets, or a name the operating system resolves.

Language

The interface is bilingual and opens in Chinese. The reader switches to English with the control in the top bar; the choice is stored in the browser and applies to every page.

The backend carries every user facing string in both languages, so the switch takes effect without a request. A concept document is written once in English as content/concepts/<id>.md and translated as content/concepts/<id>.zh.md. A document without a translation is shown in English to every reader, with a note saying so.

Running

./target/release/apsis-web --address 127.0.0.1:8080

Open http://127.0.0.1:8080. The JSON interfaces are available without the frontend:

  • GET /health
  • GET /api/docs, GET /api/docs/<id>, GET /api/docs/search?q=
  • GET /api/graph, GET /api/graph/crates, GET /api/graph/flows, GET /api/graph/<flow>
  • GET /api/api, GET /api/api/crates/<name>, GET /api/api/items/<name>
  • GET /api/tools, GET /api/tools/<id>, POST /api/tools/<id>/run

A tool call takes a JSON object of parameters and returns a shaped result:

curl -s http://127.0.0.1:8080/api/tools/hohmann-transfer/run \
  -H 'content-type: application/json' \
  -d '{"from_radius": 6778, "to_radius": 42164}'

Regenerating the interface catalog

The interface documentation is generated from the ApsisRS sources rather than written by hand. Run the extractor from this directory when the sources change, then rebuild:

scripts/extract_api.sh
cargo build --release

The script reads the workspace at ../apsis-rs by default; set APSIS_RS_WORKSPACE to point at a checkout elsewhere. It requires Python 3.8 or later. The Rust build does not run it and does not depend on Python.

Editing the content

Path Contents
content/concepts/chapters.json Chapter list and the reading order of documents, with bilingual titles
content/concepts/*.md Concept documents, with a key: value metadata header
content/concepts/*.zh.md Chinese translations; the identifier comes from the file name
content/graph/concepts.json The concept graph
content/flows/*.json The algorithm flow graphs
content/api.json The generated interface catalog; do not edit by hand
content/api.zh.json Chinese translations of the crate summaries and item doc comments

A document header declares id, title, chapter, summary, tags, and prerequisites. A cross reference is written [[id]] or [[id|label]] and renders as a link that the frontend routes without a page load.

Layout

apsis-web/
├── build.rs                  embed the frontend build and the text content
├── Cargo.toml                one runtime dependency: apsis-rs
├── content/                  authored documents, graphs, and generated catalog
├── frontend/                 Svelte and TypeScript, built by Vite
│   ├── src/lib/              API client, router, components, formatting
│   ├── src/pages/            one component per route
│   └── dist/                 build output, embedded by build.rs
├── scripts/extract_api.sh    interface catalog generator
├── src/
│   ├── api/                  the router and the JSON payloads
│   ├── docs/                 content, Markdown, documents, interface catalog
│   ├── embedded/             access to the embedded frontend assets
│   ├── graph/                the knowledge graph and the flow graphs
│   ├── http/                 request, response, and server
│   ├── tools/                the tool registry, the handlers, the result shape
│   ├── json.rs               the JSON codec
│   ├── main.rs               the process entry point
│   └── state.rs              the parsed content, shared by every worker
└── tests/service.rs          end to end tests against the built binary

Testing

cargo test          # unit tests and end to end tests
cargo clippy --all-targets
cargo fmt --check
cd frontend && npm run check

The end to end tests start the built binary on an ephemeral port and make plain TCP requests against it.

License

MIT OR Apache-2.0. See LICENSE-MIT and LICENSE-APACHE.