---
id: CAP-PFM-MTD-007
title: Prepare Image and File Uploads
feature: FEAT-PFM-MTD-02
product_area: platform
module: metadata
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: partially-observed
supersedes:
  - CAP-CO-REC-014
  - CAP-CO-XAP-007
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-platform:docs/milestones/PLAT-M10-image-and-file-fields.md#D1, D4'
  - 'services-platform:docs/milestones/plans/PLAT-M10-plan.md#6. Approach; 9. Acceptance scenarios'
purpose: >-
  A staff member needs a shared way to send a selected file before saving its owning record. Upload issuance
  provides an expiring staging address and an accountable declaration.
outcomes:
  - A staff member needs a shared way to send a selected file before saving its owning record.
  - Issuance records and audits the request.
actors:
  - ACT-PFM-008
  - ACT-PFM-007
surfaces:
  - console
  - api
preconditions:
  - The caller can request uploads; record-write permission is evaluated separately.
postconditions:
  - Issuance leaves one upload declaration and its security audit event.
permissions:
  - key: platform.files.upload
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-PFM-MTD-007-01
    proved_by: [ATS-PFM-MTD-007-01, TST-PFM-MTD-078, TST-PFM-MTD-084]
    statement: >-
      Upload issuance requires the upload permission, held by Platform Administrator and User but absent from
      Read Only; refusal issues nothing.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/files/tests/e2e/files.e2e.spec.js#is refused 403 by the dispatcher, and
      nothing is issued
    origin: 'services-platform:docs/milestones/plans/PLAT-M10-plan.md#PLAT-M10-S11'
  - id: BR-CAP-PFM-MTD-007-02
    proved_by: [ATS-PFM-MTD-007-02, TST-PFM-MTD-078, TST-PFM-MTD-082]
    statement: >-
      The signed caller context must include the workspace named in the route, and requests cannot substitute
      a workspace in the body or use another customer’s workspace.
    kind: permission
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/files/tests/e2e/files.e2e.spec.js#refuses a body that names a workspace of its
      own
    origin: 'services-platform:docs/milestones/plans/PLAT-M10-plan.md#PLAT-M10-S04'
  - id: BR-CAP-PFM-MTD-007-03
    proved_by: [ATS-PFM-MTD-007-03, TST-PFM-MTD-082, TST-PFM-MTD-083]
    statement: >-
      Upload size must be a positive whole byte count within ten mebibytes for images or twenty-five for
      files; oversized requests name the size problem without signing or recording an upload.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/files/tests/integration/services/uploads/issue-upload.integration.spec.js#refuses
      a picture over 10 MiB, naming size, and signs and records nothing
    origin: >-
      services-platform:docs/milestones/PLAT-M10-image-and-file-fields.md#D4 (Andrew, 2026-10-19: 10 MiB / 25
      MiB)
  - id: BR-CAP-PFM-MTD-007-04
    proved_by: [ATS-PFM-MTD-007-04, TST-PFM-MTD-083]
    statement: >-
      Images permit JPEG, PNG, GIF and WebP but exclude SVG; files additionally permit supported document,
      text, spreadsheet and archive formats, while mismatched image types and executables are refused.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/files/tests/integration/services/uploads/issue-upload.integration.spec.js#refuses
      an SVG picture, naming content_type, and signs and records nothing
    origin: >-
      services-platform:docs/milestones/plans/PLAT-M10-plan.md#4. Assumptions A7 (Andrew, 2026-10-08: SVG
      refused)
  - id: BR-CAP-PFM-MTD-007-05
    proved_by: [ATS-PFM-MTD-007-05, TST-PFM-MTD-083]
    statement: >-
      Platform derives staging location from workspace, record-type folder, a fresh upload identifier and a
      safe filename, uses public staging for images and rejects filenames containing paths.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/files/tests/unit/upload-keys.spec.ts#is tmp, the workspace, the object folder,
      a public- upload directory for a picture, and the file name
    origin: none
  - id: BR-CAP-PFM-MTD-007-06
    proved_by: [ATS-PFM-MTD-007-06, TST-PFM-MTD-078, TST-PFM-MTD-085]
    statement: >-
      The signed upload expires after fifteen minutes and binds declared type, length and uploader identity so
      storage rejects a changed declaration and saving can identify the uploader.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/files/tests/unit/upload-presign.spec.ts#signs the type, the length and both
      metadata headers, so S3 refuses a PUT that changes any
    origin: 'services-platform:docs/milestones/plans/PLAT-M10-plan.md#6. Approach'
  - id: BR-CAP-PFM-MTD-007-07
    proved_by: [ATS-PFM-MTD-007-07, TST-PFM-MTD-082]
    statement: >-
      Issuance records caller, object, field, location, type, size and expiry together with its security audit
      event.
    kind: policy
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-platform:modules/files/tests/integration/services/uploads/issue-upload.integration.spec.js#appends
      one file_upload audit event naming who was given the upload and for what
    origin: 'services-platform:docs/milestones/plans/PLAT-M10-plan.md#7. Deliverables'
  - id: BR-CAP-PFM-MTD-007-08
    proved_by: [ATS-PFM-MTD-007-08]
    statement: >-
      The owning save checks and copies uploaded or web-address files into managed storage and must refuse
      staging files issued to a different saving person.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: documented
    source: 'services-platform:docs/files.md#The signature'
    origin: >-
      services-platform:docs/milestones/PLAT-M10-image-and-file-fields.md#D1 (Andrew, 2026-10-19: copy at
      save)
