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 State
Generic initial upload: ACCEPTED. Drupal core managed_file owns selection and AJAX transfer. Format-blind token-scoped private upload has been proven with PNG, JPG, MP4, and HEIC samples. These are evidence samples only and are not a format restriction.
Finish submission permanent-file transition: ACCEPTED. The latest Pixel test uploaded an MP4, Finish submission completed, the form reset for another batch, and the resulting managed-file entity is permanent and exists in token-scoped private storage. The same C5 token remains active and its cumulative uses_count is 3.
Public-page UX correction: the live route-level generic Upload title and the UploadTokenForm Drupal messenger calls were positively identified as the owners of the browser-visible defects and corrected at those owners. The useful page heading remains Upload Files: [label]. Public-form results use the established PageMessageTrait inline mechanism.
Closed work: generic upload transport, format filtering, temporary-to-permanent finalization, and the two corrected public-page UX ownership defects are closed absent contradictory functional evidence.
Current acceptance boundary: continue linearly with the first remaining unproven downstream requirement. The history table currently requires specific verification because the latest audit returned no history rows. After history/accounting are resolved, continue with configured notification, token reuse as a separate functional test if still required, 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.