You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Complete the Clearfolio document lifecycle so an authorized user can download a converted PDF and request deletion with an accessible, truthful, retryable result. No step may cross tenant boundaries, expose object existence, reuse a deleted identifier, or report completion while a confidential artifact remains available.
This issue replaces the corrupted and closed PR #175. Implementation ordering is now:
Require explicit artifact:read permission for converted-PDF download.
Require explicit job:delete permission for user-facing deletion and admin:write for administrative deletion.
Resolve tenant and subject from the signed production authentication boundary; client-supplied unsigned demo headers are not production credentials.
Enforce same-tenant ownership before reading artifact bytes, returning filenames, disclosing job existence, changing lifecycle state, or scheduling cleanup.
Use non-enumerating denial responses and do not leak cross-tenant filenames, status, artifact metadata, checksums, or storage paths.
Record privacy-safe, domain-separated pseudonymous audit evidence for allowed, denied, missing, accepted, cleanup-pending, cleanup-failed, and completed decisions without raw subject identifiers, tokens, filenames, or document content.
Treat every page, header, log field, export, and audit event as tenant-scoped output.
End-to-end deletion lifecycle contract
The current repository-level tenant predicate is necessary but not sufficient. Artifact cleanup and worker scheduling occur after the scoped state mutation and are keyed only by jobId; therefore the product must make post-mutation side effects safe under concurrency and identifier reuse.
A conversion job_id is immutable and MUST NOT be reusable after deletion. Persist a tombstone or versioned lifecycle record so a later tenant cannot create a different object under the same identifier.
Do not implement deletion as an untracked repository delete -> best-effort artifact delete sequence.
Use one durable deletion state machine or transactional outbox with at least:
deletion_requested
metadata_tombstoned
artifact_cleanup_pending
artifact_cleanup_completed
artifact_cleanup_failed
Bind cleanup work to an immutable deletion receipt containing tenant, job identifier, object version/generation, artifact digest or storage generation, request identifier, and audit correlation identifier. The worker must reject a stale receipt rather than deleting a newer artifact.
Prevent a same-identifier cross-tenant replacement between authorization, repository mutation, artifact cleanup, and retry enqueue.
An accepted retry must enqueue exactly the lifecycle generation that was atomically transitioned. A stale or replaced generation must not be processed.
Artifact cleanup failure must not be swallowed and reported as completed deletion. Return a truthful accepted/pending or failed result and retain retryable audit evidence.
Repeated identical DELETE requests must produce the same intended effect without duplicate cleanup or contradictory responses.
A completed deletion must make job metadata, artifact bytes, signed links, revocation records, and viewer bootstrap unavailable according to the documented retention policy.
Download contract
Render Download only for SUCCEEDED jobs with an authorized artifact resource.
Serve a real PDF fixture with expected media type, safe Content-Disposition, exact digest, range semantics, Cache-Control: no-store, and X-Content-Type-Options: nosniff.
Never reveal the original filename or artifact existence before tenant authorization.
Revoke or invalidate all issued artifact links when deletion is requested; no link may continue serving bytes after cleanup completion.
Accessible UX contract
Render Delete with a document-specific accessible name.
Require explicit confirmation and support cancellation without a network request.
Distinguish Deleting…, Cleanup pending, Deletion failed, and Deleted; do not collapse them into a false success state.
Restore button text, accessible name, disabled state, focus, session history, and KPI state on success, authorization denial, server error, cleanup retry, and network error.
Keep filenames containing markup inert text.
Provide keyboard, touch, screen-reader, print/PDF, and exact-value evidence for lifecycle status.
Add in-memory reference behavior and deterministic concurrency/property tests.
Do not add the HTTP delete action yet.
Slice B — durable deletion receipt and outbox
Atomically create deletion_request, deletion_receipt, and artifact_cleanup_task records with the metadata tombstone.
Reject stale tenant, generation, or digest receipts.
Add crash/restart and duplicate-request recovery tests.
Slice C — artifact cleanup worker
Revoke signed links, delete only the exact artifact generation, record retryable failure, and complete the lifecycle monotonically.
Add timeout, permission, missing-object, corrupt-metadata, and storage-generation tests.
Slice D — API and accessible product flow
Add authorized download and deletion endpoints after the lower layers are proven.
Add confirmation, pending/failure/completion UI, focus restoration, exact-value status, and real browser/DOM tests.
Each slice must be independently reviewable and must not mix release, dependency, scheduler, or unrelated administrative changes.
Verification
Authorization and concealment
Missing, malformed, expired, future-dated, invalid-signature, wrong-permission, and cross-tenant signed claims.
Artifact-byte, filename, digest, status, and object-existence non-disclosure.
Same-tenant success and cross-tenant/missing equivalence.
Concurrency and lifecycle
Replace the same UUID with another tenant immediately before and immediately after the scoped mutation; no replacement metadata or artifact may be deleted, retried, or enqueued.
Attempt identifier reuse after tombstoning; creation must fail closed.
Race duplicate DELETE requests; exactly one lifecycle transition and cleanup receipt may be created.
Crash after tombstone but before artifact deletion, then restart and resume cleanup.
Artifact store timeout, permission failure, missing artifact, corrupted metadata, and stale generation receipt.
Accepted retry records the actor fingerprint and enqueues exactly once; missing/not-eligible/stale-generation paths never enqueue.
Verify signed artifact links stop serving after deletion completion.
Product and quality
Browser/DOM tests for confirmation cancellation, pending, completion, retryable failure, focus restoration, duplicate activation prevention, and accessible busy state.
Real PDF download fixture with expected headers, digest, and bytes.
Production statement coverage 100% and branch coverage 100%.
Complete beginner-readable public Javadocs/docstrings.
Property and concurrency tests for lifecycle monotonicity and identifier non-reuse.
Exact-head CI, Security Scan, SAST, fuzzing, CodeRabbit/OpenCode/Noema review, zero unresolved threads, independent write-authorized approval, and CHANGELOG.md/ADR updates.
Modular and MSA boundary
Keep the repository, state store, artifact store, deletion receipt/outbox, audit sink, and worker behind versioned interfaces.
Standalone in-memory mode must remain functional, while durable adapters must explicitly implement the same tenant predicate, generation, tombstone, and outbox semantics.
Preserve the versioned naruon/MSA integration boundary and do not couple the viewer to a single external host or storage vendor.
Database objects must use descriptive two-or-more-word snake_case names, including deletion_request, deletion_receipt, artifact_cleanup_task, job_tombstone, and audit_event.
Scope boundary
Do not add generated repair scripts, duplicate the authentication layer, weaken branch protections, use a global lookup followed by an unscoped mutation, swallow cleanup failures, reuse deleted identifiers, or treat an advisory bot response as protected-branch approval.
Buyer-visible outcome
Complete the Clearfolio document lifecycle so an authorized user can download a converted PDF and request deletion with an accessible, truthful, retryable result. No step may cross tenant boundaries, expose object existence, reuse a deleted identifier, or report completion while a confidential artifact remains available.
This issue replaces the corrupted and closed PR #175. Implementation ordering is now:
Do not revive or depend on superseded #266.
Security and authorization contract
artifact:readpermission for converted-PDF download.job:deletepermission for user-facing deletion andadmin:writefor administrative deletion.End-to-end deletion lifecycle contract
The current repository-level tenant predicate is necessary but not sufficient. Artifact cleanup and worker scheduling occur after the scoped state mutation and are keyed only by
jobId; therefore the product must make post-mutation side effects safe under concurrency and identifier reuse.job_idis immutable and MUST NOT be reusable after deletion. Persist a tombstone or versioned lifecycle record so a later tenant cannot create a different object under the same identifier.repository delete -> best-effort artifact deletesequence.deletion_requestedmetadata_tombstonedartifact_cleanup_pendingartifact_cleanup_completedartifact_cleanup_failedDownload contract
SUCCEEDEDjobs with an authorized artifact resource.Content-Disposition, exact digest, range semantics,Cache-Control: no-store, andX-Content-Type-Options: nosniff.Accessible UX contract
Deleting…,Cleanup pending,Deletion failed, andDeleted; do not collapse them into a false success state.Bounded implementation sequence
Slice A — immutable lifecycle identity
Slice B — durable deletion receipt and outbox
deletion_request,deletion_receipt, andartifact_cleanup_taskrecords with the metadata tombstone.Slice C — artifact cleanup worker
Slice D — API and accessible product flow
Each slice must be independently reviewable and must not mix release, dependency, scheduler, or unrelated administrative changes.
Verification
Authorization and concealment
Concurrency and lifecycle
Product and quality
CHANGELOG.md/ADR updates.Modular and MSA boundary
snake_casenames, includingdeletion_request,deletion_receipt,artifact_cleanup_task,job_tombstone, andaudit_event.Scope boundary
Do not add generated repair scripts, duplicate the authentication layer, weaken branch protections, use a global lookup followed by an unscoped mutation, swallow cleanup failures, reuse deleted identifiers, or treat an advisory bot response as protected-branch approval.
References
Fielding, R., Nottingham, M., & Reschke, J. (2022). HTTP semantics (RFC 9110). Internet Engineering Task Force. https://www.rfc-editor.org/rfc/rfc9110
OWASP Foundation. (2023). OWASP API Security Top 10—2023: API1:2023 Broken object level authorization. https://owasp.org/API-Security/editions/2023/en/0x11-t10/