docs(codebase): add codebase map — stack, architecture, structure, schema, conventions, testing, integrations, concerns

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 17:57:19 +02:00
parent 11afc80a7b
commit 5f23ca9482
8 changed files with 903 additions and 0 deletions

View File

@@ -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*