Skip to main content

Upload Token System

Upload Token System

Event Framework - Agreed First Consumer of Generic Intake

Status: Design frozen for first Reunion/BOD Meeting implementation.

Generic Intake remains the common transport and processing layer.
The first reusable consumer is an Event framework, initially proven
against Reunion and BOD Meeting workflows.

Bootstrap and Ownership

  • A token bootstraps creation of a specific Event workflow.
  • The token recipient is the initial responsible Event manager.
  • The manager is a Drupal member and Drupal account data is the
    authoritative identity/contact source.
  • Additional responsible managers may be added to the same Event.
    Separate tokens are preferred to sharing one token.
  • After management responsibility is established, normal Drupal
    authentication should become the ordinary management identity
    where practical.

Source-Document Workflow

  • The responsible member uploads a PDF or DOC containing the
    announcement/update source.
  • The system extracts proposed structured facts and preserves
    appropriate narrative/update material.
  • The manager verifies the proposed result before acceptance.
  • The manager may correct extracted values inline, replace the
    source document, or escalate to webmaster review.
  • Replacing a source updates/reconciles the Event entities already
    owned by the bootstrap request. It must not create duplicate Event
    pages.
  • Stable Event facts and dated narrative updates are separate.
  • Newer source documents may supersede prior structured facts while
    prior source/update history remains associated with the same Event.

2026 A-4 Skyhawk Reunion Acceptance Corpus

  1. July 2026 Newsletter: bootstrap source. It must
    create the Event.
  2. August 2026 Newsletter: update/reconciliation
    source. It must update the same Event and identify meaningful
    changes without duplicate nodes.
  3. September 2026 Newsletter: final current
    pre-event source. It must reconcile the same Event to the current
    state while preserving July and August as prior updates.

The September result should be equivalent in current Event facts
to a correct direct September creation, while retaining the prior
source/update history produced by July and August.

Event Lifecycle

  • One Event identity persists through pre-event, live-event, and
    post-event use.
  • Dates and deadlines should drive phase/status automatically where
    practical, with an authorized override when real life differs.
  • Hotel, registration, travel/flight, transportation and discount
    information may include links, discount codes/rates, booking or
    registration cutoff dates, and other actionable deadlines.
  • Responsible managers receive reasonable deadline/staleness
    nudges so they can review the Event page and send updates.
  • Send Update means a Drupal-mediated reminder to the responsible
    manager, not a broadcast to members.

Members-Only Event Participation

  • Reunion and BOD Meeting Event/photo destinations may be
    members-only according to template policy.
  • Anonymous visitors receive a friendly explanation and login/join
    path instead of relying on generic Drupal access-denied messaging.
  • A valid bootstrap/intake token may authorize contribution without
    granting access to otherwise restricted destination content.
  • Once the Event exists, authenticated members may contribute
    photos directly without another upload token where policy permits.

Photo Batches and Comments

  • A photo upload creates a batch associated with the Event and the
    authenticated member UID.
  • Displayed contributor identity uses callsign when available,
    otherwise first name, while authoritative provenance retains UID
    and appropriate internal identity data.
  • Each batch has one group heading/comment displayed with the
    thumbnail collection.
  • Individual photo comments/names are optional and belong primarily
    with the enlarged/full-photo presentation rather than cluttering
    the thumbnail grid.
  • The photo contributor moderates comments submitted against their
    photos/batch.
  • Pending commenters are told that moderation is pending.
  • Pending comments have a maximum 30-day moderation period with
    reasonable reminder nudges. If no action occurs by day 30, the
    comment publishes automatically.
  • Authorized staff retain exceptional moderation authority.

ZIP Photo Transport

  • ZIP is a transport container, not a gallery object.
  • Supported photographs are safely extracted and become normal
    Drupal-managed photo/media assets.
  • Thumbnail and full-size display use normal Drupal image/media
    facilities and Views.
  • The ZIP is deleted after extraction, file-count/reconciliation,
    destination association, and usable photo display are positively
    verified.
  • The individual extracted photographs are the durable assets
    unless a particular future intake policy explicitly requires
    archival preservation of the original ZIP.

