Skip to content

Phase 3: fold in #303 landing-page seeding on portable generators (#427) #433

@melvincarvalho

Description

@melvincarvalho

Phase 3 of the umbrella plan in #427.

Scope

Resurrect the landing-page seeding work from #276 / PR #303 onto the new portable generators (Phase 1 of #427). Now that accessTo/default are emitted relatively, seedServerRoot becomes portable by construction — no further design tension between its public-read root ACL and the single-user createRootPodStructure ACL.

Changes:

  • New src/ui/server-root.html — minimal landing-page template (operator-overridable).
  • New src/ui/server-root.js — renderer + seeder. Uses generatePublicReadAcl from src/wac/parser.js (Phase-1 portable form).
  • src/server.js — gains an onReady hook (skipped in read-only mode) that calls seedServerRoot with current server context (mode, IDP, enabled features).
  • New test/server-root.test.js.

Closes #303 / supersedes its branch (origin/issue-276-server-root-landing). The original PR was open since Apr 23 and went conflicting against gh-pages.

Why

Multi-user JSS deployments currently land on a raw container listing at /. New pod providers had to build their own landing page from scratch. Single-user deployments served index.html only when the operator wrote one — which fonstr does, but a bare jss start --single-user does not.

Behavior

  • Skip-if-exists for /index.html, /.acl, and /index.html.acl — operator customisation is never overwritten.
  • Public read only at the root — no public write. Operators edit /index.html on disk, not via the web. (A future --admin-webid could relax this.)
  • Mode-aware rendering:
    • multi-user + IDP → "Create a pod" + "Sign in"
    • single-user + IDP → "Sign in" (no Create-a-pod)
    • both → "Docs" link + version + mode + enabled-feature pills
  • Read-only deployments skip the seeder entirely (no DATA_ROOT mutation).
  • Failure isolation: HTML write failure aborts ACL seeding, so the server never ends up with a public root ACL but no index page.

Carry-over from PR #303 review

PR #303 had Copilot review pickups already addressed on its branch:

  • generatePublicReadAcl reuse (no inline ACL JSON)
  • skip in read-only mode
  • check storage.write returns
  • real IDP routes (/idp/register, /idp — not the non-existent /.account/new and /idp/auth)
  • full error logging (with stack)
  • terminal feature flag
  • resilient package.json read
  • restore process.env.DATA_ROOT after tests

One remaining nit from that review thread: String.prototype.replace with a string interprets $&, $1 etc. as substitution patterns. Interpolated values like the singleUserName-derived subtitle could in principle contain $ characters. Phase 3 will switch the template substitutions to the function form (replace(/{{key}}/g, () => value)) to side-step this entirely.

Tests

Carry forward + adapt the tests from PR #303:

  • seeds /index.html so GET / serves HTML — fresh test server, GET /
  • landing page is publicly readable — direct GET /index.html
  • does not overwrite operator-provided /index.html — pre-write a custom file, assert preservation
  • renderServerRoot — mode-specific output (5 tests) — multi-user+IDP, single-user+IDP, multi-user-no-IDP, single-user subtitle includes pod name, feature listing
  • interpolates version + escapes version to prevent injection

Plus one new test for the $& regression: renderServerRoot should emit a singleUserName containing $ characters intact.

Acceptance

  • Three new files (src/ui/server-root.{html,js}, test/server-root.test.js) and the onReady hook in src/server.js.
  • All existing tests pass.
  • All new tests pass, including the $& regression.
  • PR feat: default landing page + ACL at server root (#276) #303 closed (this issue's PR notes the supersession).

Out of scope

  • Cross-host owner write (Phase 4 — separate design issue).
  • --admin-webid / web-edit access for the landing page (future iteration).

Refs #427.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions