4.7 KiB
storyteller-web
The main HTTP API monolith. This is the backend for the ArtCraft application.
Building
cargo check -p storyteller-web
There are ~370 pre-existing warnings. Check the last 8-10 lines of output for actual errors.
Structure
src/http_server/endpoints/- HTTP handlers organized by featuresrc/http_server/middleware/- Actix middleware (error alerting, etc.)src/http_server/common_responses/- Shared error types (CommonWebError)src/http_server/web_utils/- Session checking, auth helperssrc/state/- Server state, feature flagssrc/startup/- Initialization (pager, etc.)src/threads/- Background threads (health checker, etc.)src/docs/- OpenAPI/Swagger documentation (api_doc.rs)
Handler Pattern
Handlers return Result<Json<Response>, ErrorType>. The Result<HttpResponse, ErrorType> pattern is
deprecated or only used when setting other HTTP headers, like cookies.
Prefer CommonWebError for new handlers unless you need custom error variants.
The session helpers (require_user_session, require_user_session_extended, require_moderator
in http_server/web_utils/user_session/) take a generic mysql_executor argument. Pass an
already-open connection (&mut *conn) so the helper reuses it; do NOT pass
&server_state.mysql_pool when the handler already holds a connection, since that self-acquires a
second one and adds pool pressure (this crate has had pool-timeout incidents). There is no
require_user_session_using_connection / require_moderator_using_connection — the
reuse-vs-acquire behavior is determined by the argument.
Database Access
Do NOT write SQLx queries in this crate. storyteller-web contains zero direct SQLx queries —
all MySQL access goes through the mysql_queries crate. Add a function there (or reuse an existing
one) and call it from the handler; never embed sqlx::query! / sqlx::query() in a handler or
helper here. See crates/schema/database/mysql_queries/CLAUDE.md for the query-writing conventions
(compile-time query! / query_as! macros, offline cache, the Args/Executor pattern, etc.).
api_doc.rs
When adding new request/response/error types, add them to src/docs/api_doc.rs in the
schemas section (alphabetically sorted). Types from artcraft_api_defs need explicit imports.
Running locally
Environment variables are auto-loaded by Rust at startup from these files:
.env(repo root)crates/service/web/storyteller_web/config/storyteller-web.common.envcrates/service/web/storyteller_web/config/storyteller-web.development.envcrates/service/web/storyteller_web/config/storyteller-web.development-secrets.env
Do NOT use SQLX_OFFLINE=true — the server needs live DB access.
# From the repo root, just run:
cargo run --bin storyteller-web
The server binds to 0.0.0.0:12345 by default. Compilation takes ~3 minutes on first build.
Testing endpoints with curl
# 1. Log in to get session cookies:
curl -s -c /tmp/cookies.txt -X POST http://localhost:12345/v1/login \
-H "Content-Type: application/json" \
-d '{"username_or_email":"newuser4","password":"newuser4"}'
# 2. Generate video (Seedance 2.0 Fast):
# Requires a UUID-format idempotency_token.
curl -s -b /tmp/cookies.txt -X POST http://localhost:12345/v1/omni_gen/generate/video \
-H "Content-Type: application/json" \
-d '{
"model": "seedance_2p0_fast",
"prompt": "a corgi running through a field",
"duration_seconds": 5,
"aspect_ratio": "wide_sixteen_by_nine",
"idempotency_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'
# 3. Generate video (Seedance 2.0, 720p):
curl -s -b /tmp/cookies.txt -X POST http://localhost:12345/v1/omni_gen/generate/video \
-H "Content-Type: application/json" \
-d '{
"model": "seedance_2p0",
"prompt": "a corgi running through a field",
"duration_seconds": 5,
"resolution": "seven_twenty_p",
"aspect_ratio": "wide_sixteen_by_nine",
"idempotency_token": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}'
A successful response returns 200 with {"success": true, "inference_job_token": "jinf_..."}.
Notes:
idempotency_tokenmust be UUID format (32 hex chars or 36 with dashes)resolutionuses enum names:four_eighty_p,seven_twenty_p,ten_eighty_paspect_ratiouses enum names:wide_sixteen_by_nine,tall_nine_by_sixteen,square, etc.- Use a new
idempotency_tokenfor each request to avoid duplicate detection
Pager Integration
- The
Pageris available onServerStateasserver_state.pager - Health check handler sends alerts when unhealthy
- Error alerting middleware sends alerts on HTTP 500s (when enabled)
- Use
NotificationDetailsBuilderfor constructing alerts