BOD Meeting Parity

The current Board/leadership page is outside this work. The Event
framework applies to pre/live/post BOD Meeting announcement and
history pages: source documents, Event facts, links, documents,
member photos, batches and comments use the same common framework
with BOD-specific labels/policy rather than a separate uploader.

User-Facing Messaging

Success, information and error/action-required messages remain
inline, subdued and aesthetically integrated, but positioned and
styled so that a user is unlikely to miss required action. Generic
Drupal messenger popups are not the target UX for these custom
member-facing workflows.

CURRENT STATE - GENERIC INTAKE SYSTEM

Project: Generic Intake System

Status: In development

Ultimate goal: A self-service, reusable, aesthetically integrated intake framework that lets authorized nontechnical Ready Room users create purpose-specific public file requests without webmaster assistance. The underlying upload engine remains generic for future uses.

Current accepted functionality:

  • Drupal core managed_file owns automatic initial file transfer.
  • Generic file acceptance is proven. Format-specific diagnosis is closed absent contradictory evidence.
  • Token-specific private storage under private://uploads/[token]/ is proven.
  • Finish submission and permanent-file finalization are proven.
  • Reusable token behavior is proven.
  • The current Pixel/Chrome public upload presentation is accepted.
  • The redundant generic Upload title is closed work.
  • Public Drupal status-popup behavior was corrected toward the established inline PageMessage pattern.

Accepted request/invitation gate: real Ready Room testing proved explicit recipient routing, request-data persistence, the canonical https://skyhawk.org/upload/{token} invitation, the same stored request instructions in the actual email and public upload page, and on-page Ready Room request confirmation. Accepted by Report-ID 20260830T161100Z-2299062. Current implementation slice: prove the shared Event framework with the real 2026 A-4 Skyhawk Reunion corpus. JULY creates exactly one Event; AUGUST reconciles that same Event; SEPTEMBER reconciles the same Event to the current pre-event state while preserving prior updates. No duplicate Event nodes.

Next implementation principle: preserve the proven uploader/finalization engine and evolve the surrounding request-management system. Do not rewrite the working upload path merely to implement the broader framework.

Closed work: extension and MIME enumeration, image-versus-video diagnosis, synthetic upload triggering, custom serializer/queue transfer experiments, generic Upload page title, and repeated reproving of accepted core transfer/finalization behavior.

Reopen closed work only when: new contradictory functional evidence demonstrates that the accepted behavior is no longer true.

