Waves 0-5: document metadata, public gallery, HTML page, static hosting, review fixes
Server (modeler-server):
- Wave 0: DB schema migration for description/is_public/thumbnail/created_at
on assemblies + scenes tables (#62)
- Wave 1: Pure-logic modules gallery.rs (validation), middleware.rs
(request_id, metrics, gallery_visibility_gate), static_files.rs
(classify, mime_for, StaticDirService) (#63)
- Wave 2: gallery_db.rs queries (list_public, count_public, get_thumbnail,
patch_metadata, admin_unpublish/delete, moderation_queue, decode_thumbnail,
get_public_document), gallery_routes.rs (public_routes, document_routes,
admin_routes), metadata fields in assemblies.rs/scenes.rs/sync.rs,
request-id + metrics middleware, gallery visibility gate (#64)
- Wave 3: --static-dir CLI flag + custom StaticDirService mounted via
fallback_service; correct Content-Type + Cache-Control per asset class;
SPA deep-link fallback for extensionless paths (#65)
- Wave 5: /api/gallery/document/{kind}/{user_id}/{name} route for fetching
public document data; embedded /gallery HTML page with self-contained
CSS+JS gallery UI (no framework, escaped HTML)
Client (modeler):
- Wave 4: ViewportRenderer::render_to_png(512, 512) using one-shot RGBA8 +
depth32 textures, padded to 256-byte rows, map_async + PNG encode via
image crate; Document Properties dock tab (left dock, second tab)
editing description/is_public/thumbnail; new UiActions and CloudOpResults
for the metadata flow; PATCH /api/documents/{kind}/{name} plumbing on
both native and WASM
- Wave 5: src/ui/gallery.rs in-app grid + detail panel + ThumbCache (256-
entry FIFO eviction, cleared on gallery close); src/ui/toolbar.rs
Browse Public Gallery button in cloud menu and Gallery button for
anonymous users; load_gallery/load_public_document on cloud.rs;
pagination via SetGalleryPage UiAction
Review fixes (post-Wave 5):
- CRITICAL: DocumentMetadataBody.is_public is now Option<bool> (was Option
<i32>); Refresh from Cloud parses correctly
- HIGH: apply_loaded_public_document for assembly uses new add_assembly
(inserts one entry) instead of merge_library (which wiped the library)
- HIGH: trigger_eval() after replace csg_tree in both scene load paths
- HIGH: Gallery window shows Prev/Next pager with page X of Y
- HIGH: Document Properties tab uses document_kind_for(node) so Assembly
nodes edit the assemblies table, not the scenes table
- HIGH: HTML gallery 'Open in Modeler' no-op replaced with 'Copy share
link' button
- MEDIUM: ThumbCache max-entries (256) with FIFO eviction + clear() on
CloseGallery
- MEDIUM: SaveSceneToCloudWithThumbnail now checks is_authenticated()
- MEDIUM: DocumentMetadataSaved carries server's canonical description/
is_public/has_thumbnail; dispatcher adopts them after save
- LOW: test_server.sh test 58 title corrected
Tests:
- 72 server unit tests + 290 modeler lib tests + 77 bash integration
tests, all passing
- Added bash tests 27-46 (gallery, PATCH, admin, metrics, request-id)
in Wave 2
- Added bash tests 47-53 (static serving) in Wave 3
- Added bash tests 54-58 (HTML page, public document fetch, 404 paths)
in Wave 5
Extract subsystems from ModelerApp into focused modules
Phase 1-3 refactoring: split the monolithic ModelerApp into 8 dedicated
subsystems (UndoManager, NotificationQueue, SelectionState, DragDropState,
GizmoController, ExtrudeController, Clipboard, AssemblyManager) and
apply the Command pattern to centralize mutation logic.
- Extract GizmoController from src/app/gizmo.rs
- Extract ExtrudeController, Clipboard, AssemblyManager
- Extract UndoManager, NotificationQueue, DragDropState
- Apply Command trait + CommandCtx for all mutations
- Refactor ModelerApp::apply() into a thin dispatcher
- Add UI polish, toolbar updates, assembly browsing
- Add .gitignore for assets/ directory