From 5f23ca9482e69a1b04accf92fcfa013a69c213c5 Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Mon, 27 Apr 2026 17:57:19 +0200 Subject: [PATCH] =?UTF-8?q?docs(codebase):=20add=20codebase=20map=20?= =?UTF-8?q?=E2=80=94=20stack,=20architecture,=20structure,=20schema,=20con?= =?UTF-8?q?ventions,=20testing,=20integrations,=20concerns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .paul/codebase/architecture.md | 140 +++++++++++++++++++++++++++++++ .paul/codebase/concerns.md | 132 ++++++++++++++++++++++++++++++ .paul/codebase/conventions.md | 136 +++++++++++++++++++++++++++++++ .paul/codebase/db_schema.md | 123 ++++++++++++++++++++++++++++ .paul/codebase/integrations.md | 87 ++++++++++++++++++++ .paul/codebase/stack.md | 74 +++++++++++++++++ .paul/codebase/structure.md | 145 +++++++++++++++++++++++++++++++++ .paul/codebase/testing.md | 66 +++++++++++++++ 8 files changed, 903 insertions(+) create mode 100644 .paul/codebase/architecture.md create mode 100644 .paul/codebase/concerns.md create mode 100644 .paul/codebase/conventions.md create mode 100644 .paul/codebase/db_schema.md create mode 100644 .paul/codebase/integrations.md create mode 100644 .paul/codebase/stack.md create mode 100644 .paul/codebase/structure.md create mode 100644 .paul/codebase/testing.md diff --git a/.paul/codebase/architecture.md b/.paul/codebase/architecture.md new file mode 100644 index 0000000..d83a1e9 --- /dev/null +++ b/.paul/codebase/architecture.md @@ -0,0 +1,140 @@ +# Architecture + +**Analysis Date:** 2026-04-27 + +## Pattern Overview + +**Overall:** Custom PHP MVC Monolith (dual frontend — public + admin) + +**Key Characteristics:** +- Single shared `core/` layer powering both public and admin frontends +- Front Controller routing via Apache rewrite → `index.php` → Router → Controller +- All templating via Smarty (no JSON API, no SPA) +- Session-based admin auth; anonymous public form with reCAPTCHA + +## Layers + +**Router / Front Controller:** +- Purpose: Parse URL, select controller and action +- Contains: `Router.class.php`, `index.php` entry points +- Location: `_rejestracja/index.php`, `_rejestracja/Admin/index.php` +- Depends on: Core class loader +- Used by: Nothing (entry point) + +**Controller Layer:** +- Purpose: Handle request lifecycle — auth, business logic dispatch, template assignment +- Contains: `*Controller.php` files; each has `preDispatch`, `{Name}Action`, `postDispatch` +- Location: `_rejestracja/controller/` (public), `_rejestracja/Admin/controller/` +- Depends on: DAL layer, Smarty, SessionProxy, Request +- Used by: Router + +**DAL Layer (Data Access):** +- Purpose: Typed database access; maps rows to model objects +- Contains: `Mf{Entity}DAL.class.php` files, `DefaultDAL.class.php` base +- Location: `_rejestracja/core/model/` +- Depends on: MySQL connection, `DalData` query config objects, `DataObject` base model +- Used by: Controllers + +**Model Layer:** +- Purpose: Typed domain objects with getters/setters +- Contains: `Mf{Entity}.class.php` with `$fields` array mapping DB columns to properties +- Location: `_rejestracja/core/model/` +- Depends on: `DataObject.class.php` base +- Used by: DAL (hydration), Controllers, Templates (via Smarty assigns) + +**Template Layer:** +- Purpose: HTML rendering via Smarty +- Contains: `.tpl` files, Smarty plugins (`{translate}`, `{formField}`, `{url}`, `{dropDownContainer}`) +- Location: `_rejestracja/template/`, `_rejestracja/Admin/template/` +- Depends on: Variables assigned in controller (`$this->smarty->assign(...)`) +- Used by: Nothing (output layer) + +## Data Flow + +**Public Registration Request:** + +1. Browser `POST /_rejestracja/index` → Apache rewrite → `_rejestracja/index.php` +2. `Router` parses URL → selects `IndexController` +3. `IndexController::preDispatch()` sets up shared context (Smarty, layout) +4. `IndexController::IndexAction()` runs: + - Validates reCAPTCHA + - Reads POST via `Request::GetPost()` + - Hydrates `MfParticipant` model + - Calls `MfParticipantDAL::Save($obj)` → INSERT/UPDATE + - Sends confirmation email via PHPMailer + - `$this->smarty->assign(...)` + Smarty renders confirmation template +5. HTML response returned to browser + +**Admin Registration List Request:** + +1. Browser `GET /_rejestracja/Admin/Calc/Reg` → `Admin/index.php` → Router +2. `CalcController::preDispatch()` — calls `RunShared('Auth', $param)` (session check) +3. `CalcController::RegAction()`: + - `MfParticipantDAL::GetResult($dalData)` with sort DESC + - `$this->smarty->assign('arrayObj', $arrayObjReg)` +4. Smarty renders `Admin/template/partial/Calc/Reg.tpl` + +**State Management:** +- PHP sessions via `SessionProxy` for admin auth and transient UI state +- No in-memory cache; every request hits MySQL + +## Key Abstractions + +**DataObject / Model:** +- Purpose: Typed domain objects with `$fields` array auto-mapping DB↔PHP +- Examples: `MfParticipant`, `MfParameters`, `MfDictionary` +- Pattern: Active-record-lite; `$fields = ['db_col' => 'PropName']`, auto-generates getters/setters via `__get`/`__set` or explicit methods + +**DefaultDAL / DalData:** +- Purpose: Generic CRUD over MySQL; `DalData` is a query config object (conditions, sort, limit) +- Examples: `MfParticipantDAL`, `MfParametersDAL`, `MfDictionaryDAL` +- Pattern: `GetDalDataObj()` → configure → `GetResult()` / `GetById()` / `Save()` / `Delete()` + +**Smarty Plugin Suite:** +- Purpose: Template-level abstractions for common patterns +- Key plugins: `{translate word='key'}` (dictionary lookup), `{formField name="" type=""}` (form inputs — text/hidden only), `{url label=X}` (router-aware URL generation), `{dropDownContainer}` (collapsible admin sections) +- Pattern: Custom Smarty plugins registered in `_rejestracja/core/` + +## Entry Points + +**Public Frontend:** +- Location: `_rejestracja/index.php` +- Triggers: HTTP request to `/_rejestracja/` +- Responsibilities: Bootstrap core, invoke Router → Controller + +**Admin Frontend:** +- Location: `_rejestracja/Admin/index.php` +- Triggers: HTTP request to `/_rejestracja/Admin/` +- Responsibilities: Same bootstrap + admin-specific auth via `RunShared('Auth')` + +## Error Handling + +**Strategy:** Mostly unhandled — exceptions catch in isolated blocks, errors logged to PHP error_log + +**Patterns:** +- `try/catch` in `RegDeleteAction` (DAL delete errors logged but swallowed) +- `Validator` class collects field errors and returns them to template via `$out` array +- No global exception handler observed + +## Cross-Cutting Concerns + +**Logging:** +- PHP `error_log` only; `Utils::ArrayDisplay()` for dev debug (should be removed pre-deploy) + +**Validation:** +- `Validator` class at controller level for required-field checks +- reCAPTCHA for bot protection on public form +- No input sanitization layer beyond Smarty auto-escaping in templates + +**Authentication:** +- Admin: `RunShared('Auth', $param)` in every admin controller `preDispatch` +- Public: None (anonymous registration form) + +**Internationalization:** +- `{translate word='key'}` Smarty plugin reads from `mf_dictionary` table +- All visible strings for the registration form are dictionary-backed + +--- + +*Architecture analysis: 2026-04-27* +*Update when major patterns change* diff --git a/.paul/codebase/concerns.md b/.paul/codebase/concerns.md new file mode 100644 index 0000000..c60340f --- /dev/null +++ b/.paul/codebase/concerns.md @@ -0,0 +1,132 @@ +# Codebase Concerns + +**Analysis Date:** 2026-04-27 + +## Security Considerations + +**Credentials committed to repository:** +- Risk: DB credentials and SMTP credentials checked into version control +- Files: `_rejestracja/core/config/db.config.ini`, `_rejestracja/core/config/smtp.config.ini` +- Current mitigation: None — production secrets in plaintext in repo +- Recommendations: Move to gitignored config files; add `.gitignore` entry; rotate credentials if repo is/was public + +**Web-accessible migration runners:** +- Risk: Anyone who knows the URL can trigger `ALTER TABLE` operations on production DB +- Files: `_rejestracja/sql/apply-*.php` (all runner files) +- Current mitigation: Requires `?run=YYYYMMDD` param to prevent accidental execution +- Recommendations: Move runners outside web root, or add IP/auth check before execution + +**`eval()` usage in core:** +- Risk: Remote code execution if user input reaches eval +- Files: Detected in `_rejestracja/core/class/` (exact file TBD — needs verification) +- Current mitigation: Unknown — depends on what is eval'd +- Recommendations: Audit eval usage; replace with explicit logic where possible + +**No input sanitization layer:** +- Risk: SQL injection if user input bypasses DAL parameterization; XSS if template escaping is skipped +- Files: `_rejestracja/controller/IndexController.php` — uses `Request::GetPost()` directly +- Current mitigation: Smarty auto-escaping in templates; DAL may use parameterized queries (verify) +- Recommendations: Audit DAL for raw query concatenation; confirm all template output uses `|escape` + +## Tech Debt + +**`core/_model/` directory duplication:** +- Issue: 78 files in `_rejestracja/core/_model/` mirror `_rejestracja/core/model/` but are NOT loaded by the autoloader +- Files: All files in `_rejestracja/core/_model/` +- Why: Historical backup that was never deleted +- Impact: Confusing when navigating; edits to `_model/` are silently ignored; risk of editing wrong file +- Fix approach: Delete `_rejestracja/core/_model/` entirely — it serves no runtime purpose + +**Commented-out debug calls throughout controllers:** +- Issue: `//Utils::ArrayDisplay(Request::GetAllPost());` and similar calls left in code +- Files: `_rejestracja/Admin/controller/CalcController.php` (lines 54, 118), others +- Why: Dev debugging not cleaned up +- Impact: Clutter; risk of accidentally uncommenting in production +- Fix approach: Remove all commented-out debug calls during any refactor pass + +**`TODO` about disc field in IndexController:** +- Issue: Unresolved logic around the `disc` field in fee calculation +- Files: `_rejestracja/controller/IndexController.php` +- Why: Deferred during earlier development +- Impact: Potentially incorrect discount pricing in edge cases +- Fix approach: Review `disc` field handling; either implement or document the intended behavior + +**`setSortBy()` raw string injection:** +- Issue: `DalData::setSortBy()` injects value directly into `ORDER BY` SQL clause with no escaping +- Files: `_rejestracja/core/class/DefaultDAL.class.php`, all callers +- Why: Design choice for simplicity +- Impact: SQL injection risk if sort value ever comes from user input (currently hardcoded — low risk) +- Fix approach: Whitelist allowed sort columns; never pass user input to `setSortBy()` + +## Fragile Areas + +**`core/core.php` autoloader:** +- Files: `_rejestracja/core/core.php` +- Why fragile: `spl_autoload_register` loads from `core/model/` — if class naming deviates from `Mf{Entity}.class.php` convention, autoload silently fails +- Common failures: Editing `core/_model/` instead of `core/model/` (no error, just stale behavior) +- Safe modification: Always verify you're editing `core/model/` not `core/_model/` + +**`$fields` array in model classes:** +- Files: All `_rejestracja/core/model/Mf*.class.php` +- Why fragile: `$fields` array must exactly match DB column names; mismatch means property reads `null` silently +- Common failures: Adding a DB column without updating `$fields`; typo in column name +- Safe modification: After adding to `$fields`, verify getter returns expected value from DB + +**Smarty template variable assignment:** +- Files: All `_rejestracja/template/` and `_rejestracja/Admin/template/` `.tpl` files +- Why fragile: If controller doesn't `assign()` a variable, Smarty silently outputs empty string — no error +- Common failures: Renaming a controller variable without updating template references +- Safe modification: Search for the variable name in both controller and all related templates before renaming + +## Known Bugs + +**`RegDeleteAction` deletes wrong record:** +- Symptoms: `CalcController::RegDeleteAction` calls `MfParametersDAL::Delete($dalData)` instead of `MfParticipantDAL::Delete($dalData)` — DAL class mismatch +- Files: `_rejestracja/Admin/controller/CalcController.php` lines 187–206 +- Workaround: Unknown — may delete a pricing parameter row instead of the participant +- Root cause: Copy-paste error in controller method; wrong DAL class referenced + +## Performance Bottlenecks + +**No query caching:** +- Problem: Every request hits MySQL — `mf_dictionary` is read on every page load for every `{translate}` call +- Files: `_rejestracja/core/model/MfDictionaryDAL.class.php`, all templates using `{translate}` +- Cause: No caching layer; MySQL query per translation key +- Improvement path: Cache dictionary in PHP session or static array per request + +**No pagination on admin registration list:** +- Problem: `CalcController::RegAction` loads all `mf_participant` rows into memory with no LIMIT +- Files: `_rejestracja/Admin/controller/CalcController.php` (RegAction), `_rejestracja/Admin/template/partial/Calc/Reg.tpl` +- Cause: `DalData` has no pagination set; template has commented-out pager HTML +- Impact: Will degrade significantly as registration count grows past a few hundred rows + +## Dependencies at Risk + +**PHP 5.x:** +- Risk: PHP 5.x is end-of-life since December 2018; no security patches +- Impact: Known PHP 5.x vulnerabilities unpatched on production server +- Migration plan: Requires testing all code for PHP 7.x/8.x compatibility (significant effort) + +**jQuery 1.x:** +- Risk: jQuery 1.x is unmaintained; known XSS vulnerabilities in older versions +- Impact: Frontend JS security issues +- Migration plan: Upgrade to jQuery 3.x or replace with vanilla JS + +**Bundled Smarty / PHPMailer:** +- Risk: Vendor-bundled libraries in `core/lib/` may be outdated versions with unpatched CVEs +- Impact: Template injection (Smarty), email header injection (PHPMailer) +- Migration plan: Replace with Composer-managed dependencies and current versions + +## Test Coverage Gaps + +**Everything — no tests exist:** +- What's not tested: All application logic +- Files: All of `_rejestracja/` +- Risk: Any code change could introduce silent regressions; verified by manual testing only +- Priority: High for `IndexController.php` (primary user-facing flow) and `DefaultDAL.class.php` (affects all DB operations) +- Difficulty to test: Medium — PHP 5.x compatible test framework required; DAL tests need DB fixture + +--- + +*Concerns audit: 2026-04-27* +*Update as issues are fixed or new ones discovered* diff --git a/.paul/codebase/conventions.md b/.paul/codebase/conventions.md new file mode 100644 index 0000000..1f94ef6 --- /dev/null +++ b/.paul/codebase/conventions.md @@ -0,0 +1,136 @@ +# Coding Conventions + +**Analysis Date:** 2026-04-27 + +## Naming Patterns + +**Files:** +- `Mf{Entity}.class.php` — model classes (e.g., `MfParticipant.class.php`) +- `Mf{Entity}DAL.class.php` — data access classes (e.g., `MfParticipantDAL.class.php`) +- `{Name}Controller.php` — controller classes (e.g., `IndexController.php`, `CalcController.php`) +- `{Name}.tpl` — Smarty template files (e.g., `Index.tpl`, `Reg.tpl`) + +**Classes:** +- PascalCase for all classes: `MfParticipant`, `IndexController`, `DefaultDAL` +- `Mf` prefix for domain model/DAL classes (short for "mediaflex") + +**Methods:** +- PascalCase for public methods: `GetById()`, `GetResult()`, `GetName()`, `SetStatus()` +- camelCase for getters/setters in newer models: `getAdditionalInfo()`, `setAdditionalInfo()` +- `{Name}Action` suffix for controller action methods: `IndexAction`, `RegAction`, `RegEditAction` + +**Variables:** +- camelCase for local variables: `$objParticipant`, `$arrayObjReg`, `$dalData` +- `$array*` prefix for arrays: `$arrayObj`, `$arrayFee`, `$arrayObjParameters` +- `$obj*` prefix for single model instances: `$objParam`, `$objParameters` + +**DB Columns:** +- `snake_case` in database: `id_mf_participant`, `date_add`, `additional_info` +- Mapped to camelCase properties via `$fields` array in model + +## Code Style + +**Formatting:** +- Tabs for indentation (not spaces) +- No enforced line length +- No Prettier/PHP-CS-Fixer — manual formatting +- PHP opening tag `` present in all files + +**Linting:** +- No configured linter +- No static analysis tools + +## Model Field Mapping Pattern + +The `$fields` static array in each model class maps DB column names to property names: + +```php +static $fields = array( + 'id_mf_participant' => 'Id', + 'name' => 'Name', + 'nip' => 'Nip', + 'additional_info' => 'additionalInfo', +); +``` + +Getters/setters follow `get{PropertyName}()` / `set{PropertyName}()` convention. + +## Template Conventions (Smarty) + +**Always use these Smarty plugins — do not inline PHP:** +- `{translate word='key'}` — all visible text strings (reads from `mf_dictionary` table) +- `{url label=X}` or `{url Calc=Y id=$id}` — all URL generation (never hardcode paths) +- `{formField name="x" type="text"}` — text/hidden inputs only; does NOT support textarea +- `{dropDownContainer title='...'}` — admin collapsible sections + +**Textarea limitation:** +- `{formField}` Smarty plugin only supports `type="text"` and `type="hidden"` +- Multi-line fields require raw ` +``` + +**Template structure:** +- Public templates: `_rejestracja/template/partial/Index/{Name}.tpl` +- Admin templates: `_rejestracja/Admin/template/partial/{Controller}/{Name}.tpl` +- Smarty `assign`: done in controller via `$this->smarty->assign('key', $value)` + +## Controller Pattern + +Every controller has three methods: + +```php +public function preDispatch($param) { + $this->RunShared('Auth', $param); // admin only + $this->Run($param); + $this->smarty->assign('titleAdmin', '...'); + // nav structure setup +} + +public function {Name}Action($param) { + // business logic + smarty assigns +} + +public function postDispatch($param) { + // usually empty +} +``` + +## DAL Usage Pattern + +```php +$dalData = Mf{Entity}DAL::GetDalDataObj(); +$dalData->addCondition('column_name', $value); +$dalData->setSortBy('column_name DESC'); // DESC must be in the string +$results = Mf{Entity}DAL::GetResult($dalData); +$single = Mf{Entity}DAL::GetById($id); +Mf{Entity}DAL::Save($obj); +``` + +## Migration Runner Pattern + +```php +// Check before altering (idempotent) +$check = $conn->query("SELECT ... FROM INFORMATION_SCHEMA.COLUMNS WHERE ..."); +if ($check->num_rows > 0) { + echo "already exists — skipped"; + exit; +} +$conn->query("ALTER TABLE `table` ADD COLUMN `col` TEXT NULL DEFAULT NULL AFTER `other_col`"); +echo "success"; +``` + +Runner files require `?run=YYYYMMDD` param to prevent accidental execution. + +## Comments + +- Minimal comments in existing code +- `//Utils::ArrayDisplay()` debug calls left commented — remove before deploy +- PHPDoc-style block headers on controller classes (legacy format, not enforced) +- `TODO` comments used sparingly: `// TODO: consider disc field logic` + +--- + +*Convention analysis: 2026-04-27* +*Update when patterns change* diff --git a/.paul/codebase/db_schema.md b/.paul/codebase/db_schema.md new file mode 100644 index 0000000..92ab4d9 --- /dev/null +++ b/.paul/codebase/db_schema.md @@ -0,0 +1,123 @@ +# Database Schema + +**Analysis Date:** 2026-04-27 + +## Overview + +MySQL database on mysql7.ceti.pl. Custom DAL layer; no ORM. All migrations are manual SQL files with idempotent PHP runners in `_rejestracja/sql/`. + +## Core Tables + +### `mf_participant` + +Primary registration table. One row per conference registrant. + +| Column | Type | Notes | +|--------|------|-------| +| `id_mf_participant` | INT PK AUTO_INCREMENT | Primary key | +| `name` | VARCHAR | First name | +| `surname` | VARCHAR | Last name | +| `degree` | VARCHAR | Academic title/degree | +| `position` | VARCHAR | Job position | +| `phone` | VARCHAR | Phone number | +| `fax` | VARCHAR | Fax number | +| `email` | VARCHAR | Email address | +| `institution` | VARCHAR | Institution name | +| `address` | VARCHAR | Street address | +| `post_code` | VARCHAR | Postal code | +| `city` | VARCHAR | City | +| `nip` | VARCHAR | Tax ID (NIP) | +| `additional_info` | TEXT NULL | Free-text notes — added 2026-04-27 | +| `referat` | TINYINT | Presentation flag (0/1/2) | +| `poster` | TINYINT | Poster flag (0/1/2) | +| `message` | TEXT | Presentation topic | +| `autor` | VARCHAR | Co-authors | +| `participation_option` | VARCHAR | `full` / `one_day_lodging` / `one_day_no_lodging` | +| `participation_days` | VARCHAR | Selected days (for one-day option) | +| `diet` | TINYINT | Dietary preference (1=standard, 2=special) | +| `diet_special` | VARCHAR | Special diet description | +| `fee_full` | TEXT | Serialized fee selection array | +| `fee_one_day` | VARCHAR | One-day fee value | +| `price` | DECIMAL | Calculated total price | +| `agree1` | TINYINT | Data processing consent | +| `agree2` | TINYINT | Image consent | +| `status` | TINYINT | Payment status (1=no, 2=yes) | +| `location` | TINYINT | Conference location (1=aktualia, 2=PAN) | +| `date_add` | DATETIME | Registration timestamp | + +**Model:** `_rejestracja/core/model/MfParticipant.class.php` +**DAL:** `_rejestracja/core/model/MfParticipantDAL.class.php` + +### `mf_parameters` + +Pricing/fee configuration. Each row is a fee option (accommodation, conference fee, etc.). + +| Column | Type | Notes | +|--------|------|-------| +| `id_mf_parameters` | INT PK | Primary key | +| `name` | VARCHAR | Display name | +| `opis` | TEXT | Description | +| `price` | DECIMAL | Regular price (net) | +| `price_prom` | DECIMAL | Promotional/discount price | +| `price_progres` | TINYINT | Progressive pricing flag | +| `count_progres` | INT | Progressive pricing count threshold | +| `unit` | VARCHAR | Unit label | +| `link_id` | INT | Grouping link ID | +| `type` | TINYINT | Parameter type category | +| `sort` | INT | Display order | +| `publication` | TINYINT | Published/active flag | + +**Model:** `_rejestracja/core/model/MfParameters.class.php` +**DAL:** `_rejestracja/core/model/MfParametersDAL.class.php` + +### `mf_dictionary` + +Key-value store for all translatable/editable text strings visible in the UI. + +| Column | Type | Notes | +|--------|------|-------| +| `id_mf_dictionary` | INT PK | Primary key | +| `keyword` | VARCHAR | Lookup key (e.g., `registration_yes`) | +| `value` | TEXT | Display value | +| `location` | TINYINT | Site location (1/2) | + +**Model:** `_rejestracja/core/model/MfDictionary.class.php` +**DAL:** `_rejestracja/core/model/MfDictionaryDAL.class.php` +**Usage:** `{translate word='key'}` Smarty plugin → `MfDictionaryDAL` lookup + +### Supporting Tables + +- `wp_setup` — scalar/list settings for the registration form (Phase 3 form settings) +- `mf_article` / `mf_article_content` — content management (HomeSite admin) +- Additional tables inferred from DAL files in `core/model/` + +## Migration Pattern + +**SQL file:** `_rejestracja/sql/YYYY-MM-DD-description.sql` +**Runner:** `_rejestracja/sql/apply-YYYY-MM-DD-description.php` + +Runner pattern: +1. Check `INFORMATION_SCHEMA` (or similar) before altering +2. Requires `?run=YYYYMMDD` query param (or `--run` CLI flag) to execute +3. Prints "already exists / skipped" or "success" output +4. Web-accessible — see CONCERNS.md for security note + +**Applied migrations:** +- `2026-04-24-registration-form-settings` — `wp_setup` table (Phase 3, Plan 01) +- `2026-04-27-additional-info-field` — `additional_info` column on `mf_participant` (Phase 3, Plan 02) + +## DAL Query Pattern + +```php +$dalData = MfParticipantDAL::GetDalDataObj(); +$dalData->addCondition('location', 1); +$dalData->setSortBy('id_mf_participant DESC'); // value injected directly into ORDER BY +$results = MfParticipantDAL::GetResult($dalData); +``` + +`setSortBy()` value is injected verbatim into `ORDER BY` — include `DESC` in the string. + +--- + +*Schema analysis: 2026-04-27* +*Update when tables or columns change* diff --git a/.paul/codebase/integrations.md b/.paul/codebase/integrations.md new file mode 100644 index 0000000..301d091 --- /dev/null +++ b/.paul/codebase/integrations.md @@ -0,0 +1,87 @@ +# External Integrations + +**Analysis Date:** 2026-04-27 + +## APIs & External Services + +**Email (Transactional):** +- PHPMailer via mediaflex.pl SMTP — registration confirmation emails, admin notifications + - SDK/Client: PHPMailer bundled in `_rejestracja/core/lib/` + - Auth: SMTP credentials in `_rejestracja/core/config/smtp.config.ini` (committed — HIGH RISK) + - Usage: `IndexController.php` triggers email after successful registration save + +**Spam Protection:** +- Google reCAPTCHA v2 — public registration form submission guard + - Integration: server-side verification via reCAPTCHA API in `IndexController.php` + - Site key: embedded in `_rejestracja/template/partial/Index/Index.tpl` + - Secret key: in config file + +## Data Storage + +**Databases:** +- MySQL on mysql7.ceti.pl — primary data store + - Connection: credentials in `_rejestracja/core/config/db.config.ini` (INI format, committed) + - Client: custom mysqli-based DAL (`_rejestracja/core/class/DefaultDAL.class.php`) + - Migrations: manual SQL files in `_rejestracja/sql/`, applied via PHP runner scripts + +**File Storage:** +- Local filesystem — file uploads via `move_uploaded_file()` + - Upload directory: within `_rejestracja/Static/` or server path + - No cloud storage + +**Caching:** +- None — all queries hit MySQL directly, no Redis or Memcached + +## Authentication & Identity + +**Admin Auth:** +- Custom session-based auth — `AuthDAL` + `SessionProxy` + - Implementation: `_rejestracja/Admin/controller/` calls `$this->RunShared('Auth', $param)` in `preDispatch` + - Session storage: PHP sessions via `SessionProxy` + - No external identity provider + +**Public (Registration) Form:** +- No user authentication — anonymous submission with reCAPTCHA only + +## Rich Text Editing + +**CKEditor:** +- Admin templates use CKEditor for content editing (`HomeSite` admin area) + - Bundled in `_rejestracja/Static/` or loaded from CDN + +## Monitoring & Observability + +**Error Tracking:** +- None — no Sentry, no error reporting service + +**Analytics:** +- None detected + +**Logs:** +- PHP error_log only; no structured logging service + +## CI/CD & Deployment + +**Hosting:** +- Shared hosting: mediaflex.pl / ceti.pl + - Deployment: manual FTP upload via VS Code FTP Sync extension + - Config: `.vscode/ftp-kr.sync.cache.json` + +**CI Pipeline:** +- None — no GitHub Actions, no automated tests or deployment + +## Environment Configuration + +**Development:** +- Required configs: `db.config.ini` (DB host/user/pass/name), `smtp.config.ini` (SMTP credentials) +- Both committed to repo — no gitignored secret management +- Local dev requires matching PHP 5.x + MySQL + +**Production:** +- Same config files deployed via FTP +- No environment-specific config switching + +--- + +*Integration audit: 2026-04-27* +*Update when adding/removing external services* diff --git a/.paul/codebase/stack.md b/.paul/codebase/stack.md new file mode 100644 index 0000000..d2425d0 --- /dev/null +++ b/.paul/codebase/stack.md @@ -0,0 +1,74 @@ +# Technology Stack + +**Analysis Date:** 2026-04-27 + +## Languages + +**Primary:** +- PHP 5.x — all server-side application code +- SQL — database schema and migrations in `_rejestracja/sql/` + +**Secondary:** +- JavaScript/jQuery 1.x — frontend interactions, form validation +- Smarty template language — HTML generation (`_rejestracja/template/`) + +## Runtime + +**Environment:** +- PHP 5.x (shared hosting, mediaflex.pl / ceti.pl) +- Apache (inferred from .htaccess routing) +- No CLI build step; all runtime is PHP-on-request + +**Package Manager:** +- None — no Composer, no npm +- All dependencies bundled in `_rejestracja/core/lib/` and `_rejestracja/Static/` + +## Frameworks + +**Core:** +- Custom PHP MVC — hand-rolled Front Controller, Router, Controller base, DAL +- Smarty 3.x — templating engine (loaded from `_rejestracja/core/lib/Smarty/`) + +**Testing:** +- None — no test framework detected anywhere in codebase + +**Build/Dev:** +- None — no build pipeline; PHP files deployed directly to shared hosting via FTP + +## Key Dependencies + +**Critical:** +- Smarty 3.x — template rendering; bundled in `_rejestracja/core/lib/Smarty/` +- PHPMailer — SMTP email via mediaflex.pl; bundled in `_rejestracja/core/lib/` +- jQuery 1.x — frontend JS; bundled in `_rejestracja/Static/js/` +- Google reCAPTCHA v2 — spam protection on public registration form + +**Infrastructure:** +- MySQL (mysql7.ceti.pl) — primary data store, accessed via custom DAL wrapping mysqli +- Google Fonts / CDN — font loading in templates + +## Configuration + +**Environment:** +- INI config files (not .env): `_rejestracja/core/config/db.config.ini` (DB credentials), `smtp.config.ini` (email) +- No environment variable system — values hardcoded in config files committed to repo + +**Build:** +- No build config files + +## Platform Requirements + +**Development:** +- PHP 5.x compatible environment +- MySQL server +- FTP access for deployment (`.vscode/ftp-kr.sync.cache.json` indicates VS Code FTP sync) + +**Production:** +- Shared hosting: mediaflex.pl / ceti.pl +- PHP 5.x, MySQL (mysql7.ceti.pl) +- Direct FTP upload, no CI/CD + +--- + +*Stack analysis: 2026-04-27* +*Update after major dependency changes* diff --git a/.paul/codebase/structure.md b/.paul/codebase/structure.md new file mode 100644 index 0000000..10aae6a --- /dev/null +++ b/.paul/codebase/structure.md @@ -0,0 +1,145 @@ +# Codebase Structure + +**Analysis Date:** 2026-04-27 + +## Directory Layout + +``` +_rejestracja/ +├── Admin/ # Admin frontend (separate MVC stack) +│ ├── controller/ # Admin controllers (CalcController, HomeSiteController, etc.) +│ └── template/ # Admin Smarty templates +│ └── partial/ +│ └── Calc/ # Registration admin views (Reg.tpl, RegEdit.tpl, RegPAN.tpl) +├── controller/ # Public controllers (IndexController.php) +├── core/ # Shared core layer (both frontends) +│ ├── class/ # Framework classes (Router, DefaultDAL, DataObject, Validator, etc.) +│ ├── config/ # INI config files (db.config.ini, smtp.config.ini) +│ ├── lib/ # Third-party libraries (Smarty, PHPMailer) +│ ├── model/ # Active models: Mf{Entity}.class.php + Mf{Entity}DAL.class.php +│ └── _model/ # Legacy backup of model/ — NOT loaded by autoloader (78 mirror files) +├── sql/ # Migration SQL files + PHP runner scripts +├── Static/ # Frontend assets (CSS, JS, images) +│ └── image/Admin/ # Admin UI images (Thumbs.db ignored) +├── template/ # Public Smarty templates +│ └── partial/Index/ # Registration form templates (Index.tpl, IndexSent.tpl, etc.) +├── index.php # Public frontend entry point +└── Admin/index.php # Admin frontend entry point +``` + +## Directory Purposes + +**`core/model/`** (ACTIVE — edit here): +- Purpose: All domain models and DAL classes +- Contains: `Mf{Entity}.class.php` (model), `Mf{Entity}DAL.class.php` (data access) +- Key files: `MfParticipant.class.php`, `MfParticipantDAL.class.php`, `MfParameters.class.php`, `MfDictionary.class.php` +- Loaded by: `core/core.php` autoloader via `spl_autoload_register` + +**`core/_model/`** (LEGACY — do not edit): +- Purpose: Stale backup of model directory; 78 files mirroring `core/model/` +- NOT loaded by autoloader — changes here have no effect +- Should be deleted but kept for historical reference + +**`core/class/`**: +- Purpose: Framework infrastructure +- Key files: `Router.class.php`, `DefaultDAL.class.php`, `DataObject.class.php`, `Validator.class.php`, `SessionProxy.class.php`, `Request.class.php`, `MainController.class.php` + +**`core/config/`**: +- Purpose: Runtime configuration +- Key files: `db.config.ini` (DB credentials), `smtp.config.ini` (SMTP credentials) +- WARNING: Both committed to repo — contain production secrets + +**`core/lib/`**: +- Purpose: Bundled third-party libraries +- Contains: Smarty 3.x, PHPMailer, other vendored code + +**`controller/`**: +- Purpose: Public-facing request handlers +- Key files: `IndexController.php` (registration form — main entry point for all user interactions) + +**`Admin/controller/`**: +- Purpose: Admin panel request handlers +- Key files: `CalcController.php` (registration list, edit, delete), `HomeSiteController.php` (content editing) + +**`template/partial/Index/`**: +- Purpose: Public registration form templates +- Key files: `Index.tpl` (main form), `Index_good.tpl` (alternate variant), `IndexSent.tpl` (confirmation), `IndexSent_good.tpl` (alternate confirmation) + +**`Admin/template/partial/Calc/`**: +- Purpose: Admin registration management views +- Key files: `Reg.tpl` (registration list), `RegEdit.tpl` (edit payment status), `RegPAN.tpl` (alternate location view) + +**`sql/`**: +- Purpose: Database migrations +- Pattern: `YYYY-MM-DD-description.sql` + `apply-YYYY-MM-DD-description.php` (idempotent runner) +- Key files: `apply-2026-04-24-registration-form-settings.php`, `apply-2026-04-27-additional-info-field.php` + +## Key File Locations + +**Entry Points:** +- `_rejestracja/index.php` — public registration frontend +- `_rejestracja/Admin/index.php` — admin panel frontend + +**Configuration:** +- `_rejestracja/core/config/db.config.ini` — database connection +- `_rejestracja/core/config/smtp.config.ini` — SMTP email credentials +- `.vscode/ftp-kr.sync.cache.json` — FTP deployment sync config + +**Core Logic:** +- `_rejestracja/core/class/DefaultDAL.class.php` — generic CRUD base +- `_rejestracja/core/model/MfParticipant.class.php` — registration participant model +- `_rejestracja/controller/IndexController.php` — registration form controller (save, email, display) +- `_rejestracja/Admin/controller/CalcController.php` — admin registration management + +**Testing:** +- None + +## Naming Conventions + +**Files:** +- `Mf{Entity}.class.php` — model classes (MfParticipant, MfParameters, MfDictionary) +- `Mf{Entity}DAL.class.php` — data access layer classes +- `{Name}Controller.php` — controller classes +- `{Name}.tpl` — Smarty templates +- `YYYY-MM-DD-description.sql` — migration SQL files +- `apply-YYYY-MM-DD-description.php` — idempotent migration runners + +**Directories:** +- PascalCase for Admin sub-directories (Admin/controller/, Admin/template/) +- lowercase for core infrastructure directories (core/class/, core/model/) + +## Where to Add New Code + +**New model field:** +- Model: `_rejestracja/core/model/Mf{Entity}.class.php` — add to `$fields`, add property + getter/setter +- Migration: `_rejestracja/sql/YYYY-MM-DD-description.sql` + `apply-*.php` runner + +**New form field (public):** +- Template: `_rejestracja/template/partial/Index/Index.tpl` and `Index_good.tpl` +- Controller: `_rejestracja/controller/IndexController.php` — read POST, set on model +- Confirmation: `IndexSent.tpl`, `IndexSent_good.tpl` +- Admin display: `_rejestracja/Admin/template/partial/Calc/Reg.tpl` + +**New admin action:** +- Controller: `_rejestracja/Admin/controller/CalcController.php` — add `{Name}Action` method +- Template: `_rejestracja/Admin/template/partial/Calc/{Name}.tpl` + +**New dictionary phrase:** +- SQL insert into `mf_dictionary` table + migration runner + +## Special Directories + +**`core/_model/`:** +- Purpose: Legacy backup, 78 files mirroring `core/model/` +- Source: Manual backup, not updated consistently +- NOT in autoloader path — editing here has NO effect + +**`sql/`:** +- Purpose: Database migration scripts +- Runners are web-accessible (risk) — require `?run=YYYYMMDD` param to execute +- Idempotent pattern: check `INFORMATION_SCHEMA` before `ALTER TABLE` + +--- + +*Structure analysis: 2026-04-27* +*Update when directory structure changes* diff --git a/.paul/codebase/testing.md b/.paul/codebase/testing.md new file mode 100644 index 0000000..12b6e61 --- /dev/null +++ b/.paul/codebase/testing.md @@ -0,0 +1,66 @@ +# Testing Patterns + +**Analysis Date:** 2026-04-27 + +## Test Framework + +**Runner:** +- None — no test framework detected in the codebase + +**Assertion Library:** +- None + +**Run Commands:** +- No test commands defined + +## Test File Organization + +**Location:** +- No test files exist anywhere in `_rejestracja/` + +**Naming:** +- N/A — no test files + +## Current Verification Approach + +All verification is manual: + +1. **PHP syntax check** — `php -l {file}` run manually or via IDE +2. **Browser smoke test** — manually load registration form, submit, check DB/email +3. **Admin panel check** — manually verify `/_rejestracja/Admin/Calc/Reg` renders correctly +4. **Migration runner** — run `apply-*.php?run=YYYYMMDD` and read output message + +## Test Coverage Gaps + +**Everything is untested:** +- Form submission and validation logic in `IndexController.php` +- Model field mapping in `MfParticipant.class.php` (especially `$fields` array) +- DAL query generation in `DefaultDAL.class.php` +- Email sending logic +- Payment status calculation +- Smarty plugin behavior (`{translate}`, `{formField}`, `{url}`) +- Migration runners (idempotency) + +## Adding Tests (if introduced) + +If a test framework were added to this PHP project: + +**Recommended framework:** PHPUnit (standard PHP unit testing) + +**What would be easiest to test first:** +- Model getter/setter roundtrips (pure PHP, no DB) +- `Validator` class required-field checks +- Price calculation logic (if extracted from controller) + +**What would require infrastructure:** +- DAL tests (require MySQL connection) +- Full controller tests (require HTTP or simulated request context) +- Email tests (require mock or captured SMTP) + +**Key constraint:** +- PHP 5.x compatibility required — PHPUnit 4.x or 5.x (not modern versions) + +--- + +*Testing analysis: 2026-04-27* +*Update if a test framework is introduced*