{ "version": "2.0.0", "guards": [ { "id": "GR-CORE-003", "area": "core", "reviewer": "code", "title": "Request input contract", "requirement": "MUST read input via requestInput() in pages and avoid superglobals for request data." }, { "id": "GR-CORE-007", "area": "core", "reviewer": "code", "title": "OpenAPI sync", "requirement": "MUST update docs/openapi.yaml in the same merge when API endpoints change." }, { "id": "GR-CORE-010", "area": "core", "reviewer": "code", "title": "Idempotent DB update scripts", "requirement": "Schema or data changes for existing installs MUST be shipped as idempotent SQL scripts in db/updates/ (IF NOT EXISTS, ON DUPLICATE KEY, guarded ALTER TABLE). db/init/init.sql alone is not sufficient." }, { "id": "GR-CORE-011", "area": "core", "reviewer": "code", "title": "Settings in DB, not config files", "requirement": "New application settings MUST be stored in the settings DB table. storage/runtime/settings.php is a partial hot-path cache only." }, { "id": "GR-CORE-012", "area": "core", "reviewer": "code", "title": "POST-Redirect-GET", "requirement": "Actions that successfully mutate state MUST respond with a redirect (PRG pattern). Flash messages set before redirect via Flash::set()." }, { "id": "GR-TEST-001", "area": "test", "reviewer": "code", "title": "Tests ship with new logic", "requirement": "New or changed business logic in core/Service/ MUST be accompanied by PHPUnit tests covering the happy path and at least one failure or edge case. No new public method in a Service or Gateway without a test." }, { "id": "GR-TEST-002", "area": "test", "reviewer": "code", "title": "Code must be testable", "requirement": "New code MUST use constructor injection. MUST NOT introduce static side-effects in constructors, hidden global state, or direct DB/HTTP calls outside Repository/Gateway abstractions." }, { "id": "GR-UI-014", "area": "ui", "reviewer": "code", "title": "UI state completeness", "requirement": "New user-facing views or components MUST handle four states: loading, empty, error, success. All four defined in plan before implementation. Not required for small fixes to existing UI." }, { "id": "GR-UI-LIST", "area": "ui", "reviewer": "code", "title": "List and grid standards", "requirement": "Lists MUST preserve row action column plus enter/dblclick fallback behavior. Page size options and URL/localStorage/default precedence MUST be maintained. New lists MUST use initStandardListPage()." }, { "id": "GR-UI-DETAIL", "area": "ui", "reviewer": "code", "title": "Detail page standards", "requirement": "MUST use standard detail page contracts for dirty-state and actions. MUST NOT use inline confirm handlers on standardized flows. MUST use shared list/detail partials for standardized UI blocks. New pages MUST use the established layout system. Blocks reused in 2+ pages MUST be extracted as partials (app-{context}-{purpose}.phtml)." }, { "id": "GR-UI-A11Y", "area": "ui", "reviewer": "code", "title": "Accessibility", "requirement": "MUST NOT regress a11y basics (labels, roles, keyboard focus) on touched flows. New interactive components MUST use semantic HTML, be keyboard-operable (Tab/Enter/Escape), use ARIA only where necessary, and meet WCAG 2.1 AA contrast." }, { "id": "GR-UI-I18N", "area": "ui", "reviewer": "code", "title": "Internationalization completeness", "requirement": "All user-visible strings in phtml views MUST use t('key'). Every new t() key MUST be present in ALL language files (i18n/default_de.json and i18n/default_en.json) in the same merge." }, { "id": "GR-UI-REUSE", "area": "ui", "reviewer": "code", "title": "Reuse-first (JS + CSS)", "requirement": "MUST check web/js/core/ and web/js/components/ for existing exports before adding new functions. MUST check existing CSS layers and app-* classes before writing new rules. No duplication of logic from core modules." }, { "id": "GR-UI-EXPORT", "area": "ui", "reviewer": "code", "title": "List export via core primitive", "requirement": "Grid.js list pages that offer CSV/Excel downloads MUST use the core export primitive end-to-end. Server endpoints MUST call exportRequireGetRequest(), cap rows via exportCapLimit(), stream with exportSendCsv() from core/Support/helpers/export.php, and declare columns as MintyPHP\\Service\\Export\\ExportColumn. The SAME filter-schema.php as the list's data endpoint MUST be parsed via gridParseFiltersFromSchemaFile() so exported rows match the grid under identical filters. Views MUST include templates/partials/app-list-export-dropdown.phtml in $listTitleActionsHtml and pass 'exportUrl' => endpointUrl('') in the page config (never plain lurl() — query-string survival on module routes where path != target depends on endpointUrl). Page JS MUST call initListExport({ gridConfig, exportUrl }) from /js/core/app-list-export.js. No inline fputcsv, no hand-rolled headers, no bespoke click listener." }, { "id": "GR-SEC-001", "area": "security", "reviewer": "security", "title": "CSRF on POST", "requirement": "MUST verify CSRF token on every POST endpoint in pages before processing the request body." }, { "id": "GR-SEC-002", "area": "security", "reviewer": "security", "title": "No PII/secrets in logs", "requirement": "MUST NOT write PII (email, names, UUIDs) or secrets (tokens, passwords) to logs or audit metadata without prior redaction." }, { "id": "GR-SEC-003", "area": "security", "reviewer": "security", "title": "SQL via prepared statements only", "requirement": "MUST NOT build SQL strings with user-controlled input. All queries MUST go through Repository classes using prepared statements." }, { "id": "GR-SEC-004", "area": "security", "reviewer": "security", "title": "No external CDN/remote assets", "requirement": "MUST NOT load JS, CSS, fonts from external CDNs or remote URLs. Third-party libraries MUST be vendored locally and served via assetVersion()." }, { "id": "GR-SEC-005", "area": "security", "reviewer": "security", "title": "Encryption via Crypto only", "requirement": "Encryption/decryption MUST use core/Support/Crypto.php (AES-256-GCM). No raw openssl_encrypt, no base64 as encryption, no hand-rolled crypto." }, { "id": "GR-SEC-006", "area": "security", "reviewer": "security", "title": "File uploads in storage/ only", "requirement": "User-uploaded files MUST be stored under storage/ with non-guessable identifiers. MUST NOT be written to web/. MUST be served via PHP controller with authz. MUST validate MIME + extension before storing." }, { "id": "GR-SEC-007", "area": "security", "reviewer": "security", "title": "API must not start sessions", "requirement": "API requests (api/ prefix) MUST NOT trigger Session::start(), remember-me cookie handling, or session timeout redirects." }, { "id": "GR-SEC-008", "area": "security", "reviewer": "security", "title": "Server-side authorization", "requirement": "MUST enforce authorization server-side in actions and services. UI-only permission checks are insufficient." }, { "id": "GR-SEC-009", "area": "security", "reviewer": "security", "title": "Server-side tenant scope", "requirement": "MUST enforce tenant scope server-side. Every query touching tenant-scoped data MUST filter by tenant_id. No cross-tenant data leakage." }, { "id": "GR-SEC-010", "area": "security", "reviewer": "security", "title": "Output escaping in views", "requirement": "Views (.phtml) MUST use e() for all HTML output. Raw echo is only permitted for pre-built HTML fragments from framework helpers (e.g. ARIA attributes from navActive()). Each raw echo MUST carry an inline '// raw-html-ok: reason' comment." }, { "id": "GR-CORE-LAYERS", "area": "core", "reviewer": "code", "title": "Architecture layer isolation", "requirement": "MUST enforce strict layer separation: Views render only (no DB calls), Services contain no HTML, Repositories are isolated from HTTP/session. No cross-layer violations." }, { "id": "GR-CORE-MODULE", "area": "core", "reviewer": "code", "title": "Module boundary isolation", "requirement": "Modules MUST use MintyPHP\\Module\\* namespaces, declare valid manifests conforming to the schema, register providers correctly, prefix session keys with module..*, and pass per-module isolation tests." }, { "id": "GR-CORE-META", "area": "core", "reviewer": "code", "title": "Agent and codex system integrity", "requirement": "Guard catalog, enforcement map, quality gates, agent references, and codex skill/docs links MUST be internally consistent. All guard/gate IDs MUST resolve. No orphaned or broken references." }, { "id": "GR-UI-TAXONOMY", "area": "ui", "reviewer": "code", "title": "Status taxonomy consistency", "requirement": "Status enums, filter schemas, data-layer constants, and UI labels MUST stay in sync across all layers. No literal status strings outside taxonomy enums." } ] }