Skip to content

Rearchitect Coil application surfaces around Fission - #18

Draft
zcourts wants to merge 32 commits into
mainfrom
salvage
Draft

zcourts wants to merge 32 commits into
mainfrom
salvage

Conversation

@zcourts

@zcourts zcourts commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR begins the architectural replacement of Coil's presentation layer with Fission and packages the work as a reviewable migration branch. It establishes Fission as the application/UI runtime, replaces the documentation website with a Fission static site, moves Gitly's production presentation onto Fission SSR, introduces a Fission-native Shoppr storefront and protected Web admin shell, and connects Shoppr catalogue/cart rendering to PostgreSQL-backed typed jobs.

This PR is intentionally opened as a draft. The branch contains substantial, useful migration work, but the Shoppr serve entrypoint still starts the legacy HttpServerHost. Search and booking cannot yet receive their request-scoped initial data because Fission has no typed SSR-to-island initialization path. The Fission authority audit confirmed that these bounded islands need seeded data plus local reducers, not browser execution of ServerJobRegistry; queued server jobs already settle before final SSR. A separate confirmed HTML-first gap means submitted form control values cannot yet become typed server-action reducer input. These limitations are documented below rather than hidden behind passing component tests.

Size and review shape

  • 32 commits on top of main, kept as small logical changes rather than squashed.
  • 253 files changed.
  • Approximately 19,636 insertions and 24,028 deletions.
  • The deletion count is dominated by removing the Docusaurus/Node website and its lockfile.
  • The addition count includes generated Rust lockfiles, Fission application code, migrated documentation, and checked-in visual assets.

Architectural contract

The accepted design is recorded in docs/design/100-fission-native-application-architecture.md.

The important decisions are:

  1. Fission is the sole UI/application runtime. It owns widgets, routing, synchronous reducers, effect declarations, typed jobs, SSR, browser islands, full Web applications, and static sites.
  2. Coil remains the product/domain layer. It owns site/market resolution, authorization, PostgreSQL repositories and transactions, durable work, media, payments, observability, and extension contracts.
  3. Reducers are synchronous. They declare effects; the shell executes and awaits jobs, dispatches typed completions, and rerenders. During SSR, required jobs settle before the final HTML is returned.
  4. PostgreSQL remains authoritative for durable product/customer facts. Fission state is a request/application presentation snapshot, not a second authority.
  5. Public/searchable pages use SSR, bounded interactions use islands only when the framework can support their real data flow, and dense operator surfaces use full Fission Web applications.
  6. Protected Fission routes are a component/resource construction boundary, not server authorization. Protected APIs and actions must independently authenticate and authorize.

Detailed changes

Fission integration layer

  • Adds the coil-fission crate as the narrow product/framework boundary.
  • Re-exports target-specific Fission capabilities without creating a parallel widget, router, reducer, or executor abstraction.
  • Adds CoilRequestScope, SiteDefinition, and SiteRegistry for server-derived site, market, locale, origin, route, and session identity.
  • Normalizes request hosts, including development ports, before site matching.
  • Unknown and ambiguous hosts fail closed instead of selecting a fallback site.
  • Adds the central session-to-RouteDecision authorization selector used by protected routes.
  • Adds SSR job tests proving declared typed jobs settle before final HTML.

Documentation and marketing website

  • Deletes the Docusaurus/React/Node application, JavaScript package manifest, package lock, TypeScript configuration, and Docusaurus sidebars/configuration.
  • Adds a Rust Fission static-site package under website/.
  • Adds website/fission.toml with the explicit coil_website::site entrypoint required by fission site serve.
  • Implements the editorial home page in Fission widgets and adds a restrained visual system in website/src/site.css.
  • Migrates the existing documentation tree into Fission's static-site routing/discovery model.
  • Adds a generated design-direction image and documents the visual rules in website/DESIGN.md.
  • Updates contributor and root README instructions to use the Fission CLI.
  • Adds scripts/check-website-serve.sh, which launches the installed Fission CLI, probes real HTTP routes, verifies a real 404, captures evidence, and cleans up the complete server process group.
  • Updates CI, docs publication, and the pull-request template to execute that real serve-boundary check with the pinned Fission revision.

Shoppr visual/product surface

  • Adds the Townhouse editorial direction: strong typography, whitespace, long rules, photography, and minimal container chrome.
  • Adds the supporting localized copy for English, French, and Polish.
  • Adds checked-in retail/editorial photography used by the demo theme.
  • Updates the existing template storefront while migration is in progress so the still-live legacy entrypoint remains coherent.
  • Moves the local demo to port 8088 and aligns Docker/development configuration and backend documentation.

Shoppr Fission storefront

  • Adds the portable shoppr-fission crate with target-gated site and web features.
  • Adds Fission state, typed job specifications, synchronous reducers, localized widgets, responsive headers, real semantic links, catalogue/collection/product rendering, loading/error states, and the Shoppr visual tokens/CSS.
  • Registers Fission SSR routes for home, catalogue, collections, products, events, and the session-private cart.
  • Ensures product pages that emit signed server-action forms are uncached server routes rather than revalidated public-cache routes.
  • Adds per-request state loaders that derive scope from the validated Host, locale route parameter, route parameters, and Fission server session.
  • Adds a protected Fission Web admin shell using the central RouteDecision selector and lazy ProtectedRoute branches.
  • Keeps Fission features opt-in for portable/native builds so server-only dependencies do not leak into browser artifacts.

PostgreSQL catalogue and cart authority

  • Adds site/locale-scoped catalogue publication tables and event publication ownership migrations.
  • Adds authoritative commerce cart and cart-line storage keyed by server-derived site/session ownership.
  • Adds PostgresCatalogRepository for published catalogue, collection, search, product, cart read, and cart mutation queries.
  • Seeds the checked-in Shoppr catalogue through the migration lifecycle rather than treating rendered fixtures as authority.
  • Uses bounded PostgreSQL transactions for cart mutation, validates quantity, session identity, product publication, currency consistency, and cart limits, and returns a freshly loaded cart snapshot after commit.
  • Converts database failures to a public ShopprJobError without leaking connection/schema diagnostics.
  • Registers live Fission server jobs for catalogue reads, cart reads, and cart additions.
  • The server job adapter awaits the PostgreSQL future before returning the typed job result. Reducers remain synchronous and only declare the effect.

Real Fission cart action path

  • Replaces the browser-only cart counter simulation with a signed Fission server action.
  • Gives the Add-to-bag button a stable explicit Fission widget identity.
  • The action payload carries only the selected product handle; site/session ownership comes from state created by the server request, not browser-supplied identifiers.
  • The synchronous reducer marks the cart pending, declares the typed add job, binds explicit success/failure completion reducers, and dispatches the effect.
  • The server drains the job and completion before rendering the action response.
  • Adds a session-private /cart route that declares a cart read resource and renders empty, pending, failure, line-item, and subtotal states with built-in Fission widgets.
  • Adds English, French, and Polish cart empty/error/addition copy.
  • Removes the obsolete shoppr-cart WASM island implementation and its route declarations so the code no longer advertises a local-only simulation as a durable cart.

Gitly Fission migration

  • Adds the portable gitly-fission crate with Gitly state, models, localization, retained widgets, responsive navigation, search island, and theme-aware UI.
  • Adds Gitly's Fission server application with localized English/French/German routes and server-derived site scope.
  • Ports the checked-in Gitly API responses into Fission custom HTTP handlers.
  • Switches Gitly's serve_from_env production entrypoint to coil::fission::server::serve.
  • Restores native Fission light/dark theme selection.
  • Updates Gitly tests and README to describe the actual Fission presentation boundary.
  • Synchronizes the Gitly workspace lockfile with its added Fission packages in a separate commit.

Domain/runtime support work

  • Exposes shell-independent live authorization so Fission surfaces can make policy decisions without constructing the legacy HTTP renderer.
  • Adds site-scoped catalogue publication and inventory availability semantics.
  • Adds authoritative session cart domain/storage support.
  • Adds site/locale ownership to event publications and booking ownership columns.
  • Makes the job backend test harness and coordinator surfaces available where the migration needs to verify execution semantics.
  • Updates runtime authorizer wiring and focused tests without changing the rule that API/server-action authorization is independent from route presentation.

Validation and evidence

Completed

Real Fission website serve boundary

The website was exercised through the installed CLI rather than only its Rust renderer tests.

  • Runner job: 01M1XCCNC6XEEW5H5PZY39TVGE
  • Result: exit code 0
  • Command boundary: bash scripts/check-website-serve.sh
  • Fission generated 217 static routes and started the actual local server.
  • / returned 200.
  • /docs/intro/ returned 200.
  • /architecture/100-fission-native-application-architecture/ returned 200.
  • /img/favicon.svg returned 200.
  • /not-a-real-coil-route returned 404.
  • The server process group was terminated and port 18123 was confirmed closed.
  • Evidence directory: /home/zcourts/projects/projects/releases/coil/site-serve-script

