Skip to content

Materials file-manager overhaul: nested folders, uploads, quota & AI ingestion - #11

Merged
veniplex merged 1 commit into
mainfrom
claude/materials-file-upload-features-dpmieb
Jul 13, 2026
Merged

veniplex merged 1 commit into
mainfrom
claude/materials-file-upload-features-dpmieb

Conversation

@veniplex

Copy link
Copy Markdown
Owner

Reworks a module's Materials area from a flat, single-level list into a full file manager.

What's new

Folders & navigation

  • Real nested folder tree (new material_folder table + material.folderId), replacing the old single-level folder text column. Empty subfolders now persist.
  • Breadcrumb navigation (drill in/out), plus an "up one level" drop target.
  • Create subfolders anywhere; rename / move / delete (recursive) folders.

Selection & bulk actions

  • Multi-select files via checkbox, Ctrl/Cmd-click, and Shift-range.
  • Floating action bar to move or delete the whole selection.

Views & stats

  • Toggle list ↔ grid (tile) view; the choice is persisted (localStorage).
  • Top stats bar (total files, folders, size) and per-folder stats (files / subfolders / size).
  • Context menus on both files and folders.

Uploads

  • Drag & drop files and whole folders into the window — nested structure is preserved (FileSystem Entry API, with a flat fallback).
  • Upload dialog gains a folder picker (webkitdirectory) alongside file upload.
  • .zip archives are unpacked server-side (background pg-boss job) into a same-named folder, preserving their internal tree. Guards against zip-slip, __MACOSX/dotfile cruft and zip bombs (entry-count + uncompressed-size caps). The archive is discarded after unpacking.

AI can process all file types

  • Extension-based routing in extract.ts adds DOCX (mammoth), PPTX/XLSX (OOXML text scraping) and all code/plain-text files, on top of PDF.
  • Images run OCR/description via a vision model; audio/video run transcription (Whisper) — both via the already-configured AI provider, best-effort.

Storage quota (per user)

  • Admins set a per-user total-storage limit (Admin → Branding). Enforced on upload.
  • Users see their file count, used size and quota utilization in Settings.

Data model & migration

  • 0029 creates material_folder (self-referencing, cascade), adds material.folder_id, and a COALESCE(parent_id,'') unique index so sibling names stay unique even at the root.
  • 0030 backfills the tree from the legacy folder column (idempotent). The old column is retained this release for rollback safety.

Verification

  • Migration + backfill replayed against a live Postgres; backfill invariants and the sibling-uniqueness index verified.
  • Unit tests for path sanitization, zip planning (slip/caps/__MACOSX), OOXML extraction and file-type classification.
  • DB integration tests for the folder helpers (nested create/dedup, recursive stats, subtree collection, descendant guard) and end-to-end zip unpacking. These caught and fixed a real bug where a JS array was expanded as a SQL tuple instead of an array in the recursive-delete path.
  • tsc --noEmit, eslint, vitest (79 passing) and a production next build all green.

New server actions (createFolder, moveFolder, deleteFolder, bulk move/delete) and helpers live under src/lib/materials/. The DB-backed tests are gated behind RUN_DB_TESTS=1 so CI without a database stays green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LWLUNyHYuCpouMEUo3P456


Generated by Claude Code

…ads, quota & AI ingestion

Rework the module materials area into a proper file manager:

- Nested folders: new material_folder table (self-referencing) + material.folderId,
  with migration + idempotent backfill from the legacy folder column. Sibling
  names kept unique via a COALESCE expression index.
- Browser rewrite: breadcrumb navigation, list/grid toggle (persisted),
  multi-select (checkbox + ctrl/shift-click) with a bulk move/delete bar,
  per-folder and top-level stats, context menus on files AND folders, and
  drag & drop moves (files and folders).
- Drag & drop upload of files and whole folders into the window (FileSystem
  Entry API with a flat fallback); folder structure is preserved server-side.
- Zip upload is unpacked server-side (pg-boss job) into a same-named folder,
  preserving its tree; guards against zip-slip, __MACOSX and zip bombs; the
  archive is discarded after unpacking.
- AI ingestion for all file types: extension-based routing adds DOCX (mammoth),
  PPTX/XLSX (OOXML scraping) and all code/text files; images run OCR/vision and
  audio/video run transcription via the configured provider.
- Per-user storage quota: admin-configurable limit, enforced on upload, with a
  usage card in user settings.

New server actions (createFolder, moveFolder, deleteFolder recursive/keep,
bulk move/delete) plus helpers in lib/materials. Unit + DB integration tests
cover folder trees, zip unpacking, path safety and file classification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWLUNyHYuCpouMEUo3P456
@veniplex veniplex added the release-candidate Creates a new release and deployment of docker image, once merged. label Jul 13, 2026
@veniplex
veniplex merged commit 3c2897c into main Jul 13, 2026
1 of 2 checks passed
@veniplex
veniplex deleted the claude/materials-file-upload-features-dpmieb branch July 13, 2026 19:23
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-candidate Creates a new release and deployment of docker image, once merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants