Merge pull request 'docs: update AGENTS.md — verified against current codebase' (#33) from feat/android-v1.6.0 into master

Reviewed-on: #33
This commit was merged in pull request #33.
This commit is contained in:
2026-06-09 19:49:58 -04:00

View File

@@ -5,6 +5,7 @@ Repo-specific guidance for OpenCode sessions. Verified against code.
## Stack
- PHP 8.3+, custom MVC (not Laravel), MySQL/MariaDB, phpseclib 3.0, phpdotenv
- Autoload: PSR-4 `ServerManager\``src/`; `src/Helpers/functions.php` auto-loaded
- Android companion app at `android/` (Jetpack Compose, Material3, Retrofit, Kotlinx Serialization)
## Entry point
`public/index.php``App::boot()``App::run()``Router::dispatch()`
@@ -15,19 +16,34 @@ Repo-specific guidance for OpenCode sessions. Verified against code.
- `php bin/monitor.php` — collect server metrics (runs via cron every minute)
- `sudo bash install.sh` — full Ubuntu 22.04+/24.04+ install (needs sudo)
- `mysql servermanager < database/migrations/001_initial_schema.sql` — db setup
- `export ANDROID_HOME=/opt/android-sdk && cd android && ./gradlew assembleDebug` — build APK → `public/sysadmin.apk`
## Non-obvious conventions
- Route params use `:id` syntax (`/servers/:id`), not `{id}`
- Route params use `:id` syntax (`/servers/:id`), not `{id}`. Patterns: `:id``(\d+)`, `:slug``([a-zA-Z0-9\-]+)`
- Router supports method spoofing via `_method` POST field
- Session name is `SM_SESSION`; sessions stored server-side in `sessions` table
- View engine: custom PHP templates (`extract()` + `include`), not Twig/Blade
- SSH credentials encrypted with AES-256-CBC; master key at `/etc/servermanager/master.key`
- `.gitignore` line `/ vendor/` has a leading space → does NOT ignore `vendor/` (it's tracked)
- `vendor/` is properly gitignored now (`/vendor/` in `.gitignore`, no leading space)
- Android build outputs ignored: `android/.gradle/`, `android/build/`, `android/app/build/`, `android/local.properties`
- Bump `versionCode` and `versionName` in `android/app/build.gradle.kts` on every code change to the Android app
## Security
- Master encryption key required at runtime (`MASTER_ENCRYPTION_KEY` env or `/etc/servermanager/master.key`)
- Every credential access logged at `warning` level in audit trail
- Passwords hashed with Argon2id
## Backend gotchas
- `View::json()` has `: never` return type — calls `exit` immediately. Do not put code after it expecting to run.
- `AuditService::log(string $action, string $entityType, ?int $entityId, ?array $details = null, ?array $metadata = null)` — requires **3** positional args minimum. Calling with 2 args causes Error 500.
- `RoleMiddleware` defaults to `'admin'` required level. Hierarchy: `super_admin` (3) > `admin` (2) > `operator` (1).
- Role helper functions in views: `is_super_admin()`, `is_admin()`, `is_operator()`
- CSRF: middleware checks `$_POST['_csrf_token']` then `$_SERVER['HTTP_X_CSRF_TOKEN']`. Token expiry 7200s default.
- API routes have **no middleware** (auth is manual via `$this->authenticateRequest()` in controller). Web routes use `AuthMiddleware` / `RoleMiddleware` / `CSRFMiddleware`.
- Admin group routes (`/admin/*`) already include `AuthMiddleware` + `RoleMiddleware`; individual routes add `CSRFMiddleware`.
- Rate limiting on `POST /login` only (via `RateLimitMiddleware`)
- Every credential access must be logged at `warning` level via `AuditService`
## Database
- Migrations run manually: `mysql servermanager < database/migrations/NNN_name.sql`
- 5 migrations: `001_initial_schema`, `002_server_access`, `003_teams`, `004_soft_deletes`, `005_app_config_and_notifications`
- Users table has `role` ENUM: `super_admin`, `admin`, `operator`
- `api_token` column on users for Bearer token auth
## Testing / CI
- **No tests, no CI, no linter, no formatter, no typechecker** exist in this repo