feat(core-app): add auto-migration and session/cache tables

AppServiceProvider runs migrate --force on first request.
Sessions and cache tables created automatically in SQLite.
Removed synthetic HTTP migration approach in favour of pure
PHP service provider — cleaner, works with Octane workers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-02-06 22:56:44 +00:00
parent e5c82dab5e
commit c13b6b8b02
6 changed files with 95 additions and 0 deletions

View file

@ -123,6 +123,7 @@ CACHE_STORE=file
SESSION_DRIVER=file SESSION_DRIVER=file
LOG_CHANNEL=single LOG_CHANNEL=single
LOG_LEVEL=warning LOG_LEVEL=warning
`, appKey, env.DatabasePath) `, appKey, env.DatabasePath)
return os.WriteFile(filepath.Join(laravelRoot, ".env"), []byte(content), 0o644) return os.WriteFile(filepath.Join(laravelRoot, ".env"), []byte(content), 0o644)

View file

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace App\Providers;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\ServiceProvider;
use Throwable;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
// Auto-migrate on first boot. Single-user desktop app with
// SQLite — safe to run on every startup. The --force flag
// is required in production, --no-interaction prevents prompts.
try {
Artisan::call('migrate', [
'--force' => true,
'--no-interaction' => true,
]);
} catch (Throwable) {
// Silently skip — DB might not exist yet (e.g. during
// composer operations or first extraction).
}
}
}

View file

@ -9,6 +9,7 @@ use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__)) return Application::configure(basePath: dirname(__DIR__))
->withRouting( ->withRouting(
web: __DIR__.'/../routes/web.php', web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
) )
->withMiddleware(function (Middleware $middleware) { ->withMiddleware(function (Middleware $middleware) {
// //

View file

@ -0,0 +1,7 @@
<?php
declare(strict_types=1);
return [
App\Providers\AppServiceProvider::class,
];

View file

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
public function down(): void
{
Schema::dropIfExists('sessions');
}
};

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('cache', function (Blueprint $table) {
$table->string('key')->primary();
$table->mediumText('value');
$table->integer('expiration');
});
Schema::create('cache_locks', function (Blueprint $table) {
$table->string('key')->primary();
$table->string('owner');
$table->integer('expiration');
});
}
public function down(): void
{
Schema::dropIfExists('cache_locks');
Schema::dropIfExists('cache');
}
};