Files
kite/.planning/phases/04-folders-sharing-quotas-document-ux/04-05-SUMMARY.md
T
curo1305 87a32b7ee8 feat(phase-4): complete UX redesign — FileManagerView, FolderTreeItem, test suite, and all Phase 4 fixes
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>
2026-05-28 17:10:52 +02:00

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
streaming-proxy
content-delivery
preferences
pdf
range-requests
doc-02
doc-01
requires provides affects
04-02
04-04
GET /api/documents/{id}/content — streaming proxy from MinIO
GET /api/auth/me/preferences — read pdf_open_mode
PATCH /api/auth/me/preferences — update pdf_open_mode
04-09
added patterns
StreamingResponse with iter([bytes]) for zero-copy streaming
_parse_range() module-level helper for RFC 7233 byte range parsing
Literal['in_app', 'new_tab'] Pydantic field for allowlist enforcement (T-04-05-05)
get_regular_user dep blocks admin access to content proxy (T-04-05-01)
created modified
path role
backend/api/documents.py Added _parse_range() + stream_document_content endpoint
path role
backend/api/auth.py Added PreferencesUpdate model + GET/PATCH /me/preferences endpoints
path role
backend/db/models.py Added pdf_open_mode column to User ORM model
path role
backend/tests/test_documents.py Replaced xfail stubs with 8 real streaming proxy tests
path role
backend/tests/test_auth_api.py Added 7 preferences endpoint tests
Use get_regular_user (not get_current_user) for content proxy: admin role blocked at dep level (T-04-05-01)
Fetch bytes via get_object() directly — presigned_get_url() forbidden in proxy handler (T-04-05-02)
Access check inline in handler body (not helper function) for test mocking simplicity
HTTP_416_RANGE_NOT_SATISFIABLE used instead of deprecated HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
pdf_open_mode added to User ORM model (migration 0004 already added the DB column)
GET /me/preferences uses AttributeError guard for env without migration run
duration completed tasks_completed tasks_total files_modified
~15 minutes 2026-05-25 2 2 5

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 7233 bytes=X-Y syntax, handles open-ended ranges (bytes=X- and bytes=-Y), and raises HTTP 416 on any invalid or out-of-bounds range
  • stream_document_content endpoint at GET /api/documents/{id}/content:
    • Uses get_regular_user dep — 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.id OR Share.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 StreamingResponse with content-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

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:

  • PreferencesUpdate Pydantic model with pdf_open_mode: Literal["in_app", "new_tab"]
  • GET /api/auth/me/preferences — returns {"pdf_open_mode": ...} using get_current_user (both roles)
  • PATCH /api/auth/me/preferences — validates via Literal, updates current_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_SATISFIABLE is deprecated in the installed FastAPI version; HTTP_416_RANGE_NOT_SATISFIABLE is the current constant
  • Fix: Used HTTP_416_RANGE_NOT_SATISFIABLE throughout
  • 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 User class in models.py did not declare pdf_open_mode
  • Fix: Added pdf_open_mode: Mapped[str] with server_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 exists
  • backend/api/auth.py — /me/preferences routes registered (GET + PATCH)
  • backend/db/models.py — pdf_open_mode column on User model
  • backend/tests/test_documents.py — 8 streaming proxy tests pass
  • backend/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)