An earlier direct reproduction/verification job (01M1XBEDFD85QFW84KDAER3344) also completed with exit code 0 after the missing site entrypoint was fixed.

Static/integrity checks during wrap-up

  • git diff --check origin/main...HEAD passes.
  • cargo metadata --locked --manifest-path apps/shoppr/Cargo.toml --no-deps passes.
  • cargo metadata --locked --manifest-path apps/gitly/Cargo.toml --no-deps passes.
  • The complete outgoing filename set was inspected (253 files).
  • Focused outgoing-diff checks found no private keys, live API keys, or committed password/secret assignments.
  • The five local showcase/chat/image files listed below are not in the outgoing commit range.

Added but not executed before this wrap-up

Shoppr now contains focused tests for:

  • final SSR after catalogue jobs settle;
  • signed Add-to-bag action dispatch;
  • preservation of server-derived site and session ownership;
  • cart route settlement before final SSR;
  • locale and site isolation;
  • route cache/private-mode inventory;
  • live PostgreSQL Fission job registration;
  • awaiting database jobs from the multithread Fission server runtime;
  • public error redaction.

A serialized one-thread runner job (01M1XEHFAWTGJ35A6B0EJMAWB0) was submitted for these tests but remained queued behind higher-priority shared-VM release work. It was cancelled while still queued when the user requested immediate wrap-up. Therefore these new Shoppr tests are not claimed as executed in this PR description.

Known gaps and blockers

Shoppr production cutover is not complete

ShopprBootstrap::serve_from_env still invokes the legacy customer runtime/HttpServerHost. The Fission server app and production PostgreSQL job registry exist, but switching the public entrypoint now would remove checkout, account, operational, and other still-unmigrated production routes. This PR deliberately does not trade route loss for a superficial cutover claim.

The legacy router, template renderer, and frontend files therefore remain because they still have production callers. They should be deleted only after those callers move.

Search and booking islands need typed initialization

The Fission authority audit against Fission commit efe53a12 on the gaming branch confirmed one incomplete initialization pipeline: the browser bridge and WorkerBoot understand properties, but ProgressiveWorker and WasmIsland expose no request-scoped source from which the route manifest can populate them. Shoppr search and booking are correctly shaped as bounded islands that consume seeded server data and then filter or select through local synchronous reducers.

BrowserIslandApp deliberately rejects queued effects. That is not a demonstrated blocker for these two islands and does not imply that ServerJobRegistry should run in the browser. Catalogue, cart, booking, and database authority stays in SSR actions, reducers, and server jobs. The branch will not add a DOM-data or handwritten JavaScript side channel; request-scoped data remains authoritative through route_widget_with_state until Fission provides the typed initialization path.

HTML-first submitted values need typed action binding

The authority audit also confirmed a major framework gap for stateful HTML forms. Signed server-action tokens contain the render-time ActionEnvelope, while the form decoder currently reads the token but does not bind submitted successful controls into typed reducer input. Fixed render-time actions such as Add-to-bag with a known product handle work; search fields, quantities, authentication fields, checkout addresses, and administrative edits that depend on current input do not yet have a Fission-native typed submission path.

This branch does not bypass Fission signing, origin checks, or one-shot replay protection with ad hoc hidden payloads. Fission owns the typed binding design.

Other Fission authority findings

  • Synchronous reducers and server jobs are working as designed: a reducer queues a job, Fission waits for its handler to finish, dispatches the synchronous completion reducer, and only then settles SSR. Coil database adapters synchronously await their client futures inside that boundary; no async reducer or async job-handler API is required.
  • Custom HTTP handlers are exact-path-only, but this is not a blocker for dynamic UI operations. Matched widget routes already expose route parameters, so event booking and order operations belong in route actions, reducers, and jobs. A matcher extension is only needed for a concrete dynamic API or webhook protocol.
  • The optional Axum adapter targets 0.7 while Coil uses 0.8. This is a convenience-adapter mismatch rather than a renderer blocker because ServerRenderer, ServerRequest, and ServerResponse are framework-neutral; a thin Coil-owned adapter is the current boundary.
  • Fission CLI server artifact selection requires root [package].name, so virtual workspaces need explicit Cargo package selection. Guessing a package from a normalized Rust entry path is not acceptable.
  • Missing [site].entry was a Coil configuration error, not a Fission bug. Its absence intentionally selects the generic content builder. The explicit coil_website::site entry is now configured and end-to-end verified.
  • Targeted cancellation of custom fission site serve can orphan cargo/server descendants because the CLI uses Command::status without owned child supervision. Normal foreground Ctrl-C differs. Coil regression cleanup is process-group-safe; shared CLI signal forwarding remains a confirmed P1 robustness issue.

