Builds the /api Foundation into the base (per api/.memory/foundation-plan.md):
- app/Services/Installer.php DB test + dump.sql import + crypto keys + /api config + lock
- app/Services/Migrator.php versioned db/migrations/*.sql runner (+ migrations table)
- commands/InstallCommand.php (app:install), commands/MigrateCommand.php (db:migrate)
- app/Controllers/{JsonController,PublicController,ApiController} envelope + two-tier auth
- public/controllers/{health,admin}.php GET /api/health (public), /api/admin/ping (bearer)
- db/migrations/001_*.sql smoke migration
- install/controllers/index.php web wizard now delegates to Installer (path bugs fixed, lock)
- console + composer.json register commands / add commands to classmap
- app/src/pages/api-health-test.astro browser round-trip proof page
Verified (no DB): composer install OK; php console lists app:install + db:migrate;
PSR-4 classes autoload; CLI fails gracefully (validation, bad DB, missing config) with
no artifacts left; app builds 14 pages. Live DB + HTTP round-trip pending a served instance.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYHWLHihq3v9nxNwoPCKSn
69 lines
2 KiB
PHP
69 lines
2 KiB
PHP
<?php
|
|
|
|
class Index extends Controller {
|
|
|
|
function __construct() {
|
|
parent::__construct();
|
|
}
|
|
|
|
function index() {
|
|
$this->view->render(__CLASS__ .'/'. __FUNCTION__);
|
|
}
|
|
|
|
// AJAX: test the supplied DB credentials (echo 1 = ok, 0 = fail).
|
|
function checkDB(){
|
|
$host = $_POST['dbloca'];
|
|
$user = $_POST['dbuser'];
|
|
$pass = $_POST['dbpass'];
|
|
$db = $_POST['dbname'];
|
|
|
|
$dsn = "mysql:host=$host;dbname=$db;charset=utf8mb4";
|
|
$options = [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_LAZY,
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
];
|
|
|
|
try {
|
|
new PDO($dsn, $user, $pass, $options);
|
|
echo 1;
|
|
} catch (\PDOException $e) {
|
|
echo 0;
|
|
}
|
|
}
|
|
|
|
// Run the install by delegating to the shared Installer service.
|
|
// Refuses once installed; writes the correct /api config (no DOCUMENT_ROOT path bugs).
|
|
function installation() {
|
|
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
|
|
|
$installer = new \App\Services\Installer();
|
|
if ($installer->isInstalled()) {
|
|
http_response_code(403);
|
|
die('Already installed. Remove api/system/.installed to reinstall.');
|
|
}
|
|
if (!$_POST) {
|
|
header('Location: /api/install/');
|
|
die();
|
|
}
|
|
|
|
try {
|
|
$installer->run([
|
|
'url' => 'https://example.com',
|
|
'name' => 'SeedProject',
|
|
'db' => [
|
|
'host' => $_POST['dbloca'],
|
|
'name' => $_POST['dbname'],
|
|
'user' => $_POST['dbuser'],
|
|
'pass' => $_POST['dbpass'],
|
|
],
|
|
]);
|
|
} catch (\Throwable $e) {
|
|
http_response_code(500);
|
|
die('Install failed: ' . htmlspecialchars($e->getMessage()));
|
|
}
|
|
|
|
header('Location: /api/install/i/complete');
|
|
}
|
|
|
|
}
|