CluPilotCloud/database/migrations/2026_07_26_020000_create_su...

66 lines
2.6 KiB
PHP

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* What a customer actually bought, frozen at the moment they bought it.
*
* The plan catalogue in config/provisioning.php describes what we sell TODAY.
* A customer who signed up last year bought last year's terms, and raising a
* price must never reach back into their contract. So every condition that
* matters commercially is copied here at signup and never touched again:
* price, quotas, seats, the hardware behind the plan.
*
* `term` decides the rhythm: a monthly subscription can be changed at the end
* of the month, a yearly one at the end of the year. Upgrades are the exception
* — they take effect immediately and are charged pro rata.
*/
return new class extends Migration
{
public function up(): void
{
Schema::create('subscriptions', function (Blueprint $table) {
$table->id();
$table->uuid()->unique();
$table->foreignId('customer_id')->constrained()->cascadeOnDelete();
$table->foreignId('instance_id')->nullable()->constrained()->nullOnDelete();
$table->string('plan');
$table->string('term')->default('monthly'); // monthly|yearly
// ── Snapshot: the conditions this customer is owed ──────────────
$table->unsignedInteger('price_cents'); // net, per term
$table->string('currency', 3)->default('EUR');
$table->unsignedBigInteger('quota_gb');
$table->unsignedBigInteger('traffic_gb');
$table->unsignedInteger('seats');
$table->unsignedInteger('ram_mb');
$table->unsignedInteger('cores');
$table->unsignedBigInteger('disk_gb');
$table->string('performance')->nullable();
$table->timestamp('started_at');
$table->timestamp('current_period_start');
$table->timestamp('current_period_end');
// A downgrade is scheduled, never immediate: it lands when the term
// the customer already paid for runs out.
$table->string('pending_plan')->nullable();
$table->timestamp('pending_effective_at')->nullable();
$table->string('status')->default('active'); // active|cancelled
$table->timestamp('cancelled_at')->nullable();
$table->timestamps();
$table->index(['customer_id', 'status']);
});
}
public function down(): void
{
Schema::dropIfExists('subscriptions');
}
};