Imported from TheSeems/flink-fuchsia (
AGENTS.md). Install upstream withnpx skills add TheSeems/flink-fuchsia. Copyright stays with the author.
AGENTS.md
Guidance for AI coding agents (and humans) working in this repository. Keep it current when the architecture changes.
What Fuchsia is
Fuchsia is a no-fork reskin of the Apache Flink web dashboard, extensible in both the UI and the
backend. It ships as a small set of JARs you drop into a Flink cluster's lib/ directory — no Flink
patch, no separate service. On startup it installs a handler into the JobManager's existing Netty
REST pipeline that:
- Gates every request through a pluggable
FuchsiaAuthorizer(authenticate → authorize), and - Serves a modern Svelte single-page app plus a few
/fuchsia/*endpoints, while - Forwarding allowed requests to Flink's own REST API unchanged — so the full Flink API stays available behind whatever auth you plug in.
Three extension seams carry the pitch (see Writing a plugin): authorization first — RBAC is the gap Flink leaves open — then runtime UI sections and your own endpoints.
Repository layout
flink-fuchsia-api/ The plugin API (authorizers + server plugins/endpoints). Plugin authors compile
against ONLY this. Flink is compileOnly and surfaces only in the server-plugin
types (PluginContext, ClusterInfo); no Netty. Package root: me.theseems.fuchsia.api
(subpackages: http, plugin, security, operation)
flink-fuchsia-web/ The Svelte 5 SPA (Vite). Built into a resources jar (assets under web/); keeps
frontend/ the Node/Vite toolchain out of the Java modules. core bundles this jar.
flink-fuchsia-core/ The gate + endpoints + the built-in token auth (server/builtin) — the deployable
UI jar (bundles the SPA). Package: me.theseems.fuchsia.{bootstrap,server}
The default-auth UI lives at flink-fuchsia-web/frontend/src/builtin/default-auth.
plugins/
flink-fuchsia-plugin-auth-unrestricted/ Standalone authorizer granting full access — drop in lib/ to bypass auth.
examples/
flink-fuchsia-plugin-example/ Reference runtime-loaded UI plugin, no SPA rebuild. Never released.
complex-topology-job/ Demo Flink job (~33 vertices, CPU hotspot) to exercise the DAG
visualizer's busy/backpressure coloring. Submit via bin/flink run.
docker/ Images, built with the repo root as context.
flink-fuchsia/ Official flink image + the Fuchsia jar in lib/; stock entrypoint.
demo/ FROM the above + demo job + entrypoint.sh (JM+TM in one container).
Gradle multi-module; see settings.gradle.kts. Group me.theseems; the shared version lives in
gradle/libs.versions.toml.
Commands
All from the repo root unless noted.
# Build every module jar (the core fat-jar bundles :flink-fuchsia-api + :flink-fuchsia-web).
# The Svelte SPA is built automatically (:flink-fuchsia-web's buildFrontend → processResources) and packed into the jar.
./gradlew jar
# → flink-fuchsia-core/build/libs/flink-fuchsia-core-<version>.jar (the deployable UI jar)
# → plugins/*/build/libs/*.jar (standalone drop-in plugins)
# Frontend-only dev loop (hot reload). Vite serves on :5173 and proxies API calls to a running
# cluster's Fuchsia gate on :8081 — no jar rebuild needed for UI work.
cd flink-fuchsia-web/frontend && npm install && npm run dev
# Type-check the frontend.
cd flink-fuchsia-web/frontend && npm run check
# If you already ran `npm run build` and only want to repackage, skip the npm steps:
./gradlew jar -x buildFrontend -x npmInstall
Deploy (not automated here): copy flink-fuchsia-core-*.jar (plus any standalone plugin jars) into
<flink>/lib/, restart the cluster, and open the JobManager REST port (default 8081).
Architecture
- Bootstrap.
me.theseems.fuchsia.bootstrap.FuchsiaChannelHandlerFactoryimplements Flink'sorg.apache.flink.runtime.io.network.netty.InboundChannelHandlerFactorySPI (registered viaMETA-INF/services). Flink instantiates it during REST server setup and it insertsFuchsiaGateHandlerinto the Netty pipeline. No Flink code is modified. - The gate (
server/AccessGate,server/OperationResolver) normalizes each request into aFlinkOperation(anOpType+ method/path/jobId), resolves the caller to aPrincipalvia the activeFuchsiaAuthorizer, and allows/denies. Allowed Flink-path requests are forwarded upstream;/fuchsia/*requests are answered by endpoints. - Endpoints (
api.http.Endpoint, implementations inserver/endpoints/*) are Spring-controller-style: each class declaresmatches(Request)andhandle(...), wired in the composition rootFuchsiaComponents. They serve the SPA (StaticAssetsEndpoint), identity (MeEndpoint), cluster info, and the plugin manifest + plugin assets (PluginsEndpoint,PluginAssetEndpoint). - Authorizer discovery.
FuchsiaAuthorizers are found viaServiceLoader. A non-fallback authorizer wins; aFallbackAuthorizer(the bundled token auth) is used only if it's the only one; if none, deny-all. The marker is checked without constructing the authorizer. - The SPA (
flink-fuchsia-web/frontend) talks to the gate over the same origin. It models Flink's REST shapes into stable internal types (src/lib/api.ts,types.ts) and is theme-able / plugin-able.
Conventions
- Backend: Java targeting release 11 bytecode built with a JDK 21 toolchain. Lombok
@Value @Accessors(fluent = true)for immutable DTOs. Flink (and its shaded Netty + Jackson) iscompileOnly— provided by the cluster, never bundled; the jar stays small. Package rootme.theseems.fuchsia. Third-party versions (Flink, Lombok, slf4j) are pinned in thegradle/libs.versions.tomlcatalog — reference them aslibs.*, don't inline versions. - Frontend: Svelte 5 (runes:
$state/$derived/$props/$effect), TypeScript, Vite. Design tokens (colors, spacing, fonts) live insrc/app.cssas CSS custom properties — prefer them over hard-coded values. Fonts are latin-woff2 only to keep the bundle lean. - Comment sparingly. Only add a comment when the why is non-obvious (a constraint, invariant, workaround, or external quirk); never restate what the code does. Keep them to a tight line.
Writing a plugin
Three extension seams — authorization, dashboard sections, endpoints — with step-by-step recipes in
docs/plugins.md, the user-facing guide. Templates:
plugins/flink-fuchsia-plugin-auth-unrestricted (auth), examples/flink-fuchsia-plugin-example (UI).
Gotchas for agents
- Don't read or grep git-ignored working directories. A local Flink distribution or vendored Flink sources run to gigabytes and will blow up search results and context.
flink-fuchsia-web/src/main/resources/web/is generated by the frontend build — never hand-edit it; it's git-ignored.- Flink REST casing trap:
/jobs/overviewreturnstaskswith lower-case state keys ({running: 66}) while/jobs/:idvertices use UPPER-CASE ({RUNNING: 2}).api.tsnormalizes both viaupperTasks. - The jar must stay dependency-light: Flink provides Netty/Jackson/slf4j at runtime — keep them
compileOnly.