Upload Token System
Upload Token System
This is the authoritative reference for the generic public upload-token product implemented in skyhawk_site_fixes.
Architecture
- Public route:
/upload/{token}. - Admin route:
/admin/skyhawk/upload-tokens. - The public route is owned by
UploadTokenForm. - Drupal core
managed_fileowns file selection, AJAX transfer, validation, and temporary file entities. - Files are stored under
private://uploads/[token]/. - No custom synthetic mouse event or parallel direct-upload controller participates in the live product.
Public Upload Page Workflow
- The public page has no redundant generic Upload page title. Its identifying heading is Upload Files: [label].
- The secret token value is never displayed.
- Selecting files is the upload action. Drupal core managed_file immediately starts AJAX transfer from the file-input change event.
- Successful initial uploads become temporary Drupal managed files under private://uploads/[token]/.
- The final action is Finish submission.
- Skyhawk custom-form results never use Drupal messenger/status popups. Upload/finalization results render inline on the form using the established PageMessageTrait pattern required by Tier-1 Rule 8.3.
Token Lifecycle
- A token is valid when it exists, has status
active, and has not expired. - Generated tokens have a minimum lifetime of seven days.
- A token may be used for multiple upload sessions until expiry or explicit administrative revocation.
- A successful upload does not consume or invalidate the token.
uses_countrecords cumulative finalized files for administrative information only.uses_allowed = 0is retained as the unlimited-until-expiry/revocation sentinel for schema compatibility.
Upload Rules
- Multiple files may be selected.
- Maximum individual file size is 511 MiB (535,822,336 bytes).
- The hosting transport ceiling remains 512 MiB for an HTTP POST, so exceptionally large batches may need to be selected/uploaded separately even though each individual file is legal.
- After Drupal receives temporary managed files, final submission makes them permanent, records each file in
skyhawk_upload_file, increments cumulative file accounting, and sends the configured batch notification. - Completion notifications contain only the files finalized in that batch, not every historical file associated with the token.
Administration
- The admin form creates reusable tokens and sends the upload URL by email.
- The admin form can explicitly revoke an active token.
- Existing contact and purpose data are reused.
- The current history table remains operational; conversion to a Drupal View is a later Views-first improvement, not part of the uploader replacement.
Replacement State
The public and admin upload forms were replaced in toto after a discovery audit found contradictory one-use lifecycle logic, a redundant unrouted direct-upload controller, and a custom mobile workaround that duplicated Drupal core behavior.
The old UploadTokenController and upload_token_mobile_fix.js are retired into the timestamped replacement backup rather than destroyed during initial acceptance testing.
Functional acceptance remains pending until the Pixel test verifies: legal multi-file upload, final submission, private storage, history rows, notification, reuse of the same token, explicit revocation, expiry rejection, and oversize rejection.
Current Functional Failure
Generic initial upload: ACCEPTED. Drupal 11.4.5 core managed_file owns selection and AJAX transfer and successfully creates temporary managed-file entities under private://uploads/[token]/. Device testing has proven PNG, JPG, MP4, and HEIC samples. These formats are evidence samples only; file format is not a product restriction.
Closed branches: extension enumeration, MIME taxonomy, image-versus-video diagnosis, synthetic mouse events, custom serializer/queue transport, and a separate human Upload action are closed absent new contradictory evidence.
Public-page UX: the invitation is identified by Upload Files: [label]. The redundant generic Upload title is removed. Skyhawk custom-form results render inline through the established PageMessageTrait mechanism rather than Drupal messenger/status popups.
Current evidence boundary: initial generic managed_file transfer is proven and closed. Functional acceptance now proceeds downstream through Finish submission and verification of permanent-file state, private storage, skyhawk_upload_file history, cumulative accounting, configured batch notification, and reuse of the same token. Remaining lifecycle tests then cover explicit revocation, expiry rejection, and oversize rejection.
Current Regression Token
No token label is permanently reserved as the regression token. Use a currently active, unexpired test token from the existing token system. Do not create a replacement token merely because an upload test fails.