Packages: internal/core/fs.go, internal/service/fs_service.go
The VFS is a pure in-memory tree rooted at /. It is serialised as part of AppState.FileSystems in nexus.json.
type FSNode struct {
Name string
Type NodeType // "file" | "folder"
FileID string // non-empty only for Type==file → links to FileMetadata
Size int64 // file size, or recursive sum for folders (not auto-updated)
CreatedAt time.Time
Children []*FSNode // non-nil only for folders
Parent *FSNode // omitted from JSON (internal traversal only)
}
type UserFileSystem struct {
Username string
Root *FSNode // root node, Name="/"
QuotaLimit int64 // default 500 MB
QuotaUsed int64
}One UserFileSystem per authenticated user. Created on first access with a 500 MB quota limit.
resolvePath(fs, path) splits the path on /, then walks the tree from fs.Root matching each component against children by name. Returns the target node, its parent, and an error if any component is not found.
"/documents/projects/readme.txt"
→ parts: ["documents", "projects", "readme.txt"]
→ walk: root → "documents" (folder) → "projects" (folder) → "readme.txt" (file)
Returns (targetNode, parentNode, nil) on success.
- Resolve the full path — error if it already exists.
- Resolve the parent path — error if parent does not exist or is not a folder.
- Append a new
FSNode{Type: folder}to parent's children. - Save state.
No mkdir -p. Each intermediate directory must exist.
- Quota pre-check is deferred until after physical upload.
- Call
FileService.UploadFile(localPath)— chunks the file across nodes. - If
quota_used + file_size > quota_limit: delete physical chunks and return error. - Resolve parent folder in the VFS tree.
- If parent not found: delete physical chunks (orphan cleanup) and return error.
- Append
FSNode{Type: file, FileID: meta.ID, Size: meta.Size}to parent. - Increment
fs.QuotaUsed. - Save state.
- Resolve target node and its parent.
- Refuse to delete root.
- Recursive walk: for every
filenode, callFileService.DeleteFile(fileID)and decrement quota. For folder nodes, recurse into children first. - Remove target from parent's children slice.
- Save state.
- Resolve source node and source parent.
- Resolve destination parent folder.
- Detach source from source parent's children.
- Update
sourceNode.Nameto the last component of the destination path. - Append source node to destination parent's children.
- Save state.
Physical chunks are not moved — only the VFS pointer changes.
Resolve the path, assert it is a folder, return node.Children.
- Default: 500 MB per user (
500 * 1024 * 1024bytes). - Tracked in
UserFileSystem.QuotaUsed(incremented on upload, decremented on delete). - Checked in
UploadFileToPathafter physical upload (rollback on excess). - No enforcement at mkdir.
- No quota for the raw
FileService(CLIfile upload); only the VFS layer enforces quotas.
The entire VFS tree is serialised to JSON as part of AppState. The Parent pointer is tagged json:"-" to avoid circular reference during marshalling. Parent pointers are not restored on deserialization — they are not needed by any current operation (path resolution walks top-down only).
- No atomic rename. Move is two operations (detach + attach) with no rollback.
- No hard links or symlinks.
- Folder size not recursively maintained.
FSNode.Sizefor folders is not updated on child changes. - No file versioning.
- Username is hardcoded to
"cli-user"in the CLI. Full auth integration is pending.