scenarios:
  - id: SC-CAP-PFM-MTD-007-01
    given: A staff editor is selecting Ruth Kim contact photo.
    when: Request staging for a forty-eight-kilobyte JPEG.
    then: 'The response supplies an upload identity, expiring PUT address, required headers and save reference.'
    provenance: test
    source: >-
      services-platform:modules/files/tests/e2e/files.e2e.spec.js#answers a PUT upload with the headers and
      the staging reference of this workspace
edge_cases:
  - id: SC-CAP-PFM-MTD-007-02
    given: The caller has customer administrator permissions.
    when: Request an oversized image and an SVG upload.
    then: Both requests identify the size or media-type problem and issue nothing.
    provenance: test
    source: >-
      services-platform:modules/files/tests/e2e/files.e2e.spec.js#is refused an SVG picture by its type, and
      nothing is issued
constraints: []
depends_on: []
related:
  - CAP-PFM-MTD-005
  - CAP-PFM-MTD-012
journeys: []
open_questions: []
concepts:
  - CON-PFM-MTD-002
evidence:
  - >-
    services-platform at ad3f6a6582843008ed0f5a17b131878d15829af1: modules/files/aws/api/files.routes.ts ,
    services/uploads/issue-upload.ts, upload-storage.ts, services/persistence/file-uploads.ts,
    db/file-uploads.table.ts, files.settings.ts; tests e2e/files.e2e.spec.js,
    integration/services/uploads/issue-upload.integration.spec.js, unit/upload-keys.spec.ts,
    upload-presign.spec.ts, upload-permission.spec.ts; docs/files.md, docs/assets.md;
    docs/milestones/PLAT-M10-image-and-file-fields.md and plans/PLAT-M10-plan.md.
controls: [TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
exercised_by: [FAS-PFM-MTD-02-03, FAS-PFM-MTD-02-04]
suites: [TST-PFM-MTD-078, TST-PFM-MTD-082, TST-PFM-MTD-083, TST-PFM-MTD-084, TST-PFM-MTD-085]
---

# Prepare Image and File Uploads

## Purpose

A staff member needs a shared way to send a selected file before saving its owning record. Upload issuance provides an expiring staging address and an accountable declaration.

## How It Works

The editor declares the destination field and the file characteristics. Platform validates size, media type and filename. It creates a staging location and signs the upload request. The browser sends the bytes directly to storage using the returned headers. The response also contains the reference needed by the record save. Issuance records and audits the request. The owning save remains responsible for preparing and attaching the asset, and issuance alone does not prove that save-side enforcement.

## Relationships

Image and file definitions identify the intended use. Custom-record saving delegates managed file preparation to the shared asset pipeline.
