refactor: rename lib/ to core/ for clearer core-module separation
Rename the top-level lib/ directory to core/ so the project root immediately communicates which code is core platform and which lives in modules/. PHP namespaces (MintyPHP\*) are unchanged — only the Composer PSR-4 path mapping moves from lib/ to core/. Module-internal lib/ directories (modules/*/lib/) are untouched. Updated across the full stack: - composer.json PSR-4 mapping - bootstrap entry points (web/index.php, bin/*, tests/bootstrap.php) - tooling configs (phpstan.neon, phpunit.xml, php-cs-fixer) - 26 architecture contract tests - enforcement-policy, guard-catalog, quality-gates - all documentation (CLAUDE.md, README, 25 docs/, .agents/skills/) - bin/qa-extended.sh search paths - .claude/settings.local.json permission paths Workflow: .agents/runs/CORE-LIB-RENAME-001/ (Analyst → Planner → Executor → Code Review (4 findings fixed) → Security Review → Acceptance Test → Finalizer) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,9 +6,9 @@
|
||||
"id": "risk-security",
|
||||
"description": "Any change touching authentication, authorization, CSRF, encryption, logging redaction, file uploads, or API bootstrap/security behavior.",
|
||||
"paths": [
|
||||
"lib/Http/**",
|
||||
"lib/Service/Access/**",
|
||||
"lib/Support/Crypto.php",
|
||||
"core/Http/**",
|
||||
"core/Service/Access/**",
|
||||
"core/Support/Crypto.php",
|
||||
"pages/api/**",
|
||||
"pages/**"
|
||||
]
|
||||
@@ -17,7 +17,7 @@
|
||||
"id": "risk-data-boundary",
|
||||
"description": "Any change touching tenant-scoped data access, repository query boundaries, DB schema updates, or API contracts.",
|
||||
"paths": [
|
||||
"lib/Repository/**",
|
||||
"core/Repository/**",
|
||||
"db/updates/**",
|
||||
"db/init/init.sql",
|
||||
"docs/openapi.yaml"
|
||||
@@ -28,7 +28,7 @@
|
||||
"description": "Any change touching module manifests, module runtime wiring, module routes, module providers, or module migrations/assets.",
|
||||
"paths": [
|
||||
"modules/*/module.php",
|
||||
"lib/App/Module/**",
|
||||
"core/App/Module/**",
|
||||
"storage/runtime/pages/**",
|
||||
"web/modules/**"
|
||||
]
|
||||
@@ -37,7 +37,7 @@
|
||||
"id": "risk-cross-layer",
|
||||
"description": "Any feature/addition changing more than one architecture layer (Repository, Service, pages/templates/web, modules, config, db).",
|
||||
"paths": [
|
||||
"lib/**",
|
||||
"core/**",
|
||||
"pages/**",
|
||||
"templates/**",
|
||||
"web/**",
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"area": "test",
|
||||
"reviewer": "code",
|
||||
"title": "Tests ship with new logic",
|
||||
"requirement": "New or changed business logic in lib/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."
|
||||
"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",
|
||||
@@ -125,7 +125,7 @@
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "Encryption via Crypto only",
|
||||
"requirement": "Encryption/decryption MUST use lib/Support/Crypto.php (AES-256-GCM). No raw openssl_encrypt, no base64 as encryption, no hand-rolled crypto."
|
||||
"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",
|
||||
|
||||
@@ -38,7 +38,7 @@ Guard IDs live in `.agents/checks/guard-catalog.json` (guards where `reviewer` =
|
||||
- `GR-SEC-002` no PII or secrets in logs/audit metadata
|
||||
- `GR-SEC-003` all SQL via Repository with prepared statements
|
||||
- `GR-SEC-004` no external CDN or remote asset loading
|
||||
- `GR-SEC-005` encryption only via lib/Support/Crypto.php
|
||||
- `GR-SEC-005` encryption only via core/Support/Crypto.php
|
||||
- `GR-SEC-006` file uploads in storage/ only; authz-gated serving; MIME validated
|
||||
- `GR-SEC-007` API requests do not start sessions
|
||||
- `GR-SEC-008` authorization enforced server-side
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"id": "QG-004",
|
||||
"type": "fast",
|
||||
"name": "Structural rg checks",
|
||||
"command": "(rg 'new\\s+[^\\s(]+Factory\\(' lib/Service || true) | wc -l\n(rg --glob '!**/*Factory.php' 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' lib/Service || true) | wc -l\n(rg \"\\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\\(\" pages lib templates web || true) | wc -l\n(rg -n 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' pages -g '*.php' || true) | wc -l\n(rg -n '\\bDB::' pages -g '*.php' || true) | wc -l\n(rg -n 'app\\([^\\n]*Factory::class\\)->create' pages/admin -g '*.php' || true) | wc -l\n(rg -n 'Factory::class' pages/admin -g '*.php' || true) | wc -l\n(rg -n 'ApiResponse::readJsonBody\\(' pages/api/v1 -g '*.php' || true) | wc -l"
|
||||
"command": "(rg 'new\\s+[^\\s(]+Factory\\(' core/Service || true) | wc -l\n(rg --glob '!**/*Factory.php' 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' core/Service || true) | wc -l\n(rg \"\\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\\(\" pages core templates web || true) | wc -l\n(rg -n 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' pages -g '*.php' || true) | wc -l\n(rg -n '\\bDB::' pages -g '*.php' || true) | wc -l\n(rg -n 'app\\([^\\n]*Factory::class\\)->create' pages/admin -g '*.php' || true) | wc -l\n(rg -n 'Factory::class' pages/admin -g '*.php' || true) | wc -l\n(rg -n 'ApiResponse::readJsonBody\\(' pages/api/v1 -g '*.php' || true) | wc -l"
|
||||
},
|
||||
{
|
||||
"id": "QG-005",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Schichtgrenzen
|
||||
|
||||
1. MUST SQL nur in `lib/Repository/**` halten.
|
||||
2. MUST Business-Logik in `lib/Service/**` halten.
|
||||
1. MUST SQL nur in `core/Repository/**` halten.
|
||||
2. MUST Business-Logik in `core/Service/**` halten.
|
||||
3. MUST `pages/**` auf Input, Auth/AuthZ, Orchestrierung, Response begrenzen.
|
||||
4. MUST NOT Business- oder Permission-Logik in `templates/**` legen.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
1. MUST in Actions/Helpern/Templates nur `app(Foo::class)` verwenden.
|
||||
2. MUST NOT in `pages/**` direkt `new ...Service|Gateway|Repository` nutzen.
|
||||
3. MUST NOT in `lib/Service/**` (ausser `*Factory.php`) direkt `new ...Factory|Service|Gateway|Repository` nutzen.
|
||||
3. MUST NOT in `core/Service/**` (ausser `*Factory.php`) direkt `new ...Factory|Service|Gateway|Repository` nutzen.
|
||||
4. MUST NOT in `pages/admin/**` `Factory::class` referenzieren oder `app(...Factory::class)->create...` nutzen.
|
||||
|
||||
## Input / Validation
|
||||
|
||||
@@ -15,9 +15,9 @@ Policy-Hinweis:
|
||||
## Struktur-Gates (schnell)
|
||||
|
||||
```bash
|
||||
(rg 'new\s+[^\s(]+Factory\(' lib/Service || true) | wc -l
|
||||
(rg --glob '!**/*Factory.php' 'new\s+[^\s(]+(Service|Gateway|Repository)\(' lib/Service || true) | wc -l
|
||||
(rg "\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\(" pages lib templates web || true) | wc -l
|
||||
(rg 'new\s+[^\s(]+Factory\(' core/Service || true) | wc -l
|
||||
(rg --glob '!**/*Factory.php' 'new\s+[^\s(]+(Service|Gateway|Repository)\(' core/Service || true) | wc -l
|
||||
(rg "\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\(" pages core templates web || true) | wc -l
|
||||
(rg -n 'new\s+[^\s(]+(Service|Gateway|Repository)\(' pages -g '*.php' || true) | wc -l
|
||||
(rg -n '\bDB::' pages -g '*.php' || true) | wc -l
|
||||
(rg -n 'app\([^\n]*Factory::class\)->create' pages/admin -g '*.php' || true) | wc -l
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Kernregeln
|
||||
|
||||
- Architektur- und Schichtgrenzen: `/docs/explanation-architektur.md`
|
||||
- `lib/**`-Regeln und Instanziierung: `/docs/reference-lib-standards.md`
|
||||
- `core/**`-Regeln und Instanziierung: `/docs/reference-core-standards.md`
|
||||
- Kurzkonventionen: `/docs/reference-konventionen.md`
|
||||
- Request/Input/Validation: `/docs/howto-request-input-validation.md`
|
||||
|
||||
|
||||
16
CLAUDE.md
16
CLAUDE.md
@@ -54,7 +54,7 @@ docker compose exec php vendor/bin/composer-unused
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
lib/ # All backend PHP (namespace MintyPHP\)
|
||||
core/ # All backend PHP (namespace MintyPHP\)
|
||||
App/ # DI container + bootstrap (AppContainer, Container/Registrars/)
|
||||
Module/ # Module platform (Registry, Manifest, Autoloader, Builder)
|
||||
Repository/ # SQL queries, prepared statements, filters/paging
|
||||
@@ -101,13 +101,13 @@ docker/ # Dockerfiles, Nginx configs, PHP configs
|
||||
|
||||
### Strict Layering (enforce in all changes)
|
||||
|
||||
1. **App** (`lib/App/`): DI container bootstrap. Registers all service/repository factories. No business logic.
|
||||
2. **Repository** (`lib/Repository/`): All SQL lives here. No HTTP, session, or rendering.
|
||||
3. **Service** (`lib/Service/`): Business rules and validation. No HTML. Four internal sub-types:
|
||||
1. **App** (`core/App/`): DI container bootstrap. Registers all service/repository factories. No business logic.
|
||||
2. **Repository** (`core/Repository/`): All SQL lives here. No HTTP, session, or rendering.
|
||||
3. **Service** (`core/Service/`): Business rules and validation. No HTML. Four internal sub-types:
|
||||
- **Service** (`*Service.php`): Business logic + orchestration. Coordinates repositories and gateways.
|
||||
- **Gateway** (`*Gateway.php`): Adapter for a single external dependency (repository, settings, HTTP API, scope). No orchestration flow.
|
||||
- **Factory** (`*Factory.php`): Only place inside `lib/Service/` that may call `new` on services/gateways/repositories. Registers via DI container.
|
||||
- **Policy** (`*Policy.php` in `lib/Service/Access/`): Authorization decisions per resource type. Returns `AuthorizationDecision`. No HTTP, no business logic.
|
||||
- **Factory** (`*Factory.php`): Only place inside `core/Service/` that may call `new` on services/gateways/repositories. Registers via DI container.
|
||||
- **Policy** (`*Policy.php` in `core/Service/Access/`): Authorization decisions per resource type. Returns `AuthorizationDecision`. No HTTP, no business logic.
|
||||
4. **Action** (`pages/**/*.php`): Reads input, checks permissions + tenant scope, calls services, sets view vars.
|
||||
5. **View** (`pages/**/*.phtml`): Pure rendering. **No DB calls.** HTML escaping via `e(...)`.
|
||||
6. **Template** (`templates/`): Layouts and partials.
|
||||
@@ -139,7 +139,7 @@ docker/ # Dockerfiles, Nginx configs, PHP configs
|
||||
|
||||
### PHP Conventions
|
||||
|
||||
- PSR-4 autoload: `MintyPHP\` → `lib/`, `MintyPHP\Module\*` → `modules/*/lib/`, `MintyPHP\Tests\` → `tests/`
|
||||
- PSR-4 autoload: `MintyPHP\` → `core/`, `MintyPHP\Module\*` → `modules/*/lib/`, `MintyPHP\Tests\` → `tests/`
|
||||
- All user-facing text uses `t('key')` translation helper — keys must exist in all language files under `i18n/`
|
||||
- Request input via `requestInput()` — never raw `$_GET`/`$_POST`/`$_SESSION` (GR-CORE-003)
|
||||
- Permissions + tenant scope enforced in actions/services, never just in UI
|
||||
@@ -198,7 +198,7 @@ These rules are enforced by guards GR-SEC-001 through GR-SEC-010 in `.agents/che
|
||||
- No PII or secrets in logs or audit metadata (GR-SEC-002)
|
||||
- SQL only via Repository prepared statements — no inline queries (GR-SEC-003)
|
||||
- No external CDN or remote asset loading (GR-SEC-004)
|
||||
- Encryption only via `lib/Support/Crypto.php` AES-256-GCM (GR-SEC-005)
|
||||
- Encryption only via `core/Support/Crypto.php` AES-256-GCM (GR-SEC-005)
|
||||
- File uploads: `storage/` only, authz-gated serving, MIME-validated (GR-SEC-006)
|
||||
- API requests must not start sessions (GR-SEC-007)
|
||||
- Authorization enforced server-side, not just in UI (GR-SEC-008)
|
||||
|
||||
@@ -147,7 +147,7 @@ Initiale DB-Settings (Seed):
|
||||
- Geschaeftslogik bleibt in Services.
|
||||
- `pages/.../*.php` fungiert als Action-/Controller-Schicht.
|
||||
- Service-Aufloesung in Actions/Helpern ueber `app(Foo::class)`.
|
||||
- `new ...Factory()` nur im Composition Root (`web/index.php` + `lib/App/registerContainer.php`) oder in `*Factory.php`.
|
||||
- `new ...Factory()` nur im Composition Root (`web/index.php` + `core/App/registerContainer.php`) oder in `*Factory.php`.
|
||||
- `pages/**/data().php` sind GET-only (`gridRequireGetRequest()`) und normalisieren `limit`/`offset`/`order`/`dir` ueber Grid-Helper.
|
||||
- Permissions + Tenant-Scope werden in Actions/Services erzwungen.
|
||||
- Wiederkehrende UI-Bloecke als Partials zentralisieren.
|
||||
|
||||
@@ -18,10 +18,10 @@ function cliBootstrapApp(string $channel = 'cli', string $path = 'bin/cli'): App
|
||||
chdir(__DIR__ . '/..');
|
||||
require_once 'vendor/autoload.php';
|
||||
require_once 'config/config.php';
|
||||
require_once 'lib/Support/helpers.php';
|
||||
require_once 'core/Support/helpers.php';
|
||||
|
||||
/** @var AppContainer $resolved */
|
||||
$resolved = require 'lib/App/registerContainer.php';
|
||||
$resolved = require 'core/App/registerContainer.php';
|
||||
setAppContainer($resolved);
|
||||
|
||||
$container = $resolved;
|
||||
|
||||
@@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
* php bin/console list
|
||||
* php bin/console <command> --help
|
||||
*
|
||||
* Commands are auto-discovered from lib/Console/Commands/.
|
||||
* Commands are auto-discovered from core/Console/Commands/.
|
||||
* To add a new command, create a class extending Command in that directory.
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,6 @@ require_once __DIR__ . '/../vendor/autoload.php';
|
||||
use MintyPHP\Console\ConsoleApplication;
|
||||
|
||||
$app = new ConsoleApplication();
|
||||
$app->discoverCommands(__DIR__ . '/../lib/Console/Commands');
|
||||
$app->discoverCommands(__DIR__ . '/../core/Console/Commands');
|
||||
|
||||
exit($app->run($argv));
|
||||
|
||||
@@ -13,9 +13,9 @@ declare(strict_types=1);
|
||||
chdir(__DIR__ . '/..');
|
||||
require 'vendor/autoload.php';
|
||||
require 'config/config.php';
|
||||
require 'lib/Support/helpers.php';
|
||||
require 'core/Support/helpers.php';
|
||||
|
||||
$container = require 'lib/App/registerContainer.php';
|
||||
$container = require 'core/App/registerContainer.php';
|
||||
setAppContainer($container);
|
||||
|
||||
use MintyPHP\Module\Helpdesk\Service\BcODataGateway;
|
||||
|
||||
@@ -17,9 +17,9 @@ declare(strict_types=1);
|
||||
chdir(__DIR__ . '/..');
|
||||
require 'vendor/autoload.php';
|
||||
require 'config/config.php';
|
||||
require 'lib/Support/helpers.php';
|
||||
require 'core/Support/helpers.php';
|
||||
|
||||
$container = require 'lib/App/registerContainer.php';
|
||||
$container = require 'core/App/registerContainer.php';
|
||||
setAppContainer($container);
|
||||
|
||||
use MintyPHP\Module\Helpdesk\Service\HelpdeskSettingsGateway;
|
||||
|
||||
@@ -14,9 +14,9 @@ bin/qa-required.sh
|
||||
|
||||
# QG-004 (non-blocking in phase 1): structural checks as warning-only signal
|
||||
if command -v rg >/dev/null 2>&1; then
|
||||
c1="$( (rg 'new\\s+[^\\s(]+Factory\\(' lib/Service || true) | wc -l | tr -d '[:space:]')"
|
||||
c2="$( (rg --glob '!**/*Factory.php' 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' lib/Service || true) | wc -l | tr -d '[:space:]')"
|
||||
c3="$( (rg "\\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\\(" pages lib templates web || true) | wc -l | tr -d '[:space:]')"
|
||||
c1="$( (rg 'new\\s+[^\\s(]+Factory\\(' core/Service || true) | wc -l | tr -d '[:space:]')"
|
||||
c2="$( (rg --glob '!**/*Factory.php' 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' core/Service || true) | wc -l | tr -d '[:space:]')"
|
||||
c3="$( (rg "\\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\\(" pages core templates web || true) | wc -l | tr -d '[:space:]')"
|
||||
c4="$( (rg -n 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' pages -g '*.php' || true) | wc -l | tr -d '[:space:]')"
|
||||
c5="$( (rg -n '\\bDB::' pages -g '*.php' || true) | wc -l | tr -d '[:space:]')"
|
||||
c6="$( (rg -n 'app\\([^\\n]*Factory::class\\)->create' pages/admin -g '*.php' || true) | wc -l | tr -d '[:space:]')"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"MintyPHP\\": "lib/",
|
||||
"MintyPHP\\": "core/",
|
||||
"MintyPHP\\Module\\Audit\\": "modules/audit/lib/Module/Audit/",
|
||||
"MintyPHP\\Module\\Helpdesk\\": "modules/helpdesk/lib/Module/Helpdesk/"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user