docs(14.1): add phase plans (5 plans, waves 1-5)
This commit is contained in:
@@ -0,0 +1,210 @@
|
|||||||
|
# Phase 14.1 Research: Cloud/Local File Parity Hardening
|
||||||
|
|
||||||
|
Execution note: produced via Codex generic-agent workaround for gsd-phase-researcher because typed GSD agent dispatch failed before launch.
|
||||||
|
|
||||||
|
## User Constraints
|
||||||
|
|
||||||
|
### Phase Boundary
|
||||||
|
|
||||||
|
Phase 14.1 hardens the already-shipped cloud file experience so cloud files opened, viewed, downloaded, analyzed, retried, re-analyzed, and displayed after analysis behave like local documents where the user-facing concepts match. Cloud files remain provider-owned `CloudItem` records, not imported local `Document` rows. All cloud bytes continue through DocuVault authorization and the existing cache lifecycle; provider URLs, credentials, cache object keys, cross-provider transfer, unified search, and broader provider change tracking remain out of scope.
|
||||||
|
|
||||||
|
### Implementation Decisions
|
||||||
|
|
||||||
|
#### Open/view/download parity
|
||||||
|
- **D-01:** Cloud file rows/cards open into a document-like detail view backed by `CloudItem`, not a local `Document` import.
|
||||||
|
- **D-02:** The cloud detail view exists before analysis. If a cloud file is not analyzed yet, the detail view offers Analyze; after analysis, the same view fills in extracted text, topics, and status.
|
||||||
|
- **D-03:** Preview and download controls in the cloud detail view mirror local document detail controls and placement, while calling authorized cloud preview/download handlers that hydrate bytes through the cache lifecycle.
|
||||||
|
- **D-04:** The cloud detail view stays visually aligned with local document detail and uses only subtle source metadata, such as provider, location, and current/stale status, to show that the file is provider-owned.
|
||||||
|
|
||||||
|
#### Analyzed metadata display
|
||||||
|
- **D-05:** Once analysis completes, cloud detail shows the same core sections as local documents: extracted text, topics, analysis status, preview/download controls, and subtle source metadata.
|
||||||
|
- **D-06:** `StorageBrowser.vue` rows/cards should match local rows/cards wherever equivalent data exists, including topic badges, analysis/current/stale state, and available actions in the same positions.
|
||||||
|
- **D-07:** Stale cloud analysis keeps prior extracted text and topics visible, marks them stale, and offers Re-analyze.
|
||||||
|
- **D-08:** Partial analysis results remain visible. For example, extracted text can display while failed classification/topics are marked clearly with a targeted Retry analysis or Re-analyze action.
|
||||||
|
|
||||||
|
#### Retry and re-analyze states
|
||||||
|
- **D-09:** Rename visible "Re-classify" copy to "Re-analyze" everywhere. Preserve existing local behavior/API unless planning finds an internal rename is necessary.
|
||||||
|
- **D-10:** Re-analyze appears consistently in local and cloud detail/row action locations when analysis exists or is stale/failed.
|
||||||
|
- **D-11:** Explicit Re-analyze on an already-current cloud file allows the user to force fresh extraction/classification after confirmation, instead of silently skipping as already-current.
|
||||||
|
- **D-12:** Failed analysis retry from rows/cards/detail uses the existing job retry semantics where possible; if no active job exists, create a single-item retry job.
|
||||||
|
|
||||||
|
#### Unsupported and provider-limited actions
|
||||||
|
- **D-13:** Unsupported cloud preview/download/analyze cases use the same shared action positions as local files, disabled or typed with clear backend-provided reasons.
|
||||||
|
- **D-14:** If a cloud file cannot be previewed in-app but can be downloaded, show Preview unavailable with the reason and keep authorized Download active. Do not auto-download from Preview.
|
||||||
|
- **D-15:** If a provider lacks reliable version/etag metadata, use the existing fallback metadata fingerprint and surface uncertainty only when it affects a user action.
|
||||||
|
- **D-16:** Unsupported analysis appears everywhere the Analyze action would appear, disabled with the same reason text in row/card/detail.
|
||||||
|
|
||||||
|
#### Parity tests
|
||||||
|
- **D-17:** Frontend parity tests use paired local/cloud assertions in shared components and detail surfaces, checking equivalent controls, labels, topic/status placement, and disabled states.
|
||||||
|
- **D-18:** Backend Phase 14.1 tests explicitly cover cache/auth boundaries: no provider URL, credentials, or `object_key` leakage; owner/admin negatives; preview/download through cache hydration; forced Re-analyze through the authorized analysis path; and no provider mutation.
|
||||||
|
- **D-19:** Tests require route-level parity: a cloud detail route opens from browser rows and renders the same core sections/actions as local detail.
|
||||||
|
- **D-20:** Provider coverage uses mocked provider contracts for deterministic parity/security tests and preserves opt-in live tests only where existing patterns already support them.
|
||||||
|
|
||||||
|
#### Codex's Discretion
|
||||||
|
- Choose exact route name/path, component extraction shape, copy, icons, and compact source metadata presentation while preserving local/cloud parity and provider-ownership clarity.
|
||||||
|
- Choose whether cloud detail shares an existing local detail component directly or extracts a shared detail surface first, as long as duplicate layouts/actions are not created.
|
||||||
|
- Choose internal naming changes only when needed for coherence or testability; visible copy must use Re-analyze.
|
||||||
|
|
||||||
|
### Deferred Ideas
|
||||||
|
|
||||||
|
- Unified keyword/semantic search across local and analyzed cloud documents remains Phase 15.
|
||||||
|
- Provider delta feeds, external-delete handling, and broad sync/change reliability remain Phase 16.
|
||||||
|
- Permanent local import/pinning of provider files remains future `IMPORT-01`; Phase 14.1 must not convert cloud files into local `Document` rows.
|
||||||
|
- Cross-provider copy/move and live parity testing for every provider remain out of scope.
|
||||||
|
|
||||||
|
## Project Constraints (from AGENTS.md)
|
||||||
|
|
||||||
|
- Use the existing stack: FastAPI/Python 3.12, SQLAlchemy async/PostgreSQL, MinIO, Vue 3 Options API/Pinia/Vue Router/Vite/Tailwind. [VERIFIED: AGENTS.md]
|
||||||
|
- JWT stays in Pinia memory only; refresh tokens stay httpOnly/Secure/SameSite=Strict. Do not add browser persistence for auth, cloud jobs, credentials, or object keys. [VERIFIED: AGENTS.md]
|
||||||
|
- Cloud credentials remain HKDF-encrypted per user; credentials decrypt only at provider/task boundaries and never enter API responses, logs, broker payloads, or frontend state. [VERIFIED: AGENTS.md]
|
||||||
|
- Every document, folder, connection, item, cache, and job path must enforce owner scoping; admin accounts must not receive document/cloud content. [VERIFIED: AGENTS.md]
|
||||||
|
- Cloud browse/refresh must not download bytes or mutate quota; open/preview/download/analysis are the only byte-hydrating paths. [VERIFIED: AGENTS.md]
|
||||||
|
- Router code imports shared helpers rather than creating local variants: `get_client_ip`, `CloudConnectionError`, AI parsing helpers, and password validation all have canonical modules. [VERIFIED: AGENTS.md]
|
||||||
|
- All cloud mutation orchestration remains in `backend/services/cloud_operations.py`; all byte cache lifecycle calls route through `hydrate_and_cache_bytes` in `backend/services/cloud_cache.py`. [VERIFIED: AGENTS.md]
|
||||||
|
- `CacheStatusOut` and `AnalysisJobOut` must never include `object_key` or `credentials_enc`; new cloud detail/browse schemas need the same strict allowlist style. [VERIFIED: AGENTS.md]
|
||||||
|
- Frontend formatting and provider styling must come from `frontend/src/utils/formatters.js`; `StorageBrowser.vue` remains the single file browser. [VERIFIED: AGENTS.md]
|
||||||
|
- `FileManagerView.vue` and `CloudFolderView.vue` must stay thin data providers; shared layout/action behavior belongs in smart components or shared detail components. [VERIFIED: AGENTS.md]
|
||||||
|
- Files with no active route/import must be deleted in the same commit. `HomeView.vue` and `FolderView.vue` must not be recreated. [VERIFIED: AGENTS.md]
|
||||||
|
- Any feature/bug fix requires focused tests; backend `pytest -v` and frontend tests must pass before phase advancement. [VERIFIED: AGENTS.md]
|
||||||
|
- Major shipped work must update AGENTS/README when user-facing/API/rule/version behavior changes, bump app versions, run security gates, commit, and push. [VERIFIED: AGENTS.md]
|
||||||
|
- Security gate must include dependency audits, owner/admin negatives, credential secrecy, no hardcoded secrets, header/CSP/auth invariants, and no high/critical CVEs. [VERIFIED: AGENTS.md]
|
||||||
|
|
||||||
|
## Standard Stack
|
||||||
|
|
||||||
|
- Use existing FastAPI routers under `backend/api/cloud/` for cloud item detail and analysis controls; no new backend framework or package is needed. [VERIFIED: codebase]
|
||||||
|
- Use SQLAlchemy ORM joins/selects over `CloudItem`, `CloudItemTopic`, `Topic`, `CloudConnection`, and `CloudAnalysisJobItem`; do not add raw SQL string interpolation. [VERIFIED: backend/db/models.py, AGENTS.md]
|
||||||
|
- Use existing Vue Router, Pinia, and shared API client barrel (`frontend/src/api/client.js`) for the cloud detail route and calls. [VERIFIED: frontend/src/router/index.js, frontend/src/api/client.js]
|
||||||
|
- Use `StorageBrowser.vue` for browser row/card parity and extract a shared detail surface from `DocumentView.vue` rather than creating a parallel cloud-only layout. [VERIFIED: frontend/src/views/DocumentView.vue, frontend/src/components/storage/StorageBrowser.vue]
|
||||||
|
- Use existing cache and analysis services: `hydrate_and_cache_bytes`, `estimate_scope`, `enqueue_analysis_job`, `retry_job_item`, and `process_cloud_analysis_item`. [VERIFIED: backend/services/cloud_cache.py, backend/services/cloud_analysis.py, backend/tasks/cloud_analysis_tasks.py]
|
||||||
|
|
||||||
|
## Current Runtime State Inventory
|
||||||
|
|
||||||
|
1. Routes: local detail exists at `/document/:id`; cloud list routes exist at `/cloud` and `/cloud/:connectionId/:folderId(.*)`; no cloud detail route currently exists. [VERIFIED: frontend/src/router/index.js]
|
||||||
|
2. Row open behavior: local `FileManagerView` routes `file-open` to `/document/${file.id}`; cloud `CloudFolderView` handles `file-open` by calling `openCloudFile` and may auto-fallback to download for unsupported preview. [VERIFIED: frontend/src/views/FileManagerView.vue, frontend/src/views/CloudFolderView.vue]
|
||||||
|
3. Detail layout: `DocumentView.vue` owns local header, topics card, `Re-classify` visible copy, suggestions, preview modal, delete, and extracted text layout directly. There is no shared detail component yet. [VERIFIED: frontend/src/views/DocumentView.vue]
|
||||||
|
4. Browser display: `StorageBrowser.vue` already renders local/cloud file rows, topic badges when `file.topics` exists, cloud analysis toolbar/actions, cloud queue, selection, and capability-disabled action buttons. It also has a local `translateStatus` duplicate despite the store exposing `translateAnalysisStatus`. [VERIFIED: frontend/src/components/storage/StorageBrowser.vue, frontend/src/stores/cloudConnections.js]
|
||||||
|
5. Backend data: `CloudItem` already stores `extracted_text`, `analysis_status`, `semantic_index_status`, etag/version/fingerprint inputs, and `CloudItemTopic` links topics without creating a `Document` row. [VERIFIED: backend/db/models.py]
|
||||||
|
6. Backend response gap: `CloudItemOut` currently exposes id/provider/name/kind/parent/content type/size/modified/etag/capabilities only; it does not expose extracted text, analysis status, semantic status, topics, provider display name, source metadata, or unsupported analysis reason. [VERIFIED: backend/api/cloud/schemas.py, backend/api/cloud/browse.py]
|
||||||
|
7. Cloud content boundary: open returns a DocuVault download URL; preview/download route through `hydrate_and_cache_bytes` when a `CloudItem` and version key exist, but fallback direct `adapter.get_object` still exists for missing metadata. Phase 14.1 should keep tests focused on the metadata-backed path and decide whether missing-metadata fallback is acceptable for detail/open parity. [VERIFIED: backend/api/cloud/operations.py]
|
||||||
|
8. Analysis idempotency: `enqueue_analysis_job` marks unchanged indexed items as `already_current`. There is no force flag in `AnalysisEnqueueRequest` or service signature, so D-11 requires an explicit API/service extension. [VERIFIED: backend/api/cloud/schemas.py, backend/services/cloud_analysis.py]
|
||||||
|
9. Retry semantics: `retry_job_item` retries by `cloud_item_id` within an existing job and allows `failed` or `queued`; if no active/known job exists, D-12 needs a single-item job creation path. [VERIFIED: backend/services/cloud_analysis.py, backend/api/cloud/analysis.py]
|
||||||
|
10. Processing behavior: `process_job_item` writes extracted text to `CloudItem`, classifies to `CloudItemTopic`, marks `CloudItem.analysis_status = "indexed"`, and counts stale as a failed UI outcome while preserving data fields. [VERIFIED: backend/services/cloud_analysis_processing.py]
|
||||||
|
|
||||||
|
## Architecture Patterns
|
||||||
|
|
||||||
|
- Add a cloud detail route keyed by connection UUID and opaque provider item ID, for example named route `cloud-file-detail` under `/cloud/:connectionId/item/:itemId(.*)` or an equivalent non-conflicting path. Pass provider IDs as opaque route params/query values and let Vue Router encode them; never split or decode provider paths in Vue. [VERIFIED: frontend/src/router/index.js, frontend/src/views/CloudFolderView.vue]
|
||||||
|
- Change cloud row open to navigate to the cloud detail route, not immediately preview/download. Keep explicit preview/download buttons on row/detail actions if added; do not trigger auto-download from Preview. [VERIFIED: frontend/src/views/CloudFolderView.vue, 14.1-CONTEXT.md]
|
||||||
|
- Extract a shared document detail surface from `DocumentView.vue` with props/events for: title, metadata line, source metadata, topics, status/stale badges, extracted text, preview availability, download availability, analyze/re-analyze/retry actions, and optional delete/share/suggest controls. Local and cloud views then provide data and event handlers. [VERIFIED: frontend/src/views/DocumentView.vue, AGENTS.md]
|
||||||
|
- Keep `DocumentView.vue` and the new cloud detail view as data-provider views. They should call stores/API and feed the shared detail surface; they should not duplicate the card/layout markup. [VERIFIED: AGENTS.md, frontend/src/views/FileManagerView.vue]
|
||||||
|
- Extend `CloudItemOut` only if browse rows need the added fields; otherwise add `CloudItemDetailOut` for the detail endpoint and add a lighter row extension for topics/status. In either case, schemas must be explicit allowlists with no `credentials_enc`, `object_key`, provider URL, raw tokens, or cache key fields. [VERIFIED: backend/api/cloud/schemas.py]
|
||||||
|
- Use a service helper under `backend/services/cloud_items.py` for owner-scoped cloud item detail resolution and topic loading if multiple routers need it; routers should translate `ValueError`/domain exceptions into HTTP responses. [VERIFIED: AGENTS.md, backend/services/cloud_items.py]
|
||||||
|
- For row/card parity, have browse responses include enough metadata for `StorageBrowser.vue`: `topics`, `analysis_status`, current/stale state if known, unsupported analysis reason, and existing size/modified fields. This lets local and cloud rows share topic badge/status placement. [VERIFIED: frontend/src/components/storage/StorageBrowser.vue, backend/api/cloud/browse.py]
|
||||||
|
- Use the Pinia store's `translateAnalysisStatus` as the single frontend status translation source. Remove or route around the duplicate `translateStatus` in `StorageBrowser.vue` during implementation. [VERIFIED: frontend/src/stores/cloudConnections.js, frontend/src/components/storage/StorageBrowser.vue]
|
||||||
|
- Add `force` or `force_reanalyze` to the cloud enqueue request/service path for explicit Re-analyze only. Default enqueue remains idempotent and skips already-current items. [VERIFIED: backend/api/cloud/schemas.py, backend/services/cloud_analysis.py]
|
||||||
|
- For forced Re-analyze, preserve no-provider-mutation and cache lifecycle boundaries: service may enqueue byte work despite already-current metadata, but processing still uses `process_cloud_analysis_item` and `hydrate_and_cache_bytes`; no local `Document` row is created. [VERIFIED: backend/services/cloud_analysis_processing.py, backend/services/cloud_cache.py]
|
||||||
|
|
||||||
|
## Don't Hand-Roll
|
||||||
|
|
||||||
|
- Do not build a second cloud file grid, card list, action row, or queue UI; extend `StorageBrowser.vue` and shared detail components. [VERIFIED: AGENTS.md]
|
||||||
|
- Do not create local `Document` rows for cloud detail, preview, analysis, re-analysis, retry, or topic display. `CloudItem` and `CloudItemTopic` are the canonical cloud analysis records. [VERIFIED: backend/db/models.py, 14.1-CONTEXT.md]
|
||||||
|
- Do not call provider SDKs directly from frontend code or expose raw provider URLs. Cloud preview/download must go through DocuVault API endpoints. [VERIFIED: frontend/src/api/cloud.js, backend/api/cloud/operations.py]
|
||||||
|
- Do not bypass `hydrate_and_cache_bytes` in open/preview/download or forced analysis paths. [VERIFIED: AGENTS.md, backend/api/cloud/operations.py]
|
||||||
|
- Do not duplicate formatters/provider colors/status translation in components. Use `utils/formatters.js` and the store/shared helpers. [VERIFIED: AGENTS.md, frontend/src/stores/cloudConnections.js]
|
||||||
|
- Do not introduce package dependencies for this phase. The needed primitives already exist in FastAPI, SQLAlchemy, Vue, Pinia, Vue Router, and the current codebase. [VERIFIED: package files not required by phase scope]
|
||||||
|
|
||||||
|
## Common Pitfalls
|
||||||
|
|
||||||
|
- Auto-downloading unsupported previews would violate D-14. Existing `CloudFolderView.onFileOpen` currently calls `downloadCloudFile` on `unsupported_preview`; the detail flow should replace this with visible "Preview unavailable" plus explicit Download. [VERIFIED: frontend/src/views/CloudFolderView.vue]
|
||||||
|
- Extending `CloudItemOut` with `extracted_text` for every browse row could inflate list payloads. Prefer row-level lightweight fields and full extracted text on the detail endpoint unless the planner intentionally accepts larger browse payloads. [VERIFIED: backend/api/cloud/schemas.py]
|
||||||
|
- `AnalysisJobItemOut` currently has no `name` field, while the frontend maps `item.name` from job status. Either tests already mock around this or the status/detail API needs alignment before relying on job item names in new detail controls. [VERIFIED: backend/api/cloud/schemas.py, frontend/src/stores/cloudConnections.js]
|
||||||
|
- `CacheStatusOut.analysis_progress_detail` is documented and typed as a string, while the frontend treats it as boolean in several places. Avoid compounding this mismatch during parity work; normalize at the store boundary or adjust tests deliberately. [VERIFIED: backend/api/cloud/schemas.py, frontend/src/stores/cloudConnections.js]
|
||||||
|
- The cloud item content routes have direct provider fetch fallbacks when no `CloudItem` metadata/version key exists. Phase 14.1 tests should prove the normal detail/open path requires owner-scoped metadata and uses cache hydration, and should decide whether to remove or explicitly constrain fallback behavior. [VERIFIED: backend/api/cloud/operations.py]
|
||||||
|
- Stale cloud analysis should not clear `CloudItem.extracted_text` or topic links. Processing already writes fields independently; UI should mark stale/failed states while rendering existing content. [VERIFIED: backend/services/cloud_analysis_processing.py, 14.1-CONTEXT.md]
|
||||||
|
- Provider item IDs can contain reserved URL/path characters. New cloud detail routes and API calls must use named routes/`encodeURIComponent` consistently and must not reconstruct breadcrumbs or locations by parsing provider IDs. [VERIFIED: frontend/src/views/CloudFolderView.vue, frontend/src/api/cloud.js]
|
||||||
|
- Local visible copy still says `Re-classify`; Phase 14.1 requires visible `Re-analyze` without necessarily renaming internal `classifyDocument` APIs. [VERIFIED: frontend/src/views/DocumentView.vue, 14.1-CONTEXT.md]
|
||||||
|
|
||||||
|
## Security Domain
|
||||||
|
|
||||||
|
- Security enforcement is required. Phase 14.1 touches auth-protected document/cloud content, cloud credentials, cache entries, and analysis jobs. [VERIFIED: AGENTS.md, 14.1-CONTEXT.md]
|
||||||
|
- ASVS V1/V2 auth-session constraints apply indirectly: do not add persistent tokens or local/session storage for access tokens; keep API calls through authenticated client helpers. [VERIFIED: AGENTS.md, frontend/src/api/utils.js]
|
||||||
|
- ASVS V4 access control applies directly: cloud detail, row metadata, preview, download, force re-analyze, retry, and job status must resolve `connection_id`, `provider_item_id`/`cloud_item_id`, job ID, and cache entry under `current_user.id`; foreign user and admin-negative tests are mandatory. [VERIFIED: AGENTS.md, backend/api/cloud/analysis.py, backend/api/cloud/operations.py]
|
||||||
|
- ASVS V5 validation applies to route/body fields: provider item IDs are opaque strings, UUIDs are parsed as UUIDs, and request schemas must explicitly declare accepted fields with no mass assignment. [VERIFIED: backend/api/cloud/schemas.py]
|
||||||
|
- ASVS V8 data protection applies to `credentials_enc`, provider tokens, provider URLs, MinIO object keys, cache metadata, extracted text, and admin access. Response schemas must remain allowlists and tests must assert no leakage. [VERIFIED: backend/api/cloud/schemas.py, backend/tests/test_cloud_security.py]
|
||||||
|
- ASVS V10 malicious code/dependency concerns are low for this phase because no package installation is needed. Keep no-new-package as the default. [VERIFIED: codebase]
|
||||||
|
- ASVS V12 file/resource handling applies to preview/download: filenames in headers must stay encoded, content disposition must match preview/download intent, and bytes must route through cache with owner checks. [VERIFIED: backend/api/cloud/operations.py]
|
||||||
|
|
||||||
|
## Verification Targets
|
||||||
|
|
||||||
|
- Backend API tests: owner can fetch cloud detail with analysis fields; foreign user gets 404; admin/regular-user boundary follows `get_regular_user`; response excludes `credentials_enc`, `object_key`, raw provider URLs, and provider tokens. [VERIFIED: backend/tests/test_cloud_security.py patterns]
|
||||||
|
- Backend cache tests: cloud detail does not hydrate bytes; preview/download from detail hydrate through `hydrate_and_cache_bytes`; browse/detail estimate paths do not call `adapter.get_object`; forced Re-analyze enqueues authorized analysis work without provider mutation. [VERIFIED: backend/tests/test_cloud_cache.py, backend/tests/test_cloud_analysis_contract.py]
|
||||||
|
- Backend force tests: default enqueue skips already-current; explicit force queues an already-current item and preserves no-provider-mutation counters. [VERIFIED: backend/services/cloud_analysis.py]
|
||||||
|
- Backend partial/stale tests: existing extracted text/topics remain returned when `analysis_status` is `stale` or latest job item is `failed`; retry/re-analyze response is typed and owner-scoped. [VERIFIED: backend/services/cloud_analysis_processing.py]
|
||||||
|
- Frontend route tests: clicking a cloud file row in `StorageBrowser` via `CloudFolderView` opens a cloud detail route, not a direct preview/download; local file rows still route to `/document/:id`. [VERIFIED: frontend/src/views/FileManagerView.vue, frontend/src/views/CloudFolderView.vue]
|
||||||
|
- Frontend paired parity tests: local/cloud detail surfaces render equivalent sections and action positions for title, metadata, preview/download, topics, analysis status, extracted text, and Re-analyze. [VERIFIED: frontend/src/views/DocumentView.vue]
|
||||||
|
- Frontend unsupported tests: unsupported cloud preview shows reason and keeps explicit Download active; Analyze/Re-analyze disabled states use shared action positions and backend-provided reasons. [VERIFIED: frontend/src/components/storage/__tests__/StorageBrowser.capabilities.test.js]
|
||||||
|
- Frontend row/card tests: paired local/cloud fixtures in `StorageBrowser.vue` assert topic badges and analysis/current/stale badges appear in the same relative area, and visible copy uses Re-analyze. [VERIFIED: frontend/src/components/storage/StorageBrowser.vue]
|
||||||
|
- Regression grep: no visible `Re-classify` remains after implementation except in historical planning/test snapshots where intentionally preserved. [VERIFIED: frontend/src/views/DocumentView.vue]
|
||||||
|
|
||||||
|
## Code Examples
|
||||||
|
|
||||||
|
### Cloud Detail Fetch Pattern
|
||||||
|
|
||||||
|
```python
|
||||||
|
# backend/api/cloud/detail.py or operations.py
|
||||||
|
@router.get("/connections/{connection_id}/items/{item_id:path}/detail", response_model=CloudItemDetailOut)
|
||||||
|
async def get_cloud_item_detail(...):
|
||||||
|
item = await resolve_owned_cloud_item_detail(
|
||||||
|
session,
|
||||||
|
user_id=current_user.id,
|
||||||
|
connection_id=connection_id,
|
||||||
|
provider_item_id=item_id,
|
||||||
|
)
|
||||||
|
return CloudItemDetailOut(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
Use a service helper for `resolve_owned_cloud_item_detail`; include topic names via `CloudItemTopic -> Topic`, connection/provider display metadata, and no cache/object credential fields. [VERIFIED: backend/services/cloud_items.py, backend/api/cloud/schemas.py]
|
||||||
|
|
||||||
|
### Forced Re-Analyze Pattern
|
||||||
|
|
||||||
|
```python
|
||||||
|
class AnalysisEnqueueRequest(BaseModel):
|
||||||
|
scope: str
|
||||||
|
provider_item_ids: Optional[list[str]] = None
|
||||||
|
recursive: bool = False
|
||||||
|
failure_behavior: str = "pause_batch"
|
||||||
|
force: bool = False
|
||||||
|
```
|
||||||
|
|
||||||
|
`force=False` keeps current idempotency. `force=True` bypasses `already_current` only for an explicit user action and still validates owner/connection/item and unsupported type. [VERIFIED: backend/api/cloud/schemas.py, backend/services/cloud_analysis.py]
|
||||||
|
|
||||||
|
### Frontend Shared Detail Surface Pattern
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<DocumentDetailSurface
|
||||||
|
:title="detailTitle"
|
||||||
|
:metadata="metadata"
|
||||||
|
:topics="topics"
|
||||||
|
:analysis-status="analysisStatus"
|
||||||
|
:extracted-text="extractedText"
|
||||||
|
:source="sourceMetadata"
|
||||||
|
:preview-state="previewState"
|
||||||
|
:download-state="downloadState"
|
||||||
|
@preview="preview"
|
||||||
|
@download="download"
|
||||||
|
@reanalyze="reanalyze"
|
||||||
|
@retry-analysis="retryAnalysis"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Local and cloud views provide handlers; the surface owns layout and action placement. [VERIFIED: frontend/src/views/DocumentView.vue, AGENTS.md]
|
||||||
|
|
||||||
|
## Package Legitimacy Audit
|
||||||
|
|
||||||
|
No external packages are recommended for Phase 14.1. The implementation should use existing backend/frontend dependencies and local services/components only. [VERIFIED: package scope/codebase]
|
||||||
|
|
||||||
|
## Research Confidence
|
||||||
|
|
||||||
|
- HIGH: Existing code paths, models, schemas, routes, stores, and tests cited above were read directly from this worktree. [VERIFIED: codebase]
|
||||||
|
- HIGH: User decisions, deferred scope, project constraints, and security/testing rules were read from phase context, ROADMAP, REQUIREMENTS, STATE, PROJECT, and AGENTS. [VERIFIED: planning docs]
|
||||||
|
- MEDIUM: Specific route path recommendation is discretionary; the planner may choose an equivalent path if it preserves opaque provider IDs and route-level parity. [ASSUMED]
|
||||||
|
- LOW: No external ecosystem/library claims are made; no web/package lookup was necessary because the phase is an in-repo parity hardening task. [ASSUMED]
|
||||||
Reference in New Issue
Block a user