Files
vidok.com/.paul/phases/01-contact-attachments/01-01-PLAN.md
2026-05-05 22:36:55 +02:00

9.1 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
phase plan type wave depends_on files_modified autonomous delegation
01-contact-attachments 01 execute 1
plugins/special-actions-middle.php
templates_user/pages/page-contact-v9.php
templates_user/modal/modal.php
true off
## Goal Persist uploaded files from contact forms as public attachment links in the same database row as the rest of the contact form data.

Purpose

Clients already attach project files to contact requests, but those files are only sent by email and currently use temporary storage. Sales/support should be able to recover submitted attachments from the database after the temp folder is cleaned.

Output

  • contact_messages.attachments column is created automatically when needed.
  • Uploaded contact files are stored in a dedicated public folder outside temp/.
  • saveContactData() stores attachment links in the new column.
  • The live contact page and modal communicate the allowed file types and 50 MB limit.
- **Zakres** - Obejmujemy formularze z plikami? -> Odpowiedz: Tyle te z plikami. - **Baza** - Zapisywac zalaczniki jako jedna kolumna czy osobna tabela? -> Odpowiedz: Jako jedna kolumna. - **Linki** - Publiczny link czy sciezka serwerowa? -> Odpowiedz: Publiczny link, ale dedykowanym folderze, nie temp bo ten jest czyszczony automatycznie. - **Limit** - Ograniczyc typy i rozmiar plikow? -> Odpowiedz: Ograniczmy. Limit dajmy na 50 MB, tylko musi byc o tym informacja w formularzach.

Project Context

@.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md @.paul/codebase/architecture.md @.paul/codebase/db_schema.md

Source Files

@plugins/special-actions-middle.php @templates_user/pages/page-contact-v9.php @templates_user/modal/modal.php @config.php

Current Findings

  • saveContactData() inserts into external table contact_messages using a direct PDO connection in plugins/special-actions-middle.php.
  • Contact form handlers already read $_FILES['files'], move uploads to temp/, and pass those temp paths to email sending.
  • The live contact template templates_user/pages/page-contact-v9.php contains file inputs for send-contact-form-new-2 and send-contact-form-new-deweloper.
  • The popup template templates_user/modal/modal.php contains file input for send-contact-modal.
  • File uploader JS currently uses fileMaxSize: 10; server validation only blocks .php.
  • .paul/SPECIAL-FLOWS.md is not present, so no specialized apply skills are required.

<acceptance_criteria>

Given a user submits a contact form with one or more valid files
When the form is accepted and saved by saveContactData()
Then each uploaded file is stored in a dedicated public contact attachments folder
And the matching contact_messages row contains public attachment links in one attachments column
And email delivery still receives the same uploaded files as attachments

AC-2: Automatic Database Upgrade

Given the production database does not yet have the attachments column
When the first contact submission is saved after deployment
Then the code automatically adds contact_messages.attachments without requiring a manual migration step
And the form save continues without losing the submission

AC-3: Upload Restrictions

Given a user uploads a disallowed extension or a file larger than 50 MB
When the form handler processes the submission
Then the invalid file is not persisted or emailed
And the user receives a normal form failure alert rather than a PHP warning or partial unsafe upload

AC-4: Form Limit Information

Given a user views the live contact form or modal contact form
When they reach the file upload field
Then the UI states the 50 MB per-file limit and allowed file types
And the client-side uploader enforces the same 50 MB limit as the server

</acceptance_criteria>

Task 1: Add attachment persistence helpers and schema self-upgrade plugins/special-actions-middle.php Add small helper functions near `saveContactData()`: - define allowed upload extensions for contact forms: `pdf`, `jpg`, `jpeg`, `png`, `doc`, `docx`, `xls`, `xlsx`, `csv`, `txt`, `xml`, `dwg`, `dxf`, `zip`; - define 50 MB per-file server limit; - normalize `$_FILES['files']` so both single and multiple upload shapes are handled; - save files under `uploads/contact-attachments/YYYY/mm/`, creating directories when missing; - generate collision-resistant file names using a random suffix and sanitized extension/name; - return both server paths for `\S::send_email()` and public URLs for database storage; - block invalid extension, failed upload status, non-uploaded temp files, and oversize files. Update `saveContactData()` to accept an optional `$attachments` argument, call an `ensureContactMessagesAttachmentsColumn(PDO $pdo)` helper before insert, and store `attachments` as JSON in one `TEXT NULL` column. Avoid storing files in `temp/` because it is automatically cleaned. php -l plugins/special-actions-middle.php AC-1, AC-2, and AC-3 satisfied for backend behavior. Task 2: Wire contact form handlers to persisted uploads plugins/special-actions-middle.php Replace duplicated upload loops for the forms that currently accept files with the new helper: - `send-contact-modal`; - `send-contact-form-new`; - `send-contact-form-new-2`; - `send-contact-form-new-deweloper`; - include `send-contact-landing` only if its current file input is intentionally part of the page/form scope during implementation. Pass returned server paths to existing `\S::send_email()` calls and returned public links to `saveContactData()`. Initialize `$files_to_send` safely before use so submissions without files do not create notices. If any uploaded file is invalid, stop the submission with the existing alert/redirect pattern and do not save partial contact data. Keep recipients, recaptcha behavior, and existing form validation unchanged. php -l plugins/special-actions-middle.php and code inspection showing every targeted saveContactData() call receives the attachment links argument. AC-1 and AC-3 satisfied for each in-scope form handler. Task 3: Update contact and modal upload UI limits templates_user/pages/page-contact-v9.php, templates_user/modal/modal.php Update the visible file upload copy in both files to mention: - maximum 50 MB per file; - allowed file types matching the server allowlist. Change fileuploader `fileMaxSize` from `10` to `50` in both templates. Ensure client-side `extensions` matches the backend allowlist and remove non-extension values such as `text/plain`. Keep existing layout, tracking scripts, form IDs, and recaptcha markup unchanged. php -l templates_user/pages/page-contact-v9.php; php -l templates_user/modal/modal.php AC-4 satisfied for the live contact page and popup modal contact form.

DO NOT CHANGE

  • Do not change database credentials, email recipients, recaptcha keys, tokens, or anti-spam word lists in this plan.
  • Do not refactor unrelated form handlers or admin panel code.
  • Do not move existing historical files out of temp/; only new uploads from targeted forms should use the dedicated folder.
  • Do not create a separate attachments table; the agreed schema is one column on contact_messages.

SCOPE LIMITS

  • This plan stores public links in the database; it does not build an admin UI for browsing/downloading them.
  • This plan does not retroactively recover attachments from previous submissions.
  • This plan targets the current contact page template and modal. Older unused contact template versions should only be changed if implementation proves they are still rendered in production.
Before declaring plan complete: - [ ] `php -l plugins/special-actions-middle.php` - [ ] `php -l templates_user/pages/page-contact-v9.php` - [ ] `php -l templates_user/modal/modal.php` - [ ] Inspect generated SQL path: missing `contact_messages.attachments` triggers one safe `ALTER TABLE`. - [ ] Inspect upload path: new files go to `uploads/contact-attachments/YYYY/mm/`, not `temp/`. - [ ] Inspect in-scope `saveContactData()` calls: attachment links are passed for file-enabled forms. - [ ] Confirm visible form copy and JS uploader limit say/enforce 50 MB.

<success_criteria>

  • All in-scope file-enabled forms keep sending emails with uploaded files.
  • Accepted uploaded files are retained outside temp/.
  • contact_messages.attachments is created automatically and populated with public links.
  • Server and client enforce matching file types and 50 MB per-file limit.
  • No unrelated files or PAUL-untracked user changes are reverted. </success_criteria>
After completion, create `.paul/phases/01-contact-attachments/01-01-SUMMARY.md`.