Files
pad/cmd
xarmian aa49db396e feat(storage): enforce plan storage limits at upload; Pro 1 GB pooled per account, Free 100 MB (TASK-3619) (#2110)
* feat(storage): enforce plan storage limits at upload; Pro 1 GB pooled per account, Free 100 MB (TASK-3619)

Until now, no plan's storage limit was enforced: the only check was an async
log line after the insert. Pro was unlimited by code.

- CreateAttachmentForLiveItem enforces the owner's storage_bytes limit inside
  its own transaction when passed WithPlanLimit (cloud mode only), for
  user-visible originals only; variants never refuse. The upload and image
  transform doors pass it and answer 403 plan_limit_exceeded
  (feature=storage_bytes, limit/current/requested in bytes). The message names
  the plan and says existing files stay available.
- Pro: DefaultProLimits.StorageBytes = 1 GB, pooled per ACCOUNT across every
  workspace the owner owns, soft-deleted ones included until purged. Free:
  DefaultFreeLimits.StorageBytes = 100 MB per workspace (Dave, PLAN-3605).
  Self-hosted stays unlimited.
- The lock is an owner-keyed advisory lock taken first, so concurrent uploads
  into one account's workspaces serialise (proved on Postgres).
- SeedPlanLimits rewrites a stored storage value only where it is still the old
  seed (Pro 10737418240, Free 524288000), and logs once.
- Web: Pro payers get "Need more? Contact us" (support@getpad.dev). Editor,
  comment and transform refusals raise the plan-limit prompt, fenced on
  identity. Settings → Storage and pad workspace storage say when usage is
  account-wide.

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* fix(web): comment upload refusals raise the storage prompt only for the identity that started them (TASK-3619, codex r1)

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* fix(storage): conditional seed rewrite; stale-identity storage refusals are silent (TASK-3619, codex r2)

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* fix(store): the storage check verifies the owner it locked, retrying on a mid-check ownership change (TASK-3619, codex r3)

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
2026-10-12 15:12:36 -04:00
..