Current Agreed Product Decisions

  • The Ready Room menu links directly to an Upload Requests dashboard. Individual public requests do not become menu entries.
  • Granular Drupal permissions, assigned to roles, govern creation, management, reassignment, lifecycle actions, viewing submissions, and permanent deletion.
  • Request-specific instructions are entered once and dynamically reused in both the invitation email and public upload page. The live page is authoritative when instructions change.
  • The underlying uploader remains format-agnostic even when a request expects ZIP files, photographs, video, documents, or other material.
  • Public size language uses industry-standard decimal MB where 1 MB equals 1,000,000 bytes, plus the exact comma-separated byte count where useful.
  • The configured limit is per individual file, not the aggregate of multiple files in a submission.
  • Large collections are split among multiple files or ZIP archives rather than reducing original photo or video quality merely to fit a limit.
  • Removal before Finish submission is required. Each file gets a clear individual Remove action rather than Drupal selection checkboxes.
  • The pre-finish manifest shows filename, MB, exact bytes, status, and Remove, plus file count and aggregate size.
  • Resumable transfer is desirable for large files if a maintained Drupal-compatible solution can provide it simply. Do not build a custom resumable-upload platform.
  • SA controls stored/internal filenames for sortable, collision-resistant recovery. Original contributor filenames remain preserved as metadata. Database fields, not filename parsing, remain authoritative for Views.
  • Each request has an immutable human-friendly ID and each Finish submission has a batch identity.
  • Useful provenance is retained, including original/generated filename, request, batch, known source/contributor information, timestamps, size, and relevant supplied metadata.
  • Exact duplicate hashes may be retained for integrity and later duplicate identification, but exact duplicates are not automatically rejected because provenance can differ.
  • The responsible party determines the intended disposition of each request. Receipt and automatic publication are separate concepts.
  • Original files are preserved by default, while storage and retention policy may be revisited if storage becomes a material constraint.
  • ZIP preservation or extraction depends on purpose, permissions, and downstream workflow rather than one universal rule.
  • Copyright remains with whoever legally owns it. Upload does not itself transfer copyright to SA.
  • Contributors should represent, to the best of their knowledge, that they are entitled to provide the material and are not knowingly violating another persons rights.
  • Applicable photo policy grants SA appropriate continuing non-exclusive permission to preserve, reproduce, migrate or convert, adapt for presentation, publish, and use contributed material in Association activities and publications.
  • SA remains the sole arbiter of whether and under what conditions photographs administered or distributed through the SA website are provided or authorized for third-party use, without claiming copyright SA does not own.
  • Known photographer/source and SA credit may both be used publicly as appropriate, while full provenance remains preserved internally.
  • The upload system does not ask contributors to manage future contact requests. SA may forward a legitimate contact request to the known owner/source. The requester is told that no response within the defined period means no permission or contact. Silence is never consent.
  • Photo-oriented requests may support both a batch description and optional per-photo descriptions plus other appropriate configurable metadata.
  • The exact applicable rights/agreement version, request, batch, and acceptance time are retained.
  • The existing photo-contribution workflow is superseded only after the generic framework proves equivalent or better required functionality.
  • Successful submission normally produces one internal summary per completed batch.
  • Requests may generate up to two sensible expiration reminders, but any successful submission cancels outstanding reminder prompting for that request.
  • The system does not automatically nag the contributor. The creator can resend the active request and current dynamically generated instructions.
  • Successful received material is not automatically deleted. Truly abandoned temporary material may be cleaned up conservatively under documented policy.
  • Arbitrary contributed files are treated as untrusted until appropriately reviewed or scanned. Prefer a simple maintained scanning mechanism rather than custom antivirus infrastructure.
  • Desktop, tablet, and mobile are supported where practical. Device parity must not make important functionality unreasonably complex or impossible.
  • After Finish submission, show a meaningful receipt before offering Upload another batch while the request remains active.
  • Errors remain inline and explain what happened, why, and what the contributor should do. Successfully transferred files are not needlessly retransmitted because another file failed.
  • KISS governs implementation.

Implementation order: request data model and Ready Room dashboard; shared instructions and email workflow; public manifest/removal/size/receipt/error UX; naming/batch/history/accounting/provenance/hash; permissions/expiration/reminders/lifecycle; then evaluate maintained resumable upload and malware scanning; replace photo-contribute only after parity is proven.

Deterministic AI instruction: routine work on this project must begin by rereading the ACTIVE RULES block and this CURRENT STATE block. Deeper historical or diagnostic material is supporting evidence and must not override current accepted truth unless new evidence changes that truth.

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_file owns 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_count records cumulative finalized files for administrative information only.
  • uses_allowed = 0 is 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 selection and automatic AJAX transfer to token-scoped private storage are proven. File-format diagnosis is closed.

Finish submission permanent-file transition: ACCEPTED. Direct Pixel testing proved selection, automatic upload, Finish submission, permanent managed-file state in private://uploads/[token]/, and reset of the form for another batch.

Public upload-page UX: ACCEPTED on Pixel/Chrome. The redundant generic Upload title is absent. Upload Files: [label] remains as the identifying heading. The repaired public-page presentation has passed direct browser inspection. This branch is closed absent contradictory evidence.

Current acceptance boundary: upload history. The first remaining unproven transition is whether Finish submission creates the required skyhawk_upload_file history row for each finalized file. Do not reopen generic upload, permanent-file finalization, or the accepted Pixel UX while resolving history.

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.