docs: map existing codebase
- stack.md - Technologies and dependencies - architecture.md - System design and patterns - structure.md - Directory layout - conventions.md - Code style and patterns - testing.md - Test structure (none) - integrations.md - External services - concerns.md - Technical debt and issues - db_schema.md - Database schema and relationships Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,10 @@ PLAN --> APPLY --> UNIFY
|
|||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
|
### Codebase Mapped
|
||||||
|
Date: 2026-04-26
|
||||||
|
Documents: `.paul/codebase/` (8 files — stack, architecture, structure, conventions, testing, integrations, concerns, db_schema)
|
||||||
|
|
||||||
### Decisions
|
### Decisions
|
||||||
- 2026-04-19: Event `purchase` emitowany na `order-confirm`, nie na `przelewy24` (eliminuje falszywe konwersje).
|
- 2026-04-19: Event `purchase` emitowany na `order-confirm`, nie na `przelewy24` (eliminuje falszywe konwersje).
|
||||||
- 2026-04-19: Payload ecommerce budowany w backendzie i serializowany bezpiecznie do widoku.
|
- 2026-04-19: Payload ecommerce budowany w backendzie i serializowany bezpiecznie do widoku.
|
||||||
|
|||||||
157
.paul/codebase/architecture.md
Normal file
157
.paul/codebase/architecture.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
# Architecture
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## Pattern Overview
|
||||||
|
|
||||||
|
**Overall:** Custom PHP MVC (no framework)
|
||||||
|
|
||||||
|
**Key Characteristics:**
|
||||||
|
- URL-based routing via Apache mod_rewrite in `.htaccess`
|
||||||
|
- Namespace-organized layers (controls, factory, view)
|
||||||
|
- Custom autoloader mapping namespaces to file paths
|
||||||
|
- Session-based shopping cart (no cart persistence until order submit)
|
||||||
|
- Static public methods as controller actions
|
||||||
|
- Single config file (`config.php`) containing all settings and ticket definitions
|
||||||
|
|
||||||
|
## Layers
|
||||||
|
|
||||||
|
**Controller Layer (`autoload/controls/`):**
|
||||||
|
- Purpose: Handle HTTP actions, coordinate factory/template calls, return rendered HTML
|
||||||
|
- Contains: Route action methods (e.g., `main_view()`, `basket_view()`, `przelewy24_response()`)
|
||||||
|
- Depends on: Factory layer, `\Tpl`, `\S`, `\Html`, `global $settings, $mdb, $user`
|
||||||
|
- Used by: `\controls\Site::route()` dispatcher
|
||||||
|
|
||||||
|
**Factory/Service Layer (`autoload/factory/`):**
|
||||||
|
- Purpose: Business logic, database queries, data processing
|
||||||
|
- Contains: Calendar availability, order creation, user auth, settings management
|
||||||
|
- Depends on: `global $mdb` (Medoo), `\R::` (RedBeanPHP)
|
||||||
|
- Used by: Controllers
|
||||||
|
|
||||||
|
**View Layer (`autoload/view/`):**
|
||||||
|
- Purpose: Layout assembly — wraps controller output in site layout template
|
||||||
|
- Contains: `show()` dispatcher, layout selection logic
|
||||||
|
- Depends on: Controllers (via `\controls\Site::route()`), `\Tpl`
|
||||||
|
- Used by: Entry points (`index.php` calls `\view\Site::show()`)
|
||||||
|
|
||||||
|
**Template Layer (`templates/`):**
|
||||||
|
- Purpose: HTML rendering with embedded PHP
|
||||||
|
- Contains: Module-organized `.php` template files
|
||||||
|
- Variables accessed via `$this->key` (injected by `\Tpl`)
|
||||||
|
- Used by: Any layer via `\Tpl::view('path/name', ['key' => $value])`
|
||||||
|
|
||||||
|
**Core Utilities (`autoload/`):**
|
||||||
|
- `\S` — Session management, email, utilities (`autoload/class.S.php`)
|
||||||
|
- `\Tpl` — Template engine with variable injection (`autoload/class.Tpl.php`)
|
||||||
|
- `\Html` — Form component builder (`autoload/class.Html.php`)
|
||||||
|
- `\DbModel` — Simple active-record base class (`autoload/class.DbModel.php`)
|
||||||
|
|
||||||
|
## Data Flow
|
||||||
|
|
||||||
|
**HTTP Request Lifecycle:**
|
||||||
|
|
||||||
|
1. Browser requests `/tickets/basket_view/`
|
||||||
|
2. `.htaccess` rewrites to `index.php?module=tickets&action=basket_view`
|
||||||
|
3. `index.php` bootstraps: autoloader, config, Medoo, RedBeanPHP, PHPMailer, session security
|
||||||
|
4. `\view\Site::show()` called
|
||||||
|
5. `\controls\Site::route()` resolves module + action to `\controls\Tickets::basket_view()`
|
||||||
|
6. Controller method executes: reads session basket, calls factory methods, calls `\Tpl::view()`
|
||||||
|
7. Rendered HTML returned as string to `\view\Site::show()`
|
||||||
|
8. `show()` wraps content in `templates/site/layout-logged.php`
|
||||||
|
9. Final HTML output sent to browser
|
||||||
|
|
||||||
|
**AJAX Request Lifecycle:**
|
||||||
|
|
||||||
|
1. JavaScript POSTs to `ajax.php?module=tickets&action=ticket_add`
|
||||||
|
2. `ajax.php` bootstraps similarly to `index.php`
|
||||||
|
3. Controller method executes, modifies `$_SESSION['basket']`
|
||||||
|
4. `echo json_encode([...]); exit;` returns JSON response
|
||||||
|
|
||||||
|
**Ticket Purchase Flow:**
|
||||||
|
|
||||||
|
1. `main_view()` — Shows available tickets + calendar
|
||||||
|
2. `ticket_add()` — AJAX: validates date, calculates price, updates `$_SESSION['basket']`
|
||||||
|
3. `basket_view()` — Shows cart + customer form
|
||||||
|
4. `basketFormHandler()` — Inserts `orders` + `order_tickets` records, generates QR code PNG
|
||||||
|
5. `przelewy24()` — Renders payment form for P24 gateway
|
||||||
|
6. `przelewy24_response()` — P24 webhook: marks order paid, generates invoice, sends email
|
||||||
|
7. `order_confirm()` — Shows final confirmation + Google Analytics data layer
|
||||||
|
|
||||||
|
**State Management:**
|
||||||
|
- Shopping cart: `$_SESSION['basket']` (array keyed by ticket product_id)
|
||||||
|
- Admin auth: `$_SESSION['user']` (boolean for admin, array for staff users)
|
||||||
|
- Flash messages: `$_SESSION['alert']` (cleared after display)
|
||||||
|
- Session regenerated on first visit; IP-validated on each request
|
||||||
|
|
||||||
|
## Key Abstractions
|
||||||
|
|
||||||
|
**Module/Controller:**
|
||||||
|
- Purpose: Group of static methods handling a URL namespace (e.g., `/tickets/`)
|
||||||
|
- Examples: `autoload/controls/class.Tickets.php`, `autoload/controls/class.Apanel.php`
|
||||||
|
- Pattern: Static public methods, one per URL action
|
||||||
|
|
||||||
|
**Factory:**
|
||||||
|
- Purpose: Data access and business logic for a domain
|
||||||
|
- Examples: `autoload/factory/class.Tickets.php`, `autoload/factory/class.Users.php`
|
||||||
|
- Pattern: Static methods returning data arrays or modifying DB
|
||||||
|
|
||||||
|
**`\S` Utility Class:**
|
||||||
|
- Purpose: Centralized session, request, and utility operations
|
||||||
|
- Key methods: `S::get()` (unified POST/GET), `S::get_session()`, `S::set_session()`, `S::send_email()`, `S::hash()`, `S::alert()`
|
||||||
|
- Accessed statically throughout the codebase
|
||||||
|
|
||||||
|
**`\Tpl` Template Engine:**
|
||||||
|
- Purpose: Render PHP templates with variable injection
|
||||||
|
- Usage: `\Tpl::view('tickets/main-view', ['tickets' => $arr])`
|
||||||
|
- Variables accessible in template as `$this->tickets`
|
||||||
|
- Template lookup order: `templates_user/` → `templates/` → root
|
||||||
|
|
||||||
|
## Entry Points
|
||||||
|
|
||||||
|
**`index.php`:**
|
||||||
|
- Triggers: All web page requests
|
||||||
|
- Responsibilities: Session bootstrap, DB init, autoloader, calls `\view\Site::show()`
|
||||||
|
|
||||||
|
**`ajax.php`:**
|
||||||
|
- Triggers: jQuery AJAX calls from frontend
|
||||||
|
- Responsibilities: Same bootstrap as index.php, routes to controller AJAX actions
|
||||||
|
|
||||||
|
**`api.php`:**
|
||||||
|
- Triggers: External API calls (mobile or third-party)
|
||||||
|
- Responsibilities: API-specific bootstrap
|
||||||
|
|
||||||
|
**`cron.php`:**
|
||||||
|
- Triggers: Server cron job (scheduled tasks)
|
||||||
|
- Responsibilities: Email reminders, CEIDG import, task chaining
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
**Strategy:** Minimal — most errors are silent (error_reporting suppresses notices/warnings)
|
||||||
|
|
||||||
|
**Patterns:**
|
||||||
|
- Factories return empty arrays on failure (no exceptions thrown)
|
||||||
|
- No try/catch in most controller methods
|
||||||
|
- cURL errors ignored (return value unchecked in payment flow)
|
||||||
|
- `error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT ^ E_WARNING ^ E_DEPRECATED)` in entry points
|
||||||
|
|
||||||
|
## Cross-Cutting Concerns
|
||||||
|
|
||||||
|
**Session Security:**
|
||||||
|
- IP address validated on every request; session destroyed if changed
|
||||||
|
- Session regenerated once on first visit
|
||||||
|
- Implementation: `index.php` lines 27-31
|
||||||
|
|
||||||
|
**Globals:**
|
||||||
|
- `$settings` — all configuration (from `config.php`)
|
||||||
|
- `$mdb` — Medoo DB connection
|
||||||
|
- `$user` — current user (from session)
|
||||||
|
- Accessed via `global $settings, $mdb, $user` at top of controller methods
|
||||||
|
|
||||||
|
**Template Variables:**
|
||||||
|
- All templates receive data via `\Tpl::view()` second argument
|
||||||
|
- No direct template output buffering or inheritance
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Architecture analysis: 2026-04-26*
|
||||||
|
*Update when major patterns change*
|
||||||
131
.paul/codebase/concerns.md
Normal file
131
.paul/codebase/concerns.md
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# Codebase Concerns
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## Critical Security Issues
|
||||||
|
|
||||||
|
**SQL Injection — Admin Panel:**
|
||||||
|
- `autoload/controls/class.Apanel.php` (line ~34)
|
||||||
|
- `$_GET['id']` concatenated directly into raw SQL: `'SELECT * FROM order_tickets WHERE order_id =' . $clientId`
|
||||||
|
- Any authenticated admin (or CSRF attacker) can inject arbitrary SQL
|
||||||
|
- Fix: Use Medoo parameterized query: `$mdb->select('order_tickets', '*', ['order_id' => (int)$clientId])`
|
||||||
|
|
||||||
|
**Hardcoded Credentials in Source Control:**
|
||||||
|
- `config.php` — DB password, SMTP password (`biletyonline`), admin password (`Admin2022!`), Przelewy24 CRC key, fakturowo.pl API key, test mode secret
|
||||||
|
- Any repo access exposes production credentials
|
||||||
|
- Fix: Move to environment variables or a non-committed config file
|
||||||
|
|
||||||
|
**Weak Password Hashing (MD5):**
|
||||||
|
- `autoload/controls/class.Users.php` and `autoload/factory/class.Users.php`
|
||||||
|
- User passwords stored and compared as plain MD5 — trivially broken by rainbow tables
|
||||||
|
- Fix: Replace with `password_hash()` / `password_verify()` (bcrypt)
|
||||||
|
|
||||||
|
**Payment Callback Not Fully Verified:**
|
||||||
|
- `autoload/controls/class.Tickets.php::przelewy24_response()`
|
||||||
|
- CRC check exists but cURL verification call return value may not be checked before marking order paid
|
||||||
|
- Fix: Ensure verification response is confirmed successful before updating `payment_status`
|
||||||
|
|
||||||
|
## High Priority
|
||||||
|
|
||||||
|
**Missing Input Validation on Checkout Form:**
|
||||||
|
- `autoload/controls/class.Tickets.php::basketFormHandler()`
|
||||||
|
- `$_POST` fields (email, name, NIP, ZIP) trimmed but not format-validated before DB insert
|
||||||
|
- Email not validated with `filter_var($email, FILTER_VALIDATE_EMAIL)`
|
||||||
|
- NIP, ZIP not validated for Polish format
|
||||||
|
- Fix: Add validation layer before processing order
|
||||||
|
|
||||||
|
**888-Line Monolithic Controller:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — 888 lines, handles 15+ distinct operations
|
||||||
|
- Mixes: ticket display, cart management, payment processing, email sending, invoice generation, QR generation, GA data layer
|
||||||
|
- Makes changes risky (large surface area, no tests)
|
||||||
|
- Fix: Extract into `TicketsCart`, `TicketsCheckout`, `TicketsPayment`, `TicketsNotification`
|
||||||
|
|
||||||
|
**No CSRF Protection on Admin Actions:**
|
||||||
|
- `autoload/controls/class.Apanel.php` — all POST actions (login, order edits, deletes)
|
||||||
|
- No CSRF tokens on any form
|
||||||
|
- Fix: Add token generation + validation middleware
|
||||||
|
|
||||||
|
**cURL Error Handling Missing:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — Przelewy24 and fakturowo.pl cURL calls
|
||||||
|
- `curl_exec()` return value not consistently checked; no timeout set
|
||||||
|
- Silent failures possible: order could be marked paid without invoice, or invoice not generated
|
||||||
|
- Fix: Check return value, add `CURLOPT_TIMEOUT`, log failures
|
||||||
|
|
||||||
|
**No Session Fixation Protection on Login:**
|
||||||
|
- `autoload/controls/class.Users.php::login()` — no `session_regenerate_id(true)` on successful auth
|
||||||
|
- Session regeneration only on first visit (new session), not on privilege escalation
|
||||||
|
- Fix: Call `session_regenerate_id(true)` after successful login
|
||||||
|
|
||||||
|
## Medium Priority
|
||||||
|
|
||||||
|
**Hardcoded Domain URLs:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — `https://bilety.brzezovka.pl` hardcoded in ~5 places
|
||||||
|
- Breaks if domain changes; makes staging difficult
|
||||||
|
- Fix: Store base URL in `config.php` as `$settings['base_url']`
|
||||||
|
|
||||||
|
**No Application Logging:**
|
||||||
|
- No error logging system (PSR-3 or equivalent)
|
||||||
|
- No audit trail for payments, admin actions, or errors
|
||||||
|
- Only optional `mail_debug.log` for email
|
||||||
|
- Fix: Add basic file logger for critical operations (payment events, admin changes)
|
||||||
|
|
||||||
|
**Weak Order Hash Generation:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — hash based on MD5 of email + city + timestamp
|
||||||
|
- 1-second collision window for same customer; predictable construction
|
||||||
|
- Fix: Use `bin2hex(random_bytes(16))` for cryptographically random order hashes
|
||||||
|
|
||||||
|
**Global Variables Without DI:**
|
||||||
|
- All controllers: `global $settings, $mdb, $user` at top of every method
|
||||||
|
- Untestable, hidden dependencies, risk of undefined global
|
||||||
|
- Fix: Long-term — dependency injection; short-term — document as known pattern
|
||||||
|
|
||||||
|
**QR Codes in Web-Accessible Directory:**
|
||||||
|
- `orders/{hash[0]}/{hash[1]}/{hash}.png` — served directly by Apache
|
||||||
|
- Hash is predictable (see hash concern above)
|
||||||
|
- Fix: Move QR storage outside web root; serve via PHP controller with auth check
|
||||||
|
|
||||||
|
**Large Template Files:**
|
||||||
|
- `templates/tickets/main-view.php` — 401 lines
|
||||||
|
- `templates/admin-panel/order-data.php` — 373 lines
|
||||||
|
- `templates/tickets/basket-view.php` — 316 lines
|
||||||
|
- Mixed PHP logic and HTML; difficult to maintain
|
||||||
|
- Fix: Extract repeated logic to view helper classes
|
||||||
|
|
||||||
|
**Duplicate Bootstrap Code:**
|
||||||
|
- `index.php`, `ajax.php`, `api.php`, `cron.php` — each contains near-identical DB init, session, autoloader
|
||||||
|
- Fix: Extract to `bootstrap.php` included by all entry points
|
||||||
|
|
||||||
|
**No Error Handling on DB Writes:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — `$mdb->insert()` / `$mdb->update()` calls without checking return value
|
||||||
|
- Silent failure if DB write fails (order not saved but user gets confirmation)
|
||||||
|
- Fix: Check return value; wrap in try/catch
|
||||||
|
|
||||||
|
## Low Priority / Documentation
|
||||||
|
|
||||||
|
**Magic Numbers in Pricing Logic:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — Day ranges `0`, `2`, `7` for dynamic pricing; product ID `999999` for delivery
|
||||||
|
- Fix: Define as named constants (e.g., `const DELIVERY_PRODUCT_ID = 999999`)
|
||||||
|
|
||||||
|
**Commented Debug Code:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — `// file_put_contents('sandbox_przelewy24_response.txt', ...)` left in code
|
||||||
|
- Fix: Remove
|
||||||
|
|
||||||
|
**Short PHP Tags in Templates:**
|
||||||
|
- `templates/` — `<? if ...` (deprecated, requires `short_open_tag = On`)
|
||||||
|
- Fix: Replace with `<?php` in templates over time
|
||||||
|
|
||||||
|
**MD5 Session CSRF Token:**
|
||||||
|
- `index.php` — `$_SESSION['check'] = md5(...)` used as CSRF-adjacent token
|
||||||
|
- MD5 for security tokens is considered weak
|
||||||
|
- Fix: Use `bin2hex(random_bytes(32))` for session tokens
|
||||||
|
|
||||||
|
**No README / Setup Guide:**
|
||||||
|
- No documentation on how to set up dev environment or database
|
||||||
|
- No `.env.example` or credential template
|
||||||
|
- Fix: Add `README.md` with setup steps and required config values
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Concerns analysis: 2026-04-26*
|
||||||
|
*Priority order: Critical → High → Medium → Low*
|
||||||
|
*Address Critical items before any new feature development*
|
||||||
144
.paul/codebase/conventions.md
Normal file
144
.paul/codebase/conventions.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# Coding Conventions
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## Naming Patterns
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- `class.{ClassName}.php` — All PHP class files (e.g., `class.Tickets.php`, `class.S.php`)
|
||||||
|
- `kebab-case.php` — Template files (e.g., `main-view.php`, `order-data-table.php`)
|
||||||
|
- No test file pattern — no test files exist
|
||||||
|
|
||||||
|
**Methods/Functions:**
|
||||||
|
- `snake_case` — Older/dominant style: `main_view()`, `get_session()`, `basket_view()`
|
||||||
|
- `camelCase` — Newer additions: `buildPurchaseDataLayer()`, `sendPaidOrderSummaryEmail()`, `isValidTestPriceSecret()`
|
||||||
|
- Action-oriented names mapping to URL: `ticket_add()`, `order_confirm()`, `login_check()`
|
||||||
|
|
||||||
|
**Variables:**
|
||||||
|
- `$snake_case` — All variables
|
||||||
|
- `$mdb`, `$user`, `$settings` — Global shorthand names
|
||||||
|
- `$orderArr`, `$ticketsArr` — Array suffix pattern
|
||||||
|
|
||||||
|
**Classes:**
|
||||||
|
- PascalCase: `Tickets`, `Apanel`, `Users`, `Scanner`
|
||||||
|
- Namespaced: `\controls\Tickets`, `\factory\Tickets`, `\view\Site`
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
**Formatting:**
|
||||||
|
- 2-space indentation (spaces, not tabs)
|
||||||
|
- CRLF line endings (Windows)
|
||||||
|
- Spaces inside parentheses: `function method( $param )`, `if ( $x === '' )`
|
||||||
|
- Spaces around `->`: `$this -> key` (unusual; vs `$this->key` standard)
|
||||||
|
- Spaces around operators: `$x === ''`, `$x != null`
|
||||||
|
|
||||||
|
**Method Visibility:**
|
||||||
|
- `static public` order (reversed from PSR standard): `static public function main_view()`
|
||||||
|
- Mix of `static public` and `public static` — inconsistent
|
||||||
|
- Private helpers: `private static function _helper()`
|
||||||
|
|
||||||
|
**Visibility Note:** PHP allows both orderings; the existing codebase uses `static public`.
|
||||||
|
|
||||||
|
**Type Usage:**
|
||||||
|
- Explicit type casting: `(float)$val`, `(int)$id`, `(string)$hash`
|
||||||
|
- Null coalescing: `$_SESSION[$var] ?? null`
|
||||||
|
- No strict types declaration (`declare(strict_types=1)` not used)
|
||||||
|
|
||||||
|
**Linting/Formatting:**
|
||||||
|
- No ESLint, Prettier, PHP-CS-Fixer, or similar configured
|
||||||
|
- Style enforced only by convention
|
||||||
|
|
||||||
|
## Import Organization
|
||||||
|
|
||||||
|
- No `use` statements or `import` — classes referenced by full namespace inline: `\controls\Tickets::method()`
|
||||||
|
- Globals declared at method start: `global $settings, $mdb, $user;`
|
||||||
|
- Libraries loaded in entry points (`index.php`, `ajax.php`) with `require_once`
|
||||||
|
|
||||||
|
## Template Patterns
|
||||||
|
|
||||||
|
**Rendering:**
|
||||||
|
```php
|
||||||
|
return \Tpl::view('tickets/main-view', [
|
||||||
|
'tickets' => $ticketsArr,
|
||||||
|
'basket' => $basket,
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Variable access in templates:**
|
||||||
|
```php
|
||||||
|
$tickets = $this->tickets; // via __get magic
|
||||||
|
echo $this->order_price;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output escaping:**
|
||||||
|
- `htmlspecialchars()` used inconsistently — not universally applied
|
||||||
|
- Short echo: `<?= $this->name ?>` (no escaping — common pattern)
|
||||||
|
- Short if: `<? if ($condition): ?>` (deprecated short tags — present in older templates)
|
||||||
|
|
||||||
|
## AJAX Response Pattern
|
||||||
|
|
||||||
|
All AJAX actions follow this pattern:
|
||||||
|
```php
|
||||||
|
echo json_encode([
|
||||||
|
'basket_html' => \Tpl::view('tickets/basket-view', ['basket' => $basket]),
|
||||||
|
'count' => count($basket),
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
```
|
||||||
|
- `exit` always follows `json_encode` output
|
||||||
|
- Response keys are snake_case
|
||||||
|
- Often includes rendered HTML fragments for DOM replacement
|
||||||
|
|
||||||
|
## Error Handling Conventions
|
||||||
|
|
||||||
|
- No exceptions thrown in application code
|
||||||
|
- Factories return `[]` or `false` on failure (no consistent return type)
|
||||||
|
- No try/catch blocks except in `autoload/factory/class.Tickets.php` (calendar transactions)
|
||||||
|
- Errors suppressed via `error_reporting(E_ALL ^ E_NOTICE ^ E_STRICT ^ E_WARNING ^ E_DEPRECATED)` in entry points
|
||||||
|
|
||||||
|
## Documentation Style
|
||||||
|
|
||||||
|
- Minimal comments overall
|
||||||
|
- Inline comments use `//*` prefix (non-standard): `//* Zapisywanie do DB bilety`
|
||||||
|
- Language: mix of Polish and English in comments and variable names
|
||||||
|
- No PHPDoc blocks on custom application methods
|
||||||
|
- Vendored libraries (e.g., Excel.php) have `/** @author */` blocks
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
**Global Access (every controller method):**
|
||||||
|
```php
|
||||||
|
static public function some_action() {
|
||||||
|
global $settings, $mdb;
|
||||||
|
global $user;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Session via S class:**
|
||||||
|
```php
|
||||||
|
\S::set_session('basket', $basket);
|
||||||
|
$basket = \S::get_session('basket') ?? [];
|
||||||
|
\S::del_session('alert');
|
||||||
|
\S::alert('Błąd - brak zamówienia');
|
||||||
|
```
|
||||||
|
|
||||||
|
**DB queries via Medoo:**
|
||||||
|
```php
|
||||||
|
$order = $mdb->get('orders', '*', ['hash' => $hash]);
|
||||||
|
$tickets = $mdb->select('order_tickets', '*', ['order_id' => $id]);
|
||||||
|
$mdb->insert('orders', ['name' => $name, 'email' => $email]);
|
||||||
|
$mdb->update('orders', ['payment_status' => 1], ['id' => $id]);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Config access:**
|
||||||
|
```php
|
||||||
|
$settings['ticket'][$product_id]['name']
|
||||||
|
$settings['p24_merchant_id']
|
||||||
|
$settings['admin-password']
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Conventions analysis: 2026-04-26*
|
||||||
|
*Update when major style changes are introduced*
|
||||||
144
.paul/codebase/db_schema.md
Normal file
144
.paul/codebase/db_schema.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# Database Schema
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
- Database: MySQL (`srv81099_brzez_ticket`)
|
||||||
|
- ORM: Medoo query builder (`$mdb` global) for most queries; RedBeanPHP for cron tasks
|
||||||
|
- No migration files — schema managed manually
|
||||||
|
- No schema files checked into repo — tables inferred from code
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tables
|
||||||
|
|
||||||
|
### `orders`
|
||||||
|
|
||||||
|
Primary order records — one row per customer purchase.
|
||||||
|
|
||||||
|
| Column | Type (inferred) | Notes |
|
||||||
|
|--------|----------------|-------|
|
||||||
|
| `id` | INT AUTO_INCREMENT PK | |
|
||||||
|
| `name` | VARCHAR | Customer first name |
|
||||||
|
| `surname` | VARCHAR | Customer last name |
|
||||||
|
| `email` | VARCHAR | Customer email |
|
||||||
|
| `zip_code` | VARCHAR | |
|
||||||
|
| `city` | VARCHAR | |
|
||||||
|
| `street` | VARCHAR | |
|
||||||
|
| `order_price` | DECIMAL | Total order value |
|
||||||
|
| `date_added` | DATETIME | Order creation timestamp |
|
||||||
|
| `hash` | VARCHAR UNIQUE | Order identifier (used in URLs, QR codes) |
|
||||||
|
| `payment_hash` | VARCHAR | Przelewy24 session/transaction ID |
|
||||||
|
| `payment_status` | TINYINT | 0 = unpaid, 1 = paid |
|
||||||
|
| `payment_date` | DATETIME | Timestamp of payment confirmation |
|
||||||
|
| `invoice_status` | TINYINT | 0 = not generated, 1 = generated |
|
||||||
|
| `invoice_url` | VARCHAR | URL to fakturowo.pl invoice/receipt |
|
||||||
|
| `vat` | TINYINT | 0 = paragon, 1 = faktura VAT |
|
||||||
|
| `company_name` | VARCHAR | For VAT invoice |
|
||||||
|
| `nip` | VARCHAR | Polish tax ID for VAT invoice |
|
||||||
|
| `gift_address` | TEXT | Gift ticket delivery address |
|
||||||
|
| `used_ticket` | TINYINT | Whether QR has been scanned/used |
|
||||||
|
| `informed_user` | TINYINT | Whether confirmation email was sent |
|
||||||
|
|
||||||
|
**Key queries:** `autoload/controls/class.Tickets.php`, `autoload/controls/class.Apanel.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `order_tickets`
|
||||||
|
|
||||||
|
Line items — one row per ticket type per order.
|
||||||
|
|
||||||
|
| Column | Type (inferred) | Notes |
|
||||||
|
|--------|----------------|-------|
|
||||||
|
| `id` | INT AUTO_INCREMENT PK | |
|
||||||
|
| `order_id` | INT FK → orders.id | |
|
||||||
|
| `product_id` | INT | Ticket product ID from `$settings['ticket']` |
|
||||||
|
| `name` | VARCHAR | Ticket name (copied from config at time of order) |
|
||||||
|
| `quantity` | INT | Number of tickets |
|
||||||
|
| `price` | DECIMAL | Unit price at time of purchase |
|
||||||
|
| `date_visit` | DATE | Intended visit date |
|
||||||
|
| `date_added` | DATETIME | Row creation timestamp |
|
||||||
|
|
||||||
|
**Key queries:** `autoload/controls/class.Apanel.php`, `autoload/factory/class.Tickets.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `users`
|
||||||
|
|
||||||
|
Staff/admin accounts for non-ticket modules.
|
||||||
|
|
||||||
|
| Column | Type (inferred) | Notes |
|
||||||
|
|--------|----------------|-------|
|
||||||
|
| `id` | INT AUTO_INCREMENT PK | |
|
||||||
|
| `email` | VARCHAR UNIQUE | Login identifier |
|
||||||
|
| `password` | VARCHAR(32) | MD5 hash (insecure — see concerns.md) |
|
||||||
|
| `name` | VARCHAR | First name |
|
||||||
|
| `surname` | VARCHAR | Last name |
|
||||||
|
| `default_project` | INT | Default project preference |
|
||||||
|
| `pushover_api` | VARCHAR | Pushover API key for push notifications |
|
||||||
|
| `pushover_user` | VARCHAR | Pushover user key |
|
||||||
|
|
||||||
|
**Key queries:** `autoload/factory/class.Users.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `ticket_calendar_availability`
|
||||||
|
|
||||||
|
Controls which dates tickets can be purchased for.
|
||||||
|
|
||||||
|
| Column | Type (inferred) | Notes |
|
||||||
|
|--------|----------------|-------|
|
||||||
|
| `ticket_group` | VARCHAR PK (composite) | e.g., `park-rozrywki`, `park-wodny` |
|
||||||
|
| `available_date` | DATE PK (composite) | Date that is enabled for purchase |
|
||||||
|
| `updated_at` | DATETIME | Last modification timestamp |
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- Created dynamically via `\factory\Tickets::ensureCalendarTable()` if missing
|
||||||
|
- Admin manages via `/apanel/settings/` → calendar editor
|
||||||
|
- Ticket groups: `park-rozrywki`, `park-wodny`, `all-open`, `bilety-rodzinne`
|
||||||
|
- **Key file:** `autoload/factory/class.Tickets.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `site_settings`
|
||||||
|
|
||||||
|
Key-value store for runtime configuration (complements `config.php`).
|
||||||
|
|
||||||
|
| Column | Type (inferred) | Notes |
|
||||||
|
|--------|----------------|-------|
|
||||||
|
| `setting_key` | VARCHAR PK | Setting name |
|
||||||
|
| `setting_value` | TEXT | Setting value |
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- Created dynamically via `\factory\Apanel::getSetting()` if missing
|
||||||
|
- `REPLACE INTO` for upserts
|
||||||
|
- Used for admin-editable settings that don't require code deploy
|
||||||
|
- **Key file:** `autoload/factory/class.Apanel.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Relationships
|
||||||
|
|
||||||
|
```
|
||||||
|
orders (1) ──────< (N) order_tickets
|
||||||
|
orders.id = order_tickets.order_id
|
||||||
|
|
||||||
|
users — standalone (no FK to orders)
|
||||||
|
ticket_calendar_availability — standalone lookup table
|
||||||
|
site_settings — standalone KV store
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Approach
|
||||||
|
|
||||||
|
- No migration tool (no Flyway, Phinx, Liquibase)
|
||||||
|
- Schema changes applied manually via MySQL client
|
||||||
|
- New tables created programmatically in application code when needed:
|
||||||
|
- `ticket_calendar_availability` — `\factory\Tickets::ensureCalendarTable()`
|
||||||
|
- `site_settings` — `\factory\Apanel::getSetting()`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Schema analysis: 2026-04-26*
|
||||||
|
*Inferred from code — no authoritative schema file in repo*
|
||||||
|
*Verify against production database for exact column types*
|
||||||
112
.paul/codebase/integrations.md
Normal file
112
.paul/codebase/integrations.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# External Integrations
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## APIs & External Services
|
||||||
|
|
||||||
|
**Payment Processing:**
|
||||||
|
- Przelewy24 — Polish payment gateway for ticket purchases
|
||||||
|
- SDK/Client: Custom cURL integration in `autoload/controls/class.Tickets.php`
|
||||||
|
- Auth: Merchant ID `227658` + CRC key (MD5-signed) in `config.php`
|
||||||
|
- Endpoints: `https://secure.przelewy24.pl/trnVerify` (production), sandbox configurable
|
||||||
|
- Flow: Pre-payment form → P24 hosted page → `przelewy24_response()` webhook callback
|
||||||
|
- Sandbox mode: toggle in `config.php`
|
||||||
|
|
||||||
|
**Invoice/Receipt Generation:**
|
||||||
|
- fakturowo.pl — Polish invoicing API (paragon or faktura VAT)
|
||||||
|
- SDK/Client: Custom cURL POST in `autoload/controls/class.Tickets.php`
|
||||||
|
- Auth: API ID in `config.php` (`$settings['fakturowo_api_id']`)
|
||||||
|
- Endpoint: `https://konto.fakturowo.pl/api`
|
||||||
|
- Triggered after successful Przelewy24 payment
|
||||||
|
- Returns invoice URL stored in `orders.invoice_url`
|
||||||
|
|
||||||
|
## Data Storage
|
||||||
|
|
||||||
|
**Databases:**
|
||||||
|
- MySQL — Primary data store
|
||||||
|
- Connection: Credentials in `config.php`, instantiated in `index.php:44`
|
||||||
|
- Client: Medoo query builder (`libraries/medoo/medoo.php`)
|
||||||
|
- Secondary ORM: RedBeanPHP (`libraries/rb.php`) used in cron tasks
|
||||||
|
|
||||||
|
**File Storage:**
|
||||||
|
- Local filesystem — QR code PNG files stored in `orders/{hash[0]}/{hash[1]}/{hash}.png`
|
||||||
|
- Web-accessible directory, predictable path structure
|
||||||
|
- Created with `mkdir($dir, 0755, true)` and `\QRcode::png()`
|
||||||
|
|
||||||
|
## Authentication & Identity
|
||||||
|
|
||||||
|
**Admin Auth:**
|
||||||
|
- Single shared password stored in `config.php` (`$settings['admin-password']`)
|
||||||
|
- Session-based: password checked once, `$_SESSION['user'] = true` set
|
||||||
|
- No individual admin accounts for ticket operations (single login)
|
||||||
|
|
||||||
|
**Staff/User Auth:**
|
||||||
|
- Separate user table for named staff (`users` table — id, email, MD5 password)
|
||||||
|
- Used for non-ticket modules (projects, finances, etc.)
|
||||||
|
- Hard-coded ACL in `autoload/controls/class.Users.php` (`permissions()` method)
|
||||||
|
- Login via `autoload/factory/class.Users.php::login()` with MD5 comparison
|
||||||
|
|
||||||
|
## Email
|
||||||
|
|
||||||
|
**PHPMailer + SMTP:**
|
||||||
|
- Library: `libraries/phpmailer/class.phpmailer.php`
|
||||||
|
- SMTP host: `h53.seohost.pl` port 25
|
||||||
|
- From address: `bilety@brzezovka.pl`
|
||||||
|
- Credentials: in `config.php`
|
||||||
|
- Fallback: native PHP `mail()` if SMTP unavailable
|
||||||
|
- Debug logging: optional to `mail_debug.log`
|
||||||
|
- Used for: order confirmations (pre-payment), payment confirmations (with QR PNG attachment)
|
||||||
|
- Implementation: `autoload/class.S.php::send_email()`
|
||||||
|
|
||||||
|
## Monitoring & Observability
|
||||||
|
|
||||||
|
**Error Tracking:** Not detected — no Sentry, Rollbar, or similar
|
||||||
|
|
||||||
|
**Analytics:**
|
||||||
|
- Google Analytics ecommerce data layer — purchase tracking
|
||||||
|
- `buildPurchaseDataLayer()` in `autoload/controls/class.Tickets.php`
|
||||||
|
- Generates `$purchase_data_layer` passed to `templates/tickets/order-confirm.php`
|
||||||
|
- Fires on order confirmation page
|
||||||
|
|
||||||
|
**Logs:**
|
||||||
|
- Optional mail debug log: `mail_debug.log` (file-based, in project root)
|
||||||
|
- No centralized application logging
|
||||||
|
|
||||||
|
## CI/CD & Deployment
|
||||||
|
|
||||||
|
**Hosting:** Shared hosting (seohost.pl, Apache)
|
||||||
|
|
||||||
|
**Deployment:**
|
||||||
|
- FTP sync via VS Code ftp-kr extension
|
||||||
|
- Config: `.vscode/ftp-kr.json`, cache: `.vscode/ftp-kr.sync.cache.json`
|
||||||
|
- Manual deploy — upload changed files via FTP
|
||||||
|
|
||||||
|
**CI Pipeline:** None detected
|
||||||
|
|
||||||
|
## Environment Configuration
|
||||||
|
|
||||||
|
**Development:**
|
||||||
|
- All config in `config.php` (single file, committed to git)
|
||||||
|
- No separate dev/staging/prod config files
|
||||||
|
- Test mode: `$settings['test_price_mode_secret']` for pricing tests
|
||||||
|
|
||||||
|
**Production:**
|
||||||
|
- Przelewy24 sandbox toggle: `$settings['p24_sandbox'] = false`
|
||||||
|
- All secrets in `config.php` — not managed via environment variables
|
||||||
|
|
||||||
|
## Webhooks & Callbacks
|
||||||
|
|
||||||
|
**Incoming:**
|
||||||
|
- Przelewy24 — `/tickets/przelewy24_response/`
|
||||||
|
- Handled in `autoload/controls/class.Tickets.php::przelewy24_response()`
|
||||||
|
- Verification: MD5 CRC check against P24 parameters
|
||||||
|
- On success: marks order paid, generates invoice, sends confirmation email
|
||||||
|
|
||||||
|
**Outgoing:**
|
||||||
|
- fakturowo.pl — POST request on payment confirmation
|
||||||
|
- Przelewy24 verification — GET/POST to `trnVerify` endpoint to confirm transaction
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Integration audit: 2026-04-26*
|
||||||
|
*Update when adding/removing external services*
|
||||||
83
.paul/codebase/stack.md
Normal file
83
.paul/codebase/stack.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# Technology Stack
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## Languages
|
||||||
|
|
||||||
|
**Primary:**
|
||||||
|
- PHP 7.4+ - All application code (`index.php`, `autoload/`)
|
||||||
|
- HTML/PHP - Template files (`templates/`)
|
||||||
|
|
||||||
|
**Secondary:**
|
||||||
|
- SCSS - Stylesheet authoring (`layout/style-scss/style.scss`)
|
||||||
|
- JavaScript (ES5+) - Client-side logic embedded in templates and CDN-loaded libraries
|
||||||
|
|
||||||
|
## Runtime
|
||||||
|
|
||||||
|
**Environment:**
|
||||||
|
- PHP 7.4+ on Apache (shared hosting)
|
||||||
|
- MySQL database (`srv81099_brzez_ticket`)
|
||||||
|
- Timezone: Europe/Warsaw
|
||||||
|
|
||||||
|
**Package Manager:**
|
||||||
|
- None — no Composer, no npm
|
||||||
|
- All dependencies vendored in `libraries/`
|
||||||
|
|
||||||
|
## Frameworks
|
||||||
|
|
||||||
|
**Core:**
|
||||||
|
- None — custom MVC built from scratch
|
||||||
|
|
||||||
|
**Frontend:**
|
||||||
|
- Bootstrap 5.2 — Responsive layout and components (CDN)
|
||||||
|
- jQuery 3.6 — DOM manipulation and AJAX (CDN)
|
||||||
|
- Font Awesome 6.1 — Icons (CDN)
|
||||||
|
- Flatpickr — Date picker for ticket date selection (CDN)
|
||||||
|
- DataTables — Admin order list pagination/sorting (CDN)
|
||||||
|
- html5-qrcode — Browser QR code scanner for on-site validation (CDN)
|
||||||
|
|
||||||
|
**Build/Dev:**
|
||||||
|
- Live Sass Compiler (VS Code extension) — SCSS → CSS compilation
|
||||||
|
- FTP sync via ftp-kr VS Code extension — Deployment
|
||||||
|
|
||||||
|
## Key Dependencies
|
||||||
|
|
||||||
|
**Critical:**
|
||||||
|
- Medoo — MySQL query builder (`libraries/medoo/medoo.php` — referenced in code, may be missing from repo)
|
||||||
|
- RedBeanPHP — ORM used in cron jobs (`libraries/rb.php`, 570KB single file)
|
||||||
|
- PHPMailer — SMTP email delivery (`libraries/phpmailer/class.phpmailer.php`, `class.smtp.php`)
|
||||||
|
- phpqrcode — QR code generation for tickets (`libraries/phpqrcode/qrlib.php`)
|
||||||
|
|
||||||
|
**Infrastructure:**
|
||||||
|
- PDO — Database access layer (used internally by Medoo)
|
||||||
|
- cURL — HTTP calls to Przelewy24 and fakturowo.pl APIs
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
**Environment:**
|
||||||
|
- Single file: `config.php` — contains ALL configuration
|
||||||
|
- Database credentials, SMTP settings, ticket pricing, payment gateway keys, admin password
|
||||||
|
- No `.env` files — credentials hardcoded (security concern documented in concerns.md)
|
||||||
|
|
||||||
|
**Build:**
|
||||||
|
- SCSS config in first-line comment of `layout/style-scss/style.scss`
|
||||||
|
- No build config files (vite, webpack, etc.)
|
||||||
|
|
||||||
|
## Platform Requirements
|
||||||
|
|
||||||
|
**Development:**
|
||||||
|
- Windows (VS Code with Live Sass Compiler + ftp-kr extensions)
|
||||||
|
- PHP 7.4+ locally or via FTP-direct editing
|
||||||
|
- MySQL access for schema changes
|
||||||
|
|
||||||
|
**Production:**
|
||||||
|
- Apache + mod_rewrite (shared hosting via seohost.pl)
|
||||||
|
- PHP 7.4+
|
||||||
|
- MySQL
|
||||||
|
- Outbound SMTP (port 25 to h53.seohost.pl)
|
||||||
|
- Outbound HTTPS for Przelewy24 and fakturowo.pl
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Stack analysis: 2026-04-26*
|
||||||
|
*Update after major dependency changes*
|
||||||
159
.paul/codebase/structure.md
Normal file
159
.paul/codebase/structure.md
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# Codebase Structure
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## Directory Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
bilety.brzezovka.pl/
|
||||||
|
├── autoload/ # PHP autoloaded classes (MVC layers + core utilities)
|
||||||
|
│ ├── controls/ # Controllers (request handlers per module)
|
||||||
|
│ ├── factory/ # Business logic and DB query services
|
||||||
|
│ ├── view/ # View composers (layout wrapping)
|
||||||
|
│ ├── class.S.php # Session, utilities, email
|
||||||
|
│ ├── class.Tpl.php # Template engine
|
||||||
|
│ ├── class.Html.php # Form component builder
|
||||||
|
│ ├── class.DbModel.php # Active-record base class
|
||||||
|
│ ├── class.Excel.php # Order Excel export
|
||||||
|
│ └── class.Cron.php # Cron stub
|
||||||
|
├── templates/ # PHP HTML templates
|
||||||
|
│ ├── tickets/ # Customer-facing ticket shop
|
||||||
|
│ ├── admin-panel/ # Admin order management
|
||||||
|
│ ├── site/ # Layout wrappers
|
||||||
|
│ ├── html/ # Reusable form components
|
||||||
|
│ ├── components/ # UI fragments (spinner, etc.)
|
||||||
|
│ └── cron/ # Cron output
|
||||||
|
├── libraries/ # Vendored PHP dependencies
|
||||||
|
│ ├── rb.php # RedBeanPHP ORM
|
||||||
|
│ ├── phpmailer/ # PHPMailer SMTP
|
||||||
|
│ └── phpqrcode/ # QR code generator
|
||||||
|
├── layout/ # Frontend assets
|
||||||
|
│ ├── style-scss/ # SCSS source files
|
||||||
|
│ ├── style-css/ # Compiled CSS
|
||||||
|
│ └── images/ # Logos, icons
|
||||||
|
├── orders/ # Generated QR code PNGs (web-accessible)
|
||||||
|
├── .paul/ # PAUL project planning files
|
||||||
|
├── .vscode/ # VS Code settings + FTP sync config
|
||||||
|
├── index.php # Main web entry point
|
||||||
|
├── ajax.php # AJAX endpoint
|
||||||
|
├── api.php # API endpoint
|
||||||
|
├── cron.php # Scheduled tasks entry point
|
||||||
|
└── config.php # All configuration (DB, SMTP, tickets, keys)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Directory Purposes
|
||||||
|
|
||||||
|
**`autoload/`:**
|
||||||
|
- Purpose: All PHP application classes, autoloaded by `spl_autoload_register`
|
||||||
|
- Naming convention: `class.{ClassName}.php`
|
||||||
|
- Namespace→path mapping: `\controls\Tickets` → `autoload/controls/class.Tickets.php`
|
||||||
|
|
||||||
|
**`autoload/controls/`:**
|
||||||
|
- Purpose: Controller classes — one per module
|
||||||
|
- Key files: `class.Tickets.php` (888 lines, ticket shop), `class.Apanel.php`, `class.Users.php`, `class.Scanner.php`, `class.Site.php` (router)
|
||||||
|
|
||||||
|
**`autoload/factory/`:**
|
||||||
|
- Purpose: Business logic and DB query classes
|
||||||
|
- Key files: `class.Tickets.php` (calendar, basket), `class.Apanel.php` (settings), `class.Users.php` (auth)
|
||||||
|
|
||||||
|
**`autoload/view/`:**
|
||||||
|
- Purpose: Layout composers — wrap controller output in site templates
|
||||||
|
- Key files: `class.Site.php` (main layout dispatcher)
|
||||||
|
|
||||||
|
**`templates/`:**
|
||||||
|
- Purpose: PHP HTML templates rendered by `\Tpl::view()`
|
||||||
|
- Subdirs match module names; files use kebab-case: `main-view.php`, `order-data.php`
|
||||||
|
|
||||||
|
**`libraries/`:**
|
||||||
|
- Purpose: Vendored third-party PHP libraries (no Composer)
|
||||||
|
- Do not modify; update by replacing files
|
||||||
|
|
||||||
|
**`layout/`:**
|
||||||
|
- Purpose: Frontend assets
|
||||||
|
- SCSS compiled via VS Code Live Sass Compiler — edit `style-scss/`, output goes to `style-css/`
|
||||||
|
|
||||||
|
**`orders/`:**
|
||||||
|
- Purpose: Runtime-generated QR code PNG storage
|
||||||
|
- Structure: `orders/{hash[0]}/{hash[1]}/{hash}.png`
|
||||||
|
- Web-accessible (referenced in confirmation emails and scanner)
|
||||||
|
|
||||||
|
## Key File Locations
|
||||||
|
|
||||||
|
**Entry Points:**
|
||||||
|
- `index.php` — All web requests
|
||||||
|
- `ajax.php` — jQuery AJAX calls
|
||||||
|
- `api.php` — External API access
|
||||||
|
- `cron.php` — Scheduled background tasks
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- `config.php` — Everything: DB, SMTP, ticket types/prices, payment keys, admin password
|
||||||
|
|
||||||
|
**Core Logic:**
|
||||||
|
- `autoload/controls/class.Tickets.php` — Full ticket purchase flow + P24 payment
|
||||||
|
- `autoload/controls/class.Apanel.php` — Admin order management
|
||||||
|
- `autoload/factory/class.Tickets.php` — Calendar availability, basket logic
|
||||||
|
- `autoload/class.S.php` — Session, email, utility methods used everywhere
|
||||||
|
|
||||||
|
**Templates:**
|
||||||
|
- `templates/tickets/main-view.php` — Ticket selection + calendar UI
|
||||||
|
- `templates/tickets/basket-form.php` — Customer details checkout form
|
||||||
|
- `templates/tickets/przelewy24.php` — Payment gateway form
|
||||||
|
- `templates/tickets/order-confirm.php` — Post-payment confirmation
|
||||||
|
- `templates/admin-panel/main-view.php` — Orders list table
|
||||||
|
- `templates/admin-panel/order-data.php` — Order detail + edit modal
|
||||||
|
- `templates/site/layout-logged.php` — Main site wrapper
|
||||||
|
|
||||||
|
**Styles:**
|
||||||
|
- `layout/style-scss/style.scss` — SCSS source (compile with Live Sass Compiler)
|
||||||
|
- `layout/style-css/style.css` — Compiled output (don't edit directly)
|
||||||
|
|
||||||
|
## Naming Conventions
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- `class.{ClassName}.php` — All PHP class files in `autoload/`
|
||||||
|
- `kebab-case.php` — Template files in `templates/`
|
||||||
|
- `style.scss` / `style.css` — Single compiled stylesheet
|
||||||
|
|
||||||
|
**Directories:**
|
||||||
|
- Singular for layers: `controls/`, `factory/`, `view/`
|
||||||
|
- Module-named for templates: `tickets/`, `admin-panel/`, `site/`
|
||||||
|
- Lowercase throughout
|
||||||
|
|
||||||
|
## Where to Add New Code
|
||||||
|
|
||||||
|
**New controller action (e.g., `/tickets/new_action/`):**
|
||||||
|
- Method: `autoload/controls/class.Tickets.php` — add `static public function new_action()`
|
||||||
|
- Template: `templates/tickets/new-action.php`
|
||||||
|
- Business logic: `autoload/factory/class.Tickets.php`
|
||||||
|
|
||||||
|
**New admin panel feature:**
|
||||||
|
- Controller: `autoload/controls/class.Apanel.php`
|
||||||
|
- Template: `templates/admin-panel/`
|
||||||
|
- Logic: `autoload/factory/class.Apanel.php`
|
||||||
|
|
||||||
|
**New module (e.g., `/reports/`):**
|
||||||
|
- Controller: `autoload/controls/class.Reports.php`
|
||||||
|
- Factory: `autoload/factory/class.Reports.php`
|
||||||
|
- View: `autoload/view/class.Reports.php` (if custom layout needed)
|
||||||
|
- Templates: `templates/reports/`
|
||||||
|
|
||||||
|
**New utility method:**
|
||||||
|
- Add to `autoload/class.S.php` as static method
|
||||||
|
|
||||||
|
**SCSS changes:**
|
||||||
|
- Edit `layout/style-scss/style.scss` — save triggers Live Sass Compiler
|
||||||
|
|
||||||
|
## Special Directories
|
||||||
|
|
||||||
|
**`orders/`:**
|
||||||
|
- Generated at runtime; not in git (should be gitignored)
|
||||||
|
- Contains QR code PNGs served directly by web server
|
||||||
|
|
||||||
|
**`.paul/`:**
|
||||||
|
- PAUL project planning files
|
||||||
|
- Committed to git as project documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Structure analysis: 2026-04-26*
|
||||||
|
*Update when directory structure changes*
|
||||||
55
.paul/codebase/testing.md
Normal file
55
.paul/codebase/testing.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Testing
|
||||||
|
|
||||||
|
**Analysis Date:** 2026-04-26
|
||||||
|
|
||||||
|
## Framework
|
||||||
|
|
||||||
|
**No automated test framework detected.**
|
||||||
|
|
||||||
|
- No PHPUnit, PHPSpec, Codeception, or Behat
|
||||||
|
- No Composer (so no dev dependencies at all)
|
||||||
|
- No `package.json` or Node.js test tooling
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
**No test directories or test files found:**
|
||||||
|
- No `tests/`, `test/`, `__tests__/` directories
|
||||||
|
- No files matching `*.test.php`, `*Test.php`, `*Spec.php`
|
||||||
|
- No `phpunit.xml`, `phpunit.xml.dist`, or similar config
|
||||||
|
|
||||||
|
## Coverage
|
||||||
|
|
||||||
|
**Zero automated test coverage.**
|
||||||
|
|
||||||
|
All validation is runtime-only:
|
||||||
|
- IP-based session security in `index.php` and `ajax.php` (security guard, not tests)
|
||||||
|
- Manual payment flow testing via Przelewy24 sandbox mode (`$settings['p24_sandbox']`)
|
||||||
|
- Test price mode: `test_price_mode_on()` sets all ticket prices to 1 PLN via secret key (`autoload/controls/class.Tickets.php`)
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
**None configured:**
|
||||||
|
- No Xdebug or pcov for coverage
|
||||||
|
- No CI/CD (no `.github/workflows/`, no `.travis.yml`, no `bitbucket-pipelines.yml`)
|
||||||
|
- No static analysis (PHPStan, Psalm)
|
||||||
|
- No linting tools
|
||||||
|
|
||||||
|
## Testing Approach in Practice
|
||||||
|
|
||||||
|
This is a legacy production system with manual testing only:
|
||||||
|
1. Developer makes changes and uploads via FTP
|
||||||
|
2. Tests manually in browser against live or sandbox payment mode
|
||||||
|
3. Przelewy24 sandbox available for payment flow testing
|
||||||
|
4. No regression protection
|
||||||
|
|
||||||
|
## Recommendations
|
||||||
|
|
||||||
|
If adding tests in future:
|
||||||
|
- PHPUnit for factory/service layer unit tests (no framework dependency to work around)
|
||||||
|
- Focus first on `autoload/factory/class.Tickets.php` — calendar logic, basket calculations
|
||||||
|
- Integration tests for payment webhook handler (`przelewy24_response()`)
|
||||||
|
- Bootstrap challenge: globals (`$mdb`, `$settings`) need to be injectable for testability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Testing analysis: 2026-04-26*
|
||||||
Reference in New Issue
Block a user