# Laravel Backend Implementation for NanoBuild

This guide provides the complete source code files and setup steps to build the Laravel API server to interact with the replicated **NanoBuild** WordPress plugin.

---

## 1. Setup Instructions

If you haven't created a Laravel project yet, run the following commands:
```bash
# Create a new Laravel project
composer create-project laravel/laravel nanobuild-server

# Navigate into the project directory
cd nanobuild-server

# Set up your .env database variables
# DB_DATABASE=nanobuild
# DB_USERNAME=root
# DB_PASSWORD=
```

---

## 2. API Routes (`routes/api.php`)

Add the following API route group to handle the incoming requests from the NanoBuild plugin:

```php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\LicenseController;
use App\Http\Controllers\Api\FeedbackController;

Route::prefix('v1')->group(function () {
    // Feedback and survey submission
    Route::post('/feedback', [FeedbackController::class, 'store']);
    
    // License activations and verifications
    Route::post('/activate', [LicenseController::class, 'activate']);
    Route::post('/verify', [LicenseController::class, 'verify']);
    Route::post('/deactivate', [LicenseController::class, 'deactivate']);
});
```

---

## 3. Database Migrations

Run these commands to generate migrations, then paste the corresponding contents:
```bash
php artisan make:migration create_licenses_table
php artisan make:migration create_license_activations_table
php artisan make:migration create_feedbacks_table
```

### `create_licenses_table.php`
```php
<?php

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('licenses', function (Blueprint $table) {
            $table->id();
            $table->string('license_key')->unique();
            $table->enum('status', ['active', 'suspended', 'expired'])->default('active');
            $table->string('tier')->default('free');
            $table->boolean('is_lifetime')->default(false);
            $table->integer('max_sites')->default(1);
            $table->timestamps();
        });
    }

    public function down(): void {
        Schema::dropIfExists('licenses');
    }
};
```

### `create_license_activations_table.php`
```php
<?php

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('license_activations', function (Blueprint $table) {
            $table->id();
            $table->foreignId('license_id')->constrained('licenses')->onDelete('cascade');
            $table->string('site_id')->nullable();
            $table->string('site_url');
            $table->string('wp_version')->nullable();
            $table->string('php_version')->nullable();
            $table->timestamp('activated_at')->useCurrent();
        });
    }

    public function down(): void {
        Schema::dropIfExists('license_activations');
    }
};
```

### `create_feedbacks_table.php`
```php
<?php

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('feedbacks', function (Blueprint $table) {
            $table->id();
            $table->string('form_type'); // 'share' or 'deactivation'
            $table->string('plugin_tier')->default('free');
            $table->string('plugin_version');
            $table->string('site_url');
            $table->text('message')->nullable();
            $table->string('email')->nullable();
            $table->string('name')->nullable();
            $table->string('reason')->nullable();
            $table->integer('days_installed')->nullable();
            $table->json('env_snapshot')->nullable();
            $table->timestamps();
        });
    }

    public function down(): void {
        Schema::dropIfExists('feedbacks');
    }
};
```

---

## 4. Eloquent Models

Create models for your tables:
```bash
php artisan make:model License
php artisan make:model LicenseActivation
php artisan make:model Feedback
```

### `app/Models/License.php`
```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class License extends Model {
    protected $fillable = [
        'license_key',
        'status',
        'tier',
        'is_lifetime',
        'max_sites',
    ];

    public function activations(): HasMany {
        return $this->hasMany(LicenseActivation::class);
    }
}
```

### `app/Models/LicenseActivation.php`
```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class LicenseActivation extends Model {
    public $timestamps = false;
    protected $dates = ['activated_at'];

    protected $fillable = [
        'license_id',
        'site_id',
        'site_url',
        'wp_version',
        'php_version',
    ];

    public function license(): BelongsTo {
        return $this->belongsTo(License::class);
    }
}
```

### `app/Models/Feedback.php`
```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Feedback extends Model {
    protected $table = 'feedbacks';

    protected $fillable = [
        'form_type',
        'plugin_tier',
        'plugin_version',
        'site_url',
        'message',
        'email',
        'name',
        'reason',
        'days_installed',
        'env_snapshot',
    ];

    protected $casts = [
        'env_snapshot' => 'array',
    ];
}
```

---

## 5. API Controllers

Create your controllers to parse incoming API requests:
```bash
php artisan make:controller Api/FeedbackController
php artisan make:controller Api/LicenseController
```

### `app/Http/Controllers/Api/FeedbackController.php`
```php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Feedback;

class FeedbackController extends Controller {
    public function store(Request $request) {
        $validated = $request->validate([
            'form_type'      => 'required|string|in:share,deactivation',
            'plugin_tier'    => 'required|string',
            'plugin_version' => 'required|string',
            'site_url'       => 'required|url',
            'message'        => 'nullable|string',
            'email'          => 'nullable|email',
            'name'           => 'nullable|string',
            'reason'         => 'nullable|string',
            'days_installed' => 'nullable|integer',
            'env_snapshot'   => 'nullable|array',
        ]);

        Feedback::create($validated);

        return response()->json([
            'ok'      => true,
            'message' => 'Feedback logged successfully.',
        ]);
    }
}
```

### `app/Http/Controllers/Api/LicenseController.php`
```php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\License;
use Illuminate\Support\Str;

class LicenseController extends Controller {
    public function activate(Request $request) {
        $request->validate([
            'key'      => 'required|string',
            'site_url' => 'required|url',
        ]);

        $license = License::where('license_key', $request->key)->first();

        if (!$license || $license->status !== 'active') {
            return response()->json([
                'ok'         => false,
                'error_code' => 'invalid_license',
                'message'    => 'License key is invalid or inactive.',
            ], 403);
        }

        $activeCount = $license->activations()->count();
        if ($activeCount >= $license->max_sites) {
            return response()->json([
                'ok'         => false,
                'error_code' => 'limit_reached',
                'message'    => 'This license key has reached its site activation limit.',
            ], 403);
        }

        $siteId = (string) Str::uuid();
        $license->activations()->create([
            'site_id'     => $siteId,
            'site_url'    => $request->site_url,
            'wp_version'  => $request->wp_version,
            'php_version' => $request->php_version,
        ]);

        return response()->json([
            'ok'      => true,
            'status'  => 'active',
            'site_id' => $siteId,
            'message' => 'License activated.',
        ]);
    }

    public function verify(Request $request) {
        $request->validate([
            'key'     => 'required|string',
            'site_id' => 'required|string',
        ]);

        $license = License::where('license_key', $request->key)->first();
        if (!$license || $license->status !== 'active') {
            return response()->json([
                'ok'         => false,
                'error_code' => 'invalid_license',
                'message'    => 'License key is invalid.',
            ], 403);
        }

        $activation = $license->activations()->where('site_id', $request->site_id)->first();
        if (!$activation) {
            return response()->json([
                'ok'         => false,
                'error_code' => 'not_activated',
                'message'   => 'This site has not been activated with this license key.',
            ], 403);
        }

        return response()->json([
            'ok'          => true,
            'status'      => 'active',
            'is_lifetime' => (bool) $license->is_lifetime,
            'message'     => 'License verified.',
        ]);
    }

    public function deactivate(Request $request) {
        $request->validate([
            'key'     => 'required|string',
            'site_id' => 'required|string',
        ]);

        $license = License::where('license_key', $request->key)->first();
        if ($license) {
            $license->activations()->where('site_id', $request->site_id)->delete();
        }

        return response()->json([
            'ok'      => true,
            'message' => 'Site deactivated successfully.',
        ]);
    }
}
```
