zlh-grind/docs/architecture/filesystem-and-file-browser.md

6.5 KiB

Filesystem and File Browser Architecture

Updated: 2026-03-01 Status: Active — reflects implemented upload model


Overview

ZeroLagHub uses a strict, runtime-aligned filesystem model for game containers. The file browser reflects the real runtime layout and does not use staging directories, shadow folders, or symlink-based indirection.

Uploads are written directly into the runtime directory tree with strict policy enforcement and provenance tracking.


Runtime Root

Each game container has a single runtime root:

/opt/zlh/minecraft/<runtime>/<world>/

All file operations are resolved relative to this root.

The agent is the only component allowed to perform filesystem mutations.


Hidden Internal Files

The following files are internal and never exposed through the file API:

  • .zlh-shadow
  • .zlh_metadata.json

These are filtered centrally inside the agent internal/files package, not in route handlers.


Upload Model

No Staging

Uploads are written directly into their final runtime location.

There is:

  • No temporary upload folder
  • No symlink-based deployment
  • No background relocation job

Uploads are atomic:

  1. Write to temp file in same directory
  2. os.Rename() to final path

Upload Allowlist

Uploads are restricted to:

Type Path Extension
Mods mods/<file>.jar .jar
Datapacks world/datapacks/<file>.zip .zip

All other upload paths are rejected.

Parent directory must already exist. No directory creation is performed.


Security Constraints

Upload is rejected if:

  • Path traversal (../)
  • Absolute path
  • Control characters
  • Target exists as directory
  • Target is a symlink
  • Target resolves outside runtime root
  • Path not allowlisted
  • Parent directory missing

Provenance Metadata

Uploads create or update .zlh_metadata.json, stored at runtime root.

Example:

{
  "mods/sodium.jar": {
    "source": "user",
    "uploaded_at": "2026-03-01T22:37:01Z"
  }
}

stat Response Extension

File stat now includes:

"source": "user" | null

Only "user" is currently written by the agent. No curated inference is performed.


File Browser Responsibilities

Portal (Frontend)

  • Displays files
  • Displays source: "user" badge
  • Enforces extension pre-validation
  • Sends multipart upload

API

  • Auth + ownership enforcement
  • Streams upload to agent
  • Does NOT inspect file contents
  • Does NOT re-implement upload policy

Agent

  • Enforces filesystem rules
  • Writes metadata
  • Performs atomic writes
  • Returns authoritative status

Symlink-based deployment was rejected because:

  • It complicates mod loading behavior
  • Breaks compatibility with server-side mod loaders
  • Introduces unexpected runtime indirection
  • Makes provenance ambiguous

Direct writes + metadata is simpler and safer.


Data Flow

Browser → API → Agent → Filesystem

The API uses raw http.request piping to stream uploads. It does not buffer large files in memory.


API Transport Considerations

The API acts strictly as a streaming proxy.

Implementation uses raw http.request piping:

req.pipe(proxyReq)
proxyRes.pipe(res)

This avoids:

  • Fetch streaming incompatibilities
  • Duplex locking issues
  • Multipart buffering problems

Upload timeout for this route should be substantially larger than normal file routes.


Frontend File Browser Direction

Layout

Split-pane panel — directory tree left, file detail/actions right. Slides in as a panel, does not replace the console view. Server console remains visible.

Navigation

Breadcrumb-based. Flat navigation within each directory rather than deep tree expansion. Click folder → replace view. Not expand-in-place.

File Listing

Columns: name, size, modified date, type icon, source badge (user for user-uploaded files). For .jar files: enabled / disabled / removed status.

Actions

Context menu or per-row three-dot menu. Actions: download, delete, rename. For .jar files: enable / disable toggle. Drag-to-upload supported, file picker fallback.

In-Browser Editor

Plain textarea or Monaco for text files (server.properties, .json, .toml, .yml, .txt). Binary files get download link only. Not required for launch.

mods-removed Surface

"Recently removed" section or toggle to show /mods-removed alongside active mods. Makes soft delete visible and gives users a restore path without knowing the underlying filesystem layout.

What to Avoid

  • Deep expand/collapse tree for mod directory (use flat list + filter)
  • In-browser zip/unzip
  • Making the file browser the primary surface — mod manager stays primary, file browser is secondary/advanced

Per-Container Web Server Decision

Do not run Nginx or Caddy per container.

The agent already runs an HTTP server. Serving static file browser assets from the agent directly keeps per-container footprint minimal. No additional process, no config management, no extra memory overhead.

zlh-proxy handles SSL at the edge. A local web server per container adds a layer without adding capability.


Dev Container File Access

Handled via WebSSH2 + SFTP, proxied through the API.

Developers get a real SSH2 session with SFTP channel. No direct container access from the browser — API proxy maintains the security boundary (DEC-008). SFTP warrants its own separate process from day one due to SSH server complexity. It does not belong in the main game agent.


Resilience Notes

The file agent (when extracted) should follow the same binary resilience pattern as the main agent:

  • Versioned release layout (releases/<version>/)
  • current symlink pointing to active binary
  • Previous version retained on disk
  • Systemd watchdog flips current back to previous on health check failure
  • No dependency on artifact server for rollback — local fallback only

Design Philosophy

The runtime directory is the source of truth.

No abstraction layer should diverge from Minecraft's real file structure.


  • docs/architecture/mod-deployment-safety.md — mod lifecycle, upload safety, rollback model
  • docs/architecture/dev-to-game-artifact-pipeline.md — dev container promotion pipeline
  • docs/reference/minecraft-file-locations.md — known files and directories by loader
  • OPEN_THREADS.md — file browser listed as next major feature
  • WebSSH2: https://github.com/billchurch/webssh2 — SFTP + SSH2 for dev containers