# 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:**

```json
{
  "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

---

## Why No Symlinks

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:

```js
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.

---

## Related Documents

- `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
