Skip to content

Workspace upload policy + Task media — Production Readiness

FieldValue
Date2026-09-09
StatusGo — engineering complete (incl. authz/isolation Pest + mid-batch store rollback); Ops migrate + staging smoke before production traffic
ScopeTenant storage.upload_policy (types + per-category max sizes) · shared enforcement on content uploads · Task + task-note multi-file attachments · SPA Upload limits + useUploadPolicy
Catalogstorage → 1.1.0 · tasks → 1.4.0
CompanionStorage production readiness · Storage ops · Developer storage · Tasks user guide

Executive summary

This delivery adds a workspace-wide upload policy (Settings → Storage → Upload limits) and ClickUp-style task media (record + note attachments on the uploads disk with quota accounting).

  • Setting key storage.upload_policy with platform caps in config/storage.php
  • WorkspaceUploadPolicy + ValidatesWorkspaceUploads on Chat, Expenses, Help Desk, Documents, Feedback, Knowledge Base, Lead imports, WhatsApp, and Tasks
  • Tables task_attachments / task_note_attachments; auth’d download/delete; bytes in WorkspaceStorageService::usedBytes
  • SPA: Upload limits UI (storage.manage + settings.update); useUploadPolicy accept + client checks across content upload surfaces
  • Batch quota: task multi-file attach asserts sum of all files against remaining allowance before any store
  • Mid-batch store failure rolls back written objects + DB rows before rethrowing
  • Settings updateMany resolves the admin catalog outside the write transaction (avoids PHP 30s timeouts)
  • One-session Playwright human flow (npm run test:e2e:upload-policy); Pest policy + task attachment suites (incl. storage.manage 403 + cross-tenant download/delete)

Go / No-Go: Go — ship after companion CI green; Ops migrate catalog bumps and complete staging smoke. Mobile task media remains deferred (accepted for this release).

GateResult
Migrations 040000 attachments + 040100 catalog bumpsPass
Catalog DB storage 1.1.0 / tasks 1.4.0Pass
CatalogSeeder versions alignedPass
Policy write gated (settings.update + storage.manage)Pass (+ Pest 403 without storage.manage)
Cross-surface BE validationPass (FormRequests)
Task attach policies + private disk (public: false)Pass (+ Pest cross-tenant 404)
Batch quota assert (multi-file)Pass (Pest)
Mid-batch store rollbackPass (Pest)
FE Upload limits + useUploadPolicy surfacesPass
Pest WorkspaceUploadPolicyTest + TaskAttachmentTestPass (local 2026-09-09, 14 tests)
Playwright test:e2e:upload-policyPass (local 2026-09-09, ~4.5m)
Docs user/API/changelog + this readiness pagePass
Mobile task attachments / upload-policy UIDeferred (Product-accepted)
Soft concurrent over-quota (cross-request race)Accepted residual (same as Storage v1)
Content malware scanAccepted residual (extension allowlist)

Catalog version path

MigrationEffect
2026_09_09_040000_create_task_attachments_tablestask_attachments + task_note_attachments
2026_09_09_040100_bump_tasks_and_storage_module_versions_for_upload_policystorage → 1.1.0, tasks → 1.4.0

Production: migrate only. Do not db:seed on upgrade. Fresh local/CI seed uses CatalogSeeder versions aligned to these bumps.


Deploy order

  1. Deploy Backend
  2. php artisan migrate --force (through 040100)
  3. Confirm central catalog storage.version = 1.1.0, tasks.version = 1.4.0
  4. Confirm FILESYSTEM_UPLOADS_DISK / object storage (existing Storage runbook) — task objects under tenants/{uuid}/tasks/
  5. Deploy SPA
  6. Deploy Docs
  7. Staging smoke below

Suggested merge order: Backend → Frontend → Docs.

No new env vars or queue workers. Uploads remain synchronous.


Pre-flight checklist

#CheckOwnerPass?
1Migrations through 040100 appliedOps
2Catalog storage = 1.1.0, tasks = 1.4.0Ops
3Settings → Storage shows Upload limits; save requires storage.manageQA
4Task create with 2 images → view shows both; download works; delete removes objectQA
5Comment with note attachment; download worksQA
6Rejected type (e.g. .exe) blocked client-side on Tasks / Documents / ExpensesQA
7Documents Office-style types still upload when enabled in policyQA
8Storage quota still blocks oversize / over-allowance uploadsQA
9Pest Storage + Task attachment suites green in CIEng
10Playwright npm run test:e2e:upload-policy greenQA

Staging smoke (human)

  1. Marketplace → Storage installed (or already entitled)
  2. Settings → Storage → set max image 0.1 MB, uncheck GIF, Save upload limits
  3. Tasks → New (full page) → empty title validation → attach .exe (rejected) → attach small PNG + TXT → Create & View → files listed
  4. Add comment with TXT attachment
  5. Documents → reject .exe → upload .txt / Office type allowed by policy
  6. Expenses / Help Desk create → reject .exe, accept allowed image/text
  7. Restore Upload limits to defaults (or leave documented test values)

Audit findings → remediation

IDSeverityFindingAction
H1HighMulti-file assertCanStore per file could overshoot quotaFixed — batch byte sum before store (TaskService::attachFiles / attachNoteFiles) + Pest
H2HighSettings PUT double forAdminApi / in-transaction catalog walk → PHP 30sFixed — single resolve outside write transaction
M1MediumCatalogSeeder missing bump versionsFixedtasks 1.4.0, storage 1.1.0
M2MediumDeveloper tasks guide still cited 1.2.0Fixed in this ship
M3MediumThin Pest on storage.manage 403 / cross-tenant downloadFixed — Pest 403 + cross-tenant download/delete 404 (task + note)
M4MediumMid-batch attach could leave orphan objectsFixedstoreAttachmentBatch deletes paths/rows on failure + Pest
L1LowLead import accept fixed to csv/txt/xlsxIntentional; size/type still via policy
I1InfoMobile deferredAccepted for this release — release notes
I2InfoExtension allowlist (no content virus scan)Accepted SaaS posture
I3InfoSoft cross-request quota raceSame as Storage v1

Rollback

LayerAction
FrontendRedeploy previous SPA (Upload limits UI + task media disappear; older clients ignore new fields)
Backend codeRedeploy previous release; catalog version may remain 1.1.0 / 1.4.0 (display-only)
SchemaForward-fix preferred — do not migrate:rollback in production; attachment tables are additive
Policy settingRows in tenant_settings for storage.upload_policy can remain; unused without new code

Sign-off

RoleNameDateDecision
Engineering2026-09-09Go (CI green + Ops smoke still required before traffic)
Ops☐ Migrate + catalog confirm + staging smoke
Product☑ Mobile deferred accepted for this release

Current decision (2026-09-09): Go — engineering residuals from the audit are closed; merge after companion CI green; Ops migrate through 040100 and complete staging smoke before production traffic. Mobile task media remains out of scope.


Official documentation for the EloSync SaaS Platform.