Admin/operations are a shell, not a finished operator product

The protected Fission Web admin shell, routing, pending/denied branches, and typed session/snapshot job contracts exist. It is not yet packaged and mounted as the production operator application with every existing CMS, commerce, event, media, membership, and ops workflow migrated and independently authorized.

Full regression qualification remains outstanding

No full workspace build, Shoppr database-backed live server E2E, browser island interaction run, or production-container qualification is claimed for the final commit. The shared Debian VM was running higher-priority release work, and Coil's explicit allowance was one serialized job/thread. This PR should remain draft until the focused Shoppr tests and an official CLI/server/database workflow have run on the exact candidate commit.

Security, persistence, and operational impact

  • Site/session ownership for cart mutations is server-derived.
  • Unknown hosts fail closed.
  • Cart writes are transactional and PostgreSQL remains authoritative.
  • Public job errors redact private database diagnostics.
  • Product routes containing signed server actions are not publicly cached.
  • Cart HTML is session-private.
  • Protected route construction does not replace API/action authorization.
  • Event and catalogue publication records gain explicit site/locale ownership.
  • Docker/dev port changes from the historical value to 8088 are reflected in compose and docs.
  • New direct application dependencies are Fission/Coil integration packages and serialization support required for typed job/action contracts; lockfile changes are committed explicitly.

Local files intentionally excluded from publication

These untracked workspace files were not staged, committed, pushed, or included in this PR:

  • showcase-coil-intro-chat.txt
  • showcase-data-entity-map.png
  • showcase-event-lifecycle.png
  • showcase-platform-vision.png
  • showcase-system-summary.png

Commit sequence

The branch intentionally preserves the logical history. In order:

  1. Loyalty/demo groundwork and Townhouse storefront direction.
  2. Architecture and Fission boundary establishment.
  3. Fission static website replacement.
  4. Request-host normalization, catalogue publication, and target feature wiring.
  5. PostgreSQL catalogue seeding and site-owned events/cart data.
  6. Shell-independent authorization and Shoppr Fission storefront/island/admin scaffolds.
  7. Shoppr localization and public Fission SSR routes.
  8. PostgreSQL session cart repository.
  9. Gitly portable Fission UI, production SSR cutover, localization, and theme restoration.
  10. Website entrypoint fix, real serve-boundary regression script, and CI/Pages enforcement.
  11. Production Shoppr Fission job registration and awaited database bridge.
  12. Signed server-action cart flow and session-private final SSR.
  13. Removal of the obsolete local-only cart island.
  14. Gitly lockfile synchronization.

Recommended review order

  1. docs/design/100-fission-native-application-architecture.md
  2. crates/coil-fission/
  3. website/, scripts/check-website-serve.sh, and workflow changes
  4. apps/gitly/crates/gitly-fission/ plus Gitly server integration
  5. apps/shoppr/crates/shoppr-fission/
  6. Shoppr PostgreSQL repository/server integration and tests
  7. Domain migrations and authorization support
  8. Legacy Shoppr template/theme changes, understanding that they remain live during the incomplete cutover

Before marking ready for merge

  • Run the focused Shoppr Fission server and production job tests on the exact PR head.
  • Run a real Shoppr CLI/server flow against PostgreSQL and verify catalogue, product, signed cart mutation, cookie continuity, and cart SSR over HTTP.
  • Land/use the Fission typed request-scoped island initialization capability, then seed and qualify the existing search/booking islands without adding browser server-job execution.
  • Land/use Fission typed HTML form-value binding before migrating search, checkout, authentication, or administrative actions whose payload depends on submitted controls.
  • Package and mount the protected admin Web app with independent server authorization.
  • Migrate checkout, account, CMS, commerce, events, media, memberships, and ops route callers.
  • Switch Shoppr's production serve boundary to Fission only after route parity.
  • Delete the legacy router/templates/frontend only after their last caller is gone.
  • Run the full applicable serialized workspace and container qualification gates.

zcourts added 30 commits April 1, 2026 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant