# Phase 1 & 2 Implementation Verification (2026-04-21) ## Scope implemented - Phase 1 infrastructure skeleton - Service container and plugin bootstrap wiring. - DB router with explicit members/mailshots database separation. - WordPress facade interfaces and production adapter. - Fixture harness (`tests/fixture/wp_shim.php`, `bootstrap.php`, `router.php`). - Structured error and logging primitives. - Phase 2 data source pipeline - DSL lexer/parser. - Semantic validator (source checks, filter-source rules, join-path validation, missing-email warning). - Parameterized SQL compiler. - Source metadata provider (built-ins + custom table metadata via information schema). - `mailshot_queries` repository and application service. - Data Sources admin page + API operations (`list`, `fields`, `validate`, `preview`, `save`, `delete`). ## Validation commands and outcomes 1. `find feca_mailshots_plugin/src tests -name '*.php' -print0 | xargs -0 -n1 php -l` - Result: pass (no syntax errors). 2. `php tests/unit/test_dsl_pipeline.php` - Result: pass. - Verifies parser/validator/compiler happy path and key invalid-path checks. 3. `php tests/unit/test_preview_shape.php` - Result: pass. - Verifies deterministic expected-field contract derivation. 4. `php tests/fixture/test_api_smoke.php` - Result: pass. - Verifies fixture bootstrap + WP shim + admin menu/page registration path. ## Notes - Fixture smoke test intentionally avoids remote DB calls in sandboxed execution. - API operations that execute SQL (`preview`, `list`, `save`, `delete`) require DB connectivity at runtime. ## Extended Phase 2 DB-access validation (2026-04-21) 5. `php tests/integration/test_phase2_db_access.php` - Result: pass. - Environment: tunnelled MySQL on `127.0.0.1:13306`. - Verified: - Live DB read-path preview via `MEMBERS_REMOTE_MYSQL_DB` (source discovered dynamically from `information_schema`). - Live DB write-path create/read/delete via `MAILSHOTS_REMOTE_MYSQL_DB.mailshot_queries`. - Test artefact cleanup confirmed (temporary data source row deleted in `finally`). ### Fix discovered by DB test - `mailshot_queries` repository insert SQL used unquoted `sql` column name, which fails on MySQL. - Fixed by quoting as `` `sql` `` in: - `feca_mailshots_plugin/src/Repository/MailshotQueryRepository.php` ## Phase 3 implementation and validation (2026-04-21) ### Implemented - Mailshot CRUD service/repository and admin API/page. - Attachment CRUD + binary file handling service/repository and admin API/page. - PDF asset CRUD + binary file handling service/repository and admin API/page. - Last-run repository operations (`listForMailshot`, `clearForMailshot`, `create`). - Token insertion helper generation from selected datasource expected fields. - Fixture user-test pages under `tests/fixture/`. - Fixture runner script `scripts/run_fixture_server.sh` (start/stop/status/restart). ### Validation 1. `php tests/integration/test_phase3_db_access.php` - Result: pass. - Verified end-to-end on tunnelled DB: - datasource creation for test, - attachment create/delete, - pdf asset create/delete, - mailshot create/delete with datasource validation, - token helper output generation, - last-run insert/list/clear behavior. - Cleanup: test artefacts removed in `finally` block. 2. `php tests/fixture/test_api_smoke.php` - Result: pass. - Verified fixture bootstrap and menu/page registration with shared plugin wiring. 3. `bash -n scripts/run_fixture_server.sh` - Result: pass. - Script shell syntax validated. ## Phase 4 implementation and validation (2026-04-21) ### Implemented - Twig template rendering pipeline service for `Subject`, `Message`, `PDFAttachment`. - SMTP sender abstraction with concrete SMTP client implementation. - IMAP sent-copy abstraction with concrete `imap_append` implementation. - Mail credentials provider backed by WordPress options (`feca_mailshots_mail_credentials`). - `MailshotRunService` with: - `renderTest` (no send), - `sendTest` (validation + SMTP + IMAP warning semantics), - `runMailshot` (clear last run + send loop + counters + per-recipient last_run rows), - `retryFailed`, - `retryRecipient`, - `MAILSHOT_TEST_TO_DEFAULT` default exposure. - Admin pages/endpoints added for: - Credentials, - Mailshot Test API, - Run Mailshot API. ### Validation 1. `php tests/integration/test_phase4_run_flow.php` - Result: pass. - Verified: - render-test behavior, - blank test-email validation, - test-send path through injected SMTP/IMAP transports, - run-mailshot counters and last-run row persistence, - retry-failed endpoint behavior. 2. Existing regression checks - `php tests/unit/test_dsl_pipeline.php` pass - `php tests/unit/test_preview_shape.php` pass - `php tests/fixture/test_api_smoke.php` pass - `php tests/integration/test_phase2_db_access.php` pass - `php tests/integration/test_phase3_db_access.php` pass ### Runtime fix included - Added Composer autoload loading in plugin autoload bootstrap so Twig/Dompdf classes resolve when vendor deps exist. ### Phase 4 UI completion (Mailshot Test + Run Mailshot) - Replaced placeholder pages with server-rendered WordPress admin UI for: - Mailshot selection, - Recipient selection/sample display, - `Render Test (No Send)` action, - `Send Test Email` action, - Run controls (`Run Mailshot`, `Retry Failed Sends`), - Last-run table with per-row `Retry` actions. - UI actions use admin-post handlers and persist most recent action result in option-backed result panes. - Added recipient-preview helper API in run service to support UI recipient picker. Validation: syntax + fixture smoke + phase4 integration test all pass after UI implementation. ## Change set: per-user encrypted credentials + access split + no-fallback runtime config (2026-04-21) ### Implemented 1. Per-user SMTP/IMAP credential storage in `MAILSHOTS_REMOTE_MYSQL_DB` - Added `mailshot_credentials` repository with table ensure/create and per-user upsert/load. - Password fields are stored encrypted (`smtp_password_enc`, `imap_password_enc`) using AES-256-CBC with key material derived from WordPress salts. 2. New Profile admin page for per-user credentials - Added `Profile` page under FECA Mailshots (editor-capable users). - Credentials are saved/loaded for the current user id. - Password inputs support blank-as-keep-existing behavior. 3. Runtime credential resolver switched to per-user DB-backed provider - Replaced global option-based provider with `PerUserMailCredentialsProvider`. - Run/test send paths now resolve credentials by current WordPress user. 4. Production DB config path made explicit (fallbacks removed) - Bootstrap now reads DB settings from Setup page option only. - No fallback chain to env vars in production bootstrap. - Fixture remains explicitly env-driven via `tests/fixture/bootstrap.php`. 5. Access control split - Setup page remains admin-only (`manage_options`). - Operational pages/APIs use editor-level capability (`edit_pages`): - Data Sources, Mailshots, Attachments, PDF Assets, - Profile, - Mailshot Test, - Run Mailshot. ### Validation - `php tests/fixture/test_api_smoke.php` pass - `php tests/integration/test_per_user_credentials.php` pass - `php tests/integration/test_phase4_run_flow.php` pass - syntax checks pass for updated files