Adds the unified file manager view (Windows Explorer-style), collapsible folder tree sidebar item, full vitest test suite (55 tests, 4 files), and commits all Phase 4 backend/frontend fixes that were staged but uncommitted. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.6 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 04-folders-sharing-quotas-document-ux | 05 | backend-api |
|
|
|
|
|
|
Phase 04 Plan 05: Document Streaming Proxy + PDF Preferences Summary
One-liner: MinIO streaming proxy for document content with Range header support (DOC-02) and pdf_open_mode user preference endpoint (DOC-01) backed by Literal validation.
What Was Built
Task 1: GET /api/documents/{id}/content (DOC-02)
Added a streaming proxy endpoint to backend/api/documents.py:
_parse_range(range_header, file_size)module-level helper that parses RFC 7233bytes=X-Ysyntax, handles open-ended ranges (bytes=X-andbytes=-Y), and raises HTTP 416 on any invalid or out-of-bounds rangestream_document_contentendpoint atGET /api/documents/{id}/content:- Uses
get_regular_userdep — admin role → 403 (T-04-05-01, CRITICAL) - Parses doc_id as UUID → 404 on ValueError
- Loads Document via session.get → 404 if None
- Access:
doc.user_id == current_user.idORShare.recipient_id == current_user.id; neither → 404 (T-04-05-04) - Fetches bytes via
get_storage_backend().get_object(doc.object_key)— no presigned URL (T-04-05-02) - Returns
StreamingResponsewithcontent-type,content-disposition: inline,accept-ranges: bytes,content-length - Range header present → 206 with
content-range: bytes {start}-{end}/{total}(T-04-05-03) - No Range → 200
- Uses
Also added pdf_open_mode column to User ORM model (migration 0004 already added the DB column).
Task 2: Preferences Endpoints (DOC-01)
Added to backend/api/auth.py:
PreferencesUpdatePydantic model withpdf_open_mode: Literal["in_app", "new_tab"]GET /api/auth/me/preferences— returns{"pdf_open_mode": ...}usingget_current_user(both roles)PATCH /api/auth/me/preferences— validates via Literal, updatescurrent_user.pdf_open_mode, commits, returns updated value
Commits
| Hash | Message |
|---|---|
8e6cb6e |
test(phase-4-05): add failing tests for document streaming proxy (DOC-02) — RED phase |
f868a4e |
feat(phase-4-05): document streaming proxy GET /api/documents/{id}/content (DOC-02) — GREEN phase |
2a0df32 |
feat(phase-4-05): PATCH /api/auth/me/preferences for pdf_open_mode (DOC-01) |
Test Results
Before this plan: 85 passed, 10 xfailed (document tests only had xfail stubs) After this plan: 137 passed, 35 xfailed — all new tests green
| Test | Result |
|---|---|
| test_content_stream_200 | PASSED |
| test_content_stream_206_range | PASSED |
| test_content_stream_admin_403 | PASSED |
| test_content_stream_no_presigned_url | PASSED |
| test_content_stream_share_recipient_200 | PASSED |
| test_content_stream_not_found | PASSED |
| test_content_stream_invalid_id | PASSED |
| test_parse_range_416 | PASSED |
| test_get_preferences_default | PASSED |
| test_patch_preferences_in_app | PASSED |
| test_patch_preferences_new_tab | PASSED |
| test_patch_preferences_invalid_value | PASSED |
| test_patch_preferences_persists | PASSED |
| test_preferences_requires_auth | PASSED |
| test_patch_preferences_requires_auth | PASSED |
Pre-existing failure: test_extract_docx (missing python-docx module in local env — not introduced by this plan).
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] Deprecated HTTP_416 status constant
- Found during: Task 1 implementation
- Issue:
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLEis deprecated in the installed FastAPI version;HTTP_416_RANGE_NOT_SATISFIABLEis the current constant - Fix: Used
HTTP_416_RANGE_NOT_SATISFIABLEthroughout - Files modified:
backend/api/documents.py - Commit:
f868a4e
2. [Rule 2 - Missing functionality] pdf_open_mode absent from User ORM model
- Found during: Task 2 — plan noted "migration 0004 adds column" but the ORM
Userclass inmodels.pydid not declarepdf_open_mode - Fix: Added
pdf_open_mode: Mapped[str]withserver_default="in_app"to the User class - Files modified:
backend/db/models.py - Commit:
f868a4e
Security Invariants Verified
| Threat ID | Status |
|---|---|
| T-04-05-01: Admin blocked at content proxy | VERIFIED — get_regular_user dep; test_content_stream_admin_403 passes |
| T-04-05-02: No presigned URL in proxy | VERIFIED — presigned_mock.assert_not_called() in test_content_stream_no_presigned_url |
| T-04-05-03: Range validation bounds | VERIFIED — test_parse_range_416 confirms 416 on out-of-bounds |
| T-04-05-04: Non-recipient 404 | VERIFIED — unshared doc returns 404; share recipient gets 200 |
| T-04-05-05: pdf_open_mode Literal | VERIFIED — test_patch_preferences_invalid_value confirms 422 on invalid value |
Known Stubs
None — all behavior is fully implemented and wired.
Threat Flags
None — no new network endpoints, auth paths, or file access patterns beyond what was planned in the threat model.
Self-Check: PASSED
backend/api/documents.py— stream_document_content endpoint existsbackend/api/auth.py— /me/preferences routes registered (GET + PATCH)backend/db/models.py— pdf_open_mode column on User modelbackend/tests/test_documents.py— 8 streaming proxy tests passbackend/tests/test_auth_api.py— 7 preferences tests pass- Commits:
8e6cb6e(RED),f868a4e(GREEN Task 1),2a0df32(Task 2) - Full suite: 137 passed, 1 pre-existing failure (test_extract_docx — missing docx module)