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.
Live status — 2026-08-09
This issue is no longer an all-greenfield lifecycle plan. The implementation is split across active, unmerged work and remaining product UX/integration work:
fix(security): require signed tenant claims on admin endpoints #268 already implements most of the lower lifecycle/security substrate described below on its branch: signed administrative tenant authorization, tenant-scoped mutation contracts, immutable/non-reusable job identity and generation fences, durable deletion receipts, restart/replay validation, cleanup retry/fairness evidence, privacy-safe audit pseudonymization and low-cardinality deletion metrics. It remains ACTIVE_PR, not protected-main behavior, and is dependency-gated behind fix(security): harden audit pseudonymization and refresh Netty evidence #270.
the remaining buyer-facing lifecycle gap after those branches integrate is the end-to-end user deletion/download experience and its exact integration/acceptance evidence, not a duplicate reimplementation of fix(security): require signed tenant claims on admin endpoints #268's lifecycle substrate.
Therefore do not open duplicate PRs for the immutable identity/deletion-receipt/recovery work already owned by #268. First integrate/reconcile the active stack, then implement only the remaining bounded lifecycle slices against the new protected-main baseline.
This issue replaces the corrupted and closed PR #175. Current dependency order is:
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.
Dedicated tenant permission and signed artifact-delivery authority are separate controls; an authorized tenant request must not bypass token integrity, expiry, scope, document/tenant/checksum binding, issued-ledger membership, revocation, Range, or read-audit semantics where the byte-delivery contract applies.
End-to-end deletion lifecycle contract
The repository-level tenant predicate is necessary but not sufficient. Artifact cleanup and worker scheduling after a scoped state mutation must remain safe under concurrency and identifier reuse.
A conversion job_id is immutable and MUST NOT be reusable after deletion. Persist/reserve a tombstone or versioned lifecycle identity 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-equivalent contract 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 controlled pending/confirmed-absence state, 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. Retain retryable durable evidence and expose only truthful pending/failure/completion state.
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, viewer bootstrap and retained token/read evidence unavailable or retained only according to the documented security/retention policy.
#268 is the current implementation owner for these lower-layer invariants. This issue remains the umbrella product acceptance authority until the integrated user flow is complete.
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, canonical zero/single-range semantics, Cache-Control: no-store, and X-Content-Type-Options: nosniff.
Never reveal the original filename or artifact existence before tenant authorization.
Require canonical signed artifact delivery where applicable; revocation and controlled read-audit evidence remain part of the byte authority.
Revoke or invalidate all issued artifact links when deletion is requested according to the lifecycle policy; 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.
Keep byte-download and deletion behavior truthful under retries/network errors.
Slice D3 — integrated recovery/release acceptance
Prove restart after accepted deletion, cleanup failure/retry, duplicate DELETE, stale generation, cross-tenant UUID probes, artifact-link invalidation, and buyer-visible recovery states on one exact integrated protected head.
Each remaining slice must be independently reviewable and must not mix unrelated dependency, scheduler, or release-control 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.
Missing/revoked/mismatched artifact token cannot be bypassed through a convenience download route.
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/receipt identity may be authoritative.
Crash after receipt/tombstone acceptance 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 controlled audit evidence and enqueues exactly once; missing/not-eligible/stale-generation paths never enqueue replacement work.
Verify signed artifact links stop serving according to deletion-state policy and never after cleanup 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, bytes, signed token, Range, revocation and read-audit evidence.
Production statement coverage 100% and branch coverage 100% for owned code.
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 valid unresolved threads, independent write-authorized approval, and canonical changelog/ADR/release evidence.
Modular and MSA boundary
Keep 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 explicitly implement the same tenant predicate, generation, tombstone, receipt/outbox and recovery semantics.
Preserve the versioned naruon/MSA integration boundary and do not couple the viewer to a single external host or storage vendor.
Database objects 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/lifecycle layer, weaken branch protections, use a global lookup followed by an unscoped mutation, swallow cleanup failures, reuse deleted identifiers, race the active #270/#268/#264 writers, or treat advisory/model/status evidence 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.
Live status — 2026-08-09
This issue is no longer an all-greenfield lifecycle plan. The implementation is split across active, unmerged work and remaining product UX/integration work:
ACTIVE_PR, not protected-main behavior, and is dependency-gated behind fix(security): harden audit pseudonymization and refresh Netty evidence #270.ACTIVE_PRrather than shipped until integration.Therefore do not open duplicate PRs for the immutable identity/deletion-receipt/recovery work already owned by #268. First integrate/reconcile the active stack, then implement only the remaining bounded lifecycle slices against the new protected-main baseline.
This issue replaces the corrupted and closed PR #175. Current dependency order is:
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 repository-level tenant predicate is necessary but not sufficient. Artifact cleanup and worker scheduling after a scoped state mutation must remain safe under concurrency and identifier reuse.
job_idis immutable and MUST NOT be reusable after deletion. Persist/reserve a tombstone or versioned lifecycle identity 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_failed#268 is the current implementation owner for these lower-layer invariants. This issue remains the umbrella product acceptance authority until the integrated user flow is complete.
Download contract
SUCCEEDEDjobs with an authorized artifact resource.Content-Disposition, exact digest, canonical zero/single-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.Remaining bounded implementation sequence
Integration gate — active substrate
Slice D1 — user-facing deletion API contract
Slice D2 — accessible product flow
Slice D3 — integrated recovery/release acceptance
Each remaining slice must be independently reviewable and must not mix unrelated dependency, scheduler, or release-control changes.
Verification
Authorization and concealment
Concurrency and lifecycle
Product and quality
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/lifecycle layer, weaken branch protections, use a global lookup followed by an unscoped mutation, swallow cleanup failures, reuse deleted identifiers, race the active #270/#268/#264 writers, or treat advisory/model/status evidence 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/