mirror of
https://github.com/dyzulk/trustlab-api.git
synced 2026-01-26 05:15:35 +07:00
feat: implement separate CA database with documentation and standardized workflows
This commit is contained in:
34
.agent/workflows/database-guidelines.md
Normal file
34
.agent/workflows/database-guidelines.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
description: Panduan Manajemen Database (Multi-Database Architecture)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Aturan & Panduan Database
|
||||||
|
|
||||||
|
Proyek ini menggunakan arsitektur **Multi-Database** untuk memisahkan data User/App dengan data High-Security (Certificate Authority).
|
||||||
|
|
||||||
|
## Arsitektur
|
||||||
|
|
||||||
|
1. **Main Database Connection (`mysql`)**
|
||||||
|
* **Kegunaan**: Menyimpan data aplikasi umum (`users`, `tickets`, `certificates` (leaf), dll).
|
||||||
|
* **Reset Policy**: Boleh di-reset saat development (`php artisan migrate:fresh --seed`).
|
||||||
|
* **Dependency**: Terikat dengan logic aplikasi utama.
|
||||||
|
|
||||||
|
2. **CA Database Connection (`mysql_ca`)**
|
||||||
|
* **Kegunaan**: KHUSUS untuk `ca_certificates` (Root & Intermediate CA).
|
||||||
|
* **Reset Policy**: **DILARANG RESET** sembarangan. Command `migrate:fresh` default TIDAK akan menyentuh database ini.
|
||||||
|
* **Driver**: Menggunakan `mysql` di Production (sama seperti Main DB), bukan SQLite atau D1 (kecuali ada instruksi spesifik).
|
||||||
|
|
||||||
|
## Aturan Migrasi
|
||||||
|
|
||||||
|
1. **Pembuatan Tabel Baru**:
|
||||||
|
* Tentukan tabel masuk ke kategori mana (App vs CA).
|
||||||
|
* Jika CA, gunakan `Schema::connection('mysql_ca')->create(...)`.
|
||||||
|
* Jika App, gunakan `Schema::create(...)` biasa.
|
||||||
|
|
||||||
|
2. **Data Safety**:
|
||||||
|
* Sebelum menjalankan query raw atau operasi destructive, pastikan koneksi yang dipilih benar.
|
||||||
|
* Gunakan command `php artisan ca:migrate-data` hanya jika perlu memindahkan data antar database.
|
||||||
|
|
||||||
|
## Cloudflare D1
|
||||||
|
* Saat ini D1 **TIDAK DIGUNAKAN** untuk kompatibilitas penuh dengan server berbasis VPS/Hosting standar.
|
||||||
|
* Jangan mengusulkan migrasi ke D1 kecuali infrastruktur berpindah ke Cloudflare Workers sepenuhnya.
|
||||||
51
.agent/workflows/deployment.md
Normal file
51
.agent/workflows/deployment.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
description: SOP Deployment (CI/CD via aaPanel)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Alur Kerja Deployment
|
||||||
|
|
||||||
|
Proyek ini menggunakan **CI/CD Otomatis** via aaPanel Webhook yang terintegrasi dengan GitHub/Git.
|
||||||
|
|
||||||
|
## 1. Automated Deployment (CI/CD)
|
||||||
|
|
||||||
|
Setiap kali Anda melakukan push ke branch `main`, script webhook di server akan berjalan.
|
||||||
|
**Apa yang dilakukan script otomatis:**
|
||||||
|
1. `git pull origin main`
|
||||||
|
2. `composer install` & `npm install` + `vite build`
|
||||||
|
3. **Update Config:** Mengcopy isi `.env.production.editable` ke `.env` (Pastikan file editable sudah benar di repo!).
|
||||||
|
4. `php artisan migrate --force` (Main & CA Database).
|
||||||
|
5. `php artisan optimize`.
|
||||||
|
|
||||||
|
**Script Reference:**
|
||||||
|
* **Repo (Public):** `scripts/deploy-webhook.example.sh` (Template aman, gunakan ini untuk copy-paste ke aaPanel lalu edit manual).
|
||||||
|
* **Local (Private):** `scripts/deploy-webhook.local.sh` (Backup pribadi Anda dengan path asli, ter-ignore oleh git).
|
||||||
|
|
||||||
|
## 2. Manual Pre-Requisites (Sebelum Push)
|
||||||
|
|
||||||
|
Sebelum Anda push code, pastikan:
|
||||||
|
1. **Environment Variables**:
|
||||||
|
* Jika ada perubahan config, update `.env.production.editable`.
|
||||||
|
* Ingat: Script akan menimpa `.env` server dengan isi `.env.production.editable`.
|
||||||
|
2. **Database**:
|
||||||
|
* Jika membuat DB baru (seperti kasus CA ini), pastikan database fisik sudah dibuat di server MySQL (`CREATE DATABASE ...`).
|
||||||
|
|
||||||
|
## 3. Manual Post-Deployment (Intervensi Khusus)
|
||||||
|
|
||||||
|
Script CI/CD tidak menangani edge-cases. Anda perlu masuk ke server (SSH) untuk kasus berikut:
|
||||||
|
|
||||||
|
1. **Data Migration Khusus**:
|
||||||
|
* Kasus: Memisahkan table CA ke database baru.
|
||||||
|
* Action: Login SSH, lalu jalankan:
|
||||||
|
```bash
|
||||||
|
cd /www/wwwroot/trustlab-api-ftp/trustlab-api.dyzulk.com
|
||||||
|
php artisan ca:migrate-data
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Rollback**:
|
||||||
|
* Jika deploy gagal total, Anda mungkin perlu restore backup database manual via aaPanel atau `php artisan migrate:rollback`.
|
||||||
|
|
||||||
|
## 4. Platform Lain (Non-aaPanel)
|
||||||
|
Jika berpindah dari aaPanel, adaptasi script `scripts/deploy-webhook.example.sh`:
|
||||||
|
* Ganti Path project (`PROJECT_PATH`).
|
||||||
|
* Ganti Path PHP Binary (`PHP_BIN`).
|
||||||
|
* Ganti mekanisme trigger (misal gunakan GitHub Actions, Jenkins, atau Laravel Forge).
|
||||||
48
.agent/workflows/manage-env.md
Normal file
48
.agent/workflows/manage-env.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
description: Memahami dan Mengelola Environment Variables (5-File System)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Aturan Manajemen Environment Variables
|
||||||
|
|
||||||
|
Proyek ini menggunakan sistem **5-File Environment** yang ketat untuk mencegah kesalahan konfigurasi produksi. AI dan Developer Wajib mengikuti aturan ini.
|
||||||
|
|
||||||
|
## Struktur File
|
||||||
|
|
||||||
|
1. **`.env`** (Local Development)
|
||||||
|
* Digunakan untuk pengembangan visual/lokal.
|
||||||
|
* Berisi kredensial lokal (localhost, root, dll).
|
||||||
|
* **Aturan:** Menjadi acuan utama *struktur* dan *urutan* key untuk file lainnya.
|
||||||
|
|
||||||
|
2. **`.env.example.for.local`** (Template Local)
|
||||||
|
* Template untuk developer lain.
|
||||||
|
* Struktur HARUS sama persis dengan `.env`.
|
||||||
|
* Value kosong atau default aman.
|
||||||
|
|
||||||
|
3. **`.env.example.for.production`** (Template Production)
|
||||||
|
* Gambaran konfigurasi produksi.
|
||||||
|
* Struktur HARUS sama persis dengan `.env`.
|
||||||
|
* Value disesuaikan untuk konteks produksi (misal `APP_ENV=production`, `APP_DEBUG=false`).
|
||||||
|
|
||||||
|
4. **`.env.production.editable`** (Staging/Pre-Production)
|
||||||
|
* File ini berisi konfigurasi produksi yang *siap* untuk diedit/standardisasi.
|
||||||
|
* **CRITICAL:** Struktur dan urutan key HARUS 100% sama dengan `.env`.
|
||||||
|
* Berisi kredensial RILL/ASLI dari server produksi.
|
||||||
|
|
||||||
|
5. **`.env.production.soft.copy`** (Snapshot Server - **READ ONLY**)
|
||||||
|
* Merupakan salinan langsung dari server saat ini.
|
||||||
|
* **DILARANG EDIT** file ini kecuali server aktual telah berubah.
|
||||||
|
* File ini digunakan sebagai validasi/referensi state server sekarang.
|
||||||
|
* Jangan menambahkan config baru di sini sebelum server di-update.
|
||||||
|
|
||||||
|
## Workflow Perubahan Environment
|
||||||
|
|
||||||
|
Jika Anda perlu menambahkan Variable baru (misal `DB_CA_...`):
|
||||||
|
|
||||||
|
1. **Tambahkan di `.env`** lokal terlebih dahulu.
|
||||||
|
2. **Standardisasi urutan** di `.env.production.editable` (copy struktur `.env`, lalu isi value produksi).
|
||||||
|
3. **Update Template** `.env.example.for.local` dan `.env.example.for.production`.
|
||||||
|
4. **JANGAN SENTUH** `.env.production.soft.copy` (biarkan apa adanya sampai deployment selesai dan snapshot baru diambil).
|
||||||
|
|
||||||
|
## Prompting AI
|
||||||
|
Untuk memastikan AI mengerti konteks ini, mintalah:
|
||||||
|
> "Baca aturan environment di `.agent/workflows/manage-env.md` sebelum melakukan perubahan pada file .env"
|
||||||
128
.env.example.for.local
Normal file
128
.env.example.for.local
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# This .env for example local development
|
||||||
|
APP_NAME=TrustLab
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
|
||||||
|
APP_LOCALE=en
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
# APP_MAINTENANCE_STORE=database
|
||||||
|
|
||||||
|
# PHP_CLI_SERVER_WORKERS=4
|
||||||
|
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=sqlite
|
||||||
|
# DB_HOST=127.0.0.1
|
||||||
|
# DB_PORT=3306
|
||||||
|
# DB_DATABASE=laravel
|
||||||
|
# DB_USERNAME=root
|
||||||
|
# DB_PASSWORD=
|
||||||
|
|
||||||
|
# CA DB Connection
|
||||||
|
DB_CA_CONNECTION=mysql_ca
|
||||||
|
DB_CA_HOST=127.0.0.1
|
||||||
|
DB_CA_PORT=3306
|
||||||
|
DB_CA_DATABASE=trustlab_ca
|
||||||
|
DB_CA_USERNAME=root
|
||||||
|
DB_CA_PASSWORD=
|
||||||
|
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=localhost
|
||||||
|
|
||||||
|
SANCTUM_STATEFUL_DOMAINS=localhost:3000,127.0.0.1:3000
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=reverb
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
CACHE_STORE=database
|
||||||
|
# CACHE_PREFIX=
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_CLIENT=phpredis
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=lab.dyzulk.com
|
||||||
|
MAIL_PORT=587
|
||||||
|
MAIL_USERNAME=noreply@lab.dyzulk.com
|
||||||
|
MAIL_PASSWORD=
|
||||||
|
MAIL_ENCRYPTION=tls
|
||||||
|
MAIL_FROM_ADDRESS="noreply@lab.dyzulk.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
MAIL_SUPPORT_MAILER=smtp
|
||||||
|
MAIL_SUPPORT_HOST=lab.dyzulk.com
|
||||||
|
MAIL_SUPPORT_PORT=587
|
||||||
|
MAIL_SUPPORT_USERNAME=support@lab.dyzulk.com
|
||||||
|
MAIL_SUPPORT_PASSWORD=
|
||||||
|
MAIL_SUPPORT_ENCRYPTION=tls
|
||||||
|
MAIL_SUPPORT_FROM_ADDRESS="support@lab.dyzulk.com"
|
||||||
|
MAIL_SUPPORT_FROM_NAME="${APP_NAME} Support"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
R2_ACCESS_KEY_ID=
|
||||||
|
R2_SECRET_ACCESS_KEY=
|
||||||
|
R2_BUCKET=
|
||||||
|
R2_PRIVATE_BUCKET=
|
||||||
|
R2_ENDPOINT=
|
||||||
|
R2_URL=
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
FRONTEND_URL=http://localhost:3000
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=reverb
|
||||||
|
|
||||||
|
REVERB_APP_ID=
|
||||||
|
REVERB_APP_KEY=
|
||||||
|
REVERB_APP_SECRET=
|
||||||
|
REVERB_HOST="localhost"
|
||||||
|
REVERB_PORT=8080
|
||||||
|
REVERB_SCHEME=http
|
||||||
|
|
||||||
|
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
|
||||||
|
VITE_REVERB_HOST="${REVERB_HOST}"
|
||||||
|
VITE_REVERB_PORT="${REVERB_PORT}"
|
||||||
|
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
||||||
|
|
||||||
|
GITHUB_CLIENT_ID=
|
||||||
|
GITHUB_CLIENT_SECRET=
|
||||||
|
GITHUB_REDIRECT_URI=${APP_URL}/api/auth/github/callback
|
||||||
|
|
||||||
|
GITHUB_DEV_CLIENT_ID=
|
||||||
|
GITHUB_DEV_CLIENT_SECRET=
|
||||||
|
GITHUB_DEV_REDIRECT_URI=${APP_URL}/api/auth/github/callback
|
||||||
|
|
||||||
|
GITHUB_PROD_CLIENT_ID=
|
||||||
|
GITHUB_PROD_CLIENT_SECRET=
|
||||||
|
GITHUB_PROD_REDIRECT_URI=${APP_URL}/api/auth/github/callback
|
||||||
|
|
||||||
|
|
||||||
|
GOOGLE_CLIENT_ID=
|
||||||
|
GOOGLE_CLIENT_SECRET=
|
||||||
|
GOOGLE_REDIRECT_URI=${APP_URL}/api/auth/google/callback
|
||||||
|
|
||||||
|
TELEGRAM_BOT_TOKEN=
|
||||||
|
TELEGRAM_CHAT_ID=
|
||||||
128
.env.example.for.production
Normal file
128
.env.example.for.production
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# This .env for example production
|
||||||
|
APP_NAME=TrustLab
|
||||||
|
APP_ENV=production
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_URL=https://trustlab-api.dyzulk.com
|
||||||
|
|
||||||
|
APP_LOCALE=en
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
# APP_MAINTENANCE_STORE=database
|
||||||
|
|
||||||
|
# PHP_CLI_SERVER_WORKERS=4
|
||||||
|
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=error
|
||||||
|
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=trustlab
|
||||||
|
DB_USERNAME=trustlab
|
||||||
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
# CA DB Connection
|
||||||
|
DB_CA_CONNECTION=mysql_ca
|
||||||
|
DB_CA_HOST=127.0.0.1
|
||||||
|
DB_CA_PORT=3306
|
||||||
|
DB_CA_DATABASE=trustlab_ca
|
||||||
|
DB_CA_USERNAME=
|
||||||
|
DB_CA_PASSWORD=
|
||||||
|
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=.dyzulk.com
|
||||||
|
|
||||||
|
SANCTUM_STATEFUL_DOMAINS=trustlab.dyzulk.com
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=reverb
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
CACHE_STORE=database
|
||||||
|
# CACHE_PREFIX=
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_CLIENT=phpredis
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=lab.dyzulk.com
|
||||||
|
MAIL_PORT=587
|
||||||
|
MAIL_USERNAME=noreply@lab.dyzulk.com
|
||||||
|
MAIL_PASSWORD=
|
||||||
|
MAIL_ENCRYPTION=tls
|
||||||
|
MAIL_FROM_ADDRESS="noreply@lab.dyzulk.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
MAIL_SUPPORT_MAILER=smtp
|
||||||
|
MAIL_SUPPORT_HOST=lab.dyzulk.com
|
||||||
|
MAIL_SUPPORT_PORT=587
|
||||||
|
MAIL_SUPPORT_USERNAME=support@lab.dyzulk.com
|
||||||
|
MAIL_SUPPORT_PASSWORD=
|
||||||
|
MAIL_SUPPORT_ENCRYPTION=tls
|
||||||
|
MAIL_SUPPORT_FROM_ADDRESS="support@lab.dyzulk.com"
|
||||||
|
MAIL_SUPPORT_FROM_NAME="${APP_NAME} Support"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
R2_ACCESS_KEY_ID=
|
||||||
|
R2_SECRET_ACCESS_KEY=
|
||||||
|
R2_BUCKET=
|
||||||
|
R2_PRIVATE_BUCKET=
|
||||||
|
R2_ENDPOINT=
|
||||||
|
R2_URL=
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
FRONTEND_URL=https://trustlab.dyzulk.com
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=reverb
|
||||||
|
|
||||||
|
REVERB_APP_ID=
|
||||||
|
REVERB_APP_KEY=
|
||||||
|
REVERB_APP_SECRET=
|
||||||
|
REVERB_HOST="trustlab-api.dyzulk.com"
|
||||||
|
REVERB_PORT=443
|
||||||
|
REVERB_SCHEME=https
|
||||||
|
|
||||||
|
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
|
||||||
|
VITE_REVERB_HOST="${REVERB_HOST}"
|
||||||
|
VITE_REVERB_PORT="${REVERB_PORT}"
|
||||||
|
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
|
||||||
|
|
||||||
|
GITHUB_CLIENT_ID=
|
||||||
|
GITHUB_CLIENT_SECRET=
|
||||||
|
GITHUB_REDIRECT_URI=${APP_URL}/api/auth/github/callback
|
||||||
|
|
||||||
|
GITHUB_DEV_CLIENT_ID=
|
||||||
|
GITHUB_DEV_CLIENT_SECRET=
|
||||||
|
GITHUB_DEV_REDIRECT_URI=${APP_URL}/api/auth/github/callback
|
||||||
|
|
||||||
|
GITHUB_PROD_CLIENT_ID=
|
||||||
|
GITHUB_PROD_CLIENT_SECRET=
|
||||||
|
GITHUB_PROD_REDIRECT_URI=${APP_URL}/api/auth/github/callback
|
||||||
|
|
||||||
|
|
||||||
|
GOOGLE_CLIENT_ID=
|
||||||
|
GOOGLE_CLIENT_SECRET=
|
||||||
|
GOOGLE_REDIRECT_URI=${APP_URL}/api/auth/google/callback
|
||||||
|
|
||||||
|
TELEGRAM_BOT_TOKEN=
|
||||||
|
TELEGRAM_CHAT_ID=
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,8 +2,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.env
|
.env
|
||||||
.env.backup
|
.env.backup
|
||||||
.env.example.for.local
|
|
||||||
.env.example.for.production
|
|
||||||
.env.production.editable
|
.env.production.editable
|
||||||
.env.production.soft.copy
|
.env.production.soft.copy
|
||||||
.phpactor.json
|
.phpactor.json
|
||||||
@@ -28,3 +26,4 @@ Thumbs.db
|
|||||||
*.sql
|
*.sql
|
||||||
*.sqlite
|
*.sqlite
|
||||||
.env.testing
|
.env.testing
|
||||||
|
scripts/deploy-webhook.local.sh
|
||||||
|
|||||||
80
app/Console/Commands/MigrateCaCertificates.php
Normal file
80
app/Console/Commands/MigrateCaCertificates.php
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use App\Models\CaCertificate;
|
||||||
|
|
||||||
|
class MigrateCaCertificates extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'ca:migrate-data {--f|force : Force migration even if target table is not empty}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Migrate CA data from default database to the new CA database';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$this->info('Starting CA data migration...');
|
||||||
|
|
||||||
|
// Check if source table exists
|
||||||
|
if (!DB::connection('mysql')->getSchemaBuilder()->hasTable('ca_certificates')) {
|
||||||
|
$this->error('Source table "ca_certificates" does not exist in the default connection.');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if target table is empty
|
||||||
|
$count = CaCertificate::count();
|
||||||
|
if ($count > 0 && !$this->option('force')) {
|
||||||
|
$this->error("Target table is not empty (contains $count records). Use --force to proceed.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch from old DB
|
||||||
|
$oldCerts = DB::connection('mysql')->table('ca_certificates')->get();
|
||||||
|
|
||||||
|
$this->info("Found {$oldCerts->count()} certificates to migrate.");
|
||||||
|
|
||||||
|
$bar = $this->output->createProgressBar($oldCerts->count());
|
||||||
|
$bar->start();
|
||||||
|
|
||||||
|
foreach ($oldCerts as $cert) {
|
||||||
|
// We use the Model to insert into the new DB (since it's now bound to 'mysql_ca')
|
||||||
|
// Using replicate() or manual array creation
|
||||||
|
|
||||||
|
$data = (array) $cert;
|
||||||
|
|
||||||
|
// Ensure we don't duplicate if it already exists (upsert-like behavior or strict check)
|
||||||
|
if (CaCertificate::where('uuid', $data['uuid'])->exists()) {
|
||||||
|
if ($this->option('force')) {
|
||||||
|
// Update existing
|
||||||
|
CaCertificate::where('uuid', $data['uuid'])->update($data);
|
||||||
|
} else {
|
||||||
|
// Skip
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CaCertificate::create($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bar->advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
$bar->finish();
|
||||||
|
$this->newLine();
|
||||||
|
$this->info('Data migration completed successfully.');
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ class CaCertificate extends Model
|
|||||||
public $incrementing = false;
|
public $incrementing = false;
|
||||||
protected $keyType = 'string';
|
protected $keyType = 'string';
|
||||||
|
|
||||||
|
protected $connection = 'mysql_ca';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'uuid',
|
'uuid',
|
||||||
'ca_type',
|
'ca_type',
|
||||||
|
|||||||
@@ -63,6 +63,26 @@ return [
|
|||||||
]) : [],
|
]) : [],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'mysql_ca' => [
|
||||||
|
'driver' => 'mysql',
|
||||||
|
'url' => env('DB_CA_URL'),
|
||||||
|
'host' => env('DB_CA_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_CA_PORT', '3306'),
|
||||||
|
'database' => env('DB_CA_DATABASE', 'trustlab_ca'),
|
||||||
|
'username' => env('DB_CA_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_CA_PASSWORD', ''),
|
||||||
|
'unix_socket' => env('DB_CA_SOCKET', ''),
|
||||||
|
'charset' => env('DB_CA_CHARSET', 'utf8mb4'),
|
||||||
|
'collation' => env('DB_CA_COLLATION', 'utf8mb4_unicode_ci'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => true,
|
||||||
|
'engine' => null,
|
||||||
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
|
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
]) : [],
|
||||||
|
],
|
||||||
|
|
||||||
'mariadb' => [
|
'mariadb' => [
|
||||||
'driver' => 'mariadb',
|
'driver' => 'mariadb',
|
||||||
'url' => env('DB_URL'),
|
'url' => env('DB_URL'),
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// Explicitly use the 'mysql_ca' connection
|
||||||
|
Schema::connection('mysql_ca')->create('ca_certificates', function (Blueprint $table) {
|
||||||
|
$table->string('uuid', 32)->primary();
|
||||||
|
$table->string('ca_type'); // root, intermediate_4096, intermediate_2048
|
||||||
|
$table->longText('cert_content')->nullable();
|
||||||
|
$table->longText('key_content')->nullable();
|
||||||
|
$table->string('serial_number')->nullable();
|
||||||
|
$table->string('common_name')->nullable();
|
||||||
|
$table->string('organization')->nullable();
|
||||||
|
$table->dateTime('valid_from')->nullable();
|
||||||
|
$table->dateTime('valid_to')->nullable();
|
||||||
|
|
||||||
|
// Tracking
|
||||||
|
$table->unsignedBigInteger('download_count')->default(0);
|
||||||
|
$table->timestamp('last_downloaded_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::connection('mysql_ca')->dropIfExists('ca_certificates');
|
||||||
|
}
|
||||||
|
};
|
||||||
121
scripts/deploy-webhook.example.sh
Normal file
121
scripts/deploy-webhook.example.sh
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# TRUSTLAB DEPLOYMENT SCRIPT (EXAMPLE)
|
||||||
|
# =========================================================================
|
||||||
|
# CATATAN PENTING:
|
||||||
|
# Script ini adalah CONTOH/TEMPLATE untuk digunakan di aaPanel Webhook.
|
||||||
|
# Jangan jalankan script ini langsung dari repository jika belum dikonfigurasi.
|
||||||
|
#
|
||||||
|
# CARA PAKAI DI AAPANEL:
|
||||||
|
# 1. Buka App Store > Webhook (atau Git Manager di versi baru).
|
||||||
|
# 2. Add Webhook > Script.
|
||||||
|
# 3. Copy-paste isi file ini ke dalam kolom Script di aaPanel.
|
||||||
|
# 4. SESUAIKAN variable di bawah ini dengan konfigurasi server Anda.
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
# --- 1. KONFIGURASI SERVER (WAJIB DIEDIT DI AAPANEL) ---
|
||||||
|
# Ganti dengan path project Anda yang sebenarnya
|
||||||
|
PROJECT_PATH="/www/wwwroot/your-project.com"
|
||||||
|
|
||||||
|
# Ganti dengan path PHP binary Anda (sesuai versi php)
|
||||||
|
PHP_BIN="/www/server/php/83/bin/php"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# CONFIGURATION & ENVIRONMENT (JANGAN UBAH DI BAWAH INI KECUALI PAHAM)
|
||||||
|
# =========================================================================
|
||||||
|
export HOME=/root
|
||||||
|
export COMPOSER_HOME=/root/.composer
|
||||||
|
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin
|
||||||
|
|
||||||
|
# --- CONFIG TELEGRAM ---
|
||||||
|
# Load from .env locally on server if available
|
||||||
|
if [ -f .env ]; then
|
||||||
|
export $(grep -v '^#' .env | xargs)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pastikan TELEGRAM_BOT_TOKEN dan TELEGRAM_CHAT_ID ada di .env server Anda
|
||||||
|
BOT_TOKEN="${TELEGRAM_BOT_TOKEN}"
|
||||||
|
CHAT_ID="${TELEGRAM_CHAT_ID}"
|
||||||
|
|
||||||
|
send_telegram() {
|
||||||
|
local message="$1"
|
||||||
|
if [ -n "$BOT_TOKEN" ] && [ -n "$CHAT_ID" ]; then
|
||||||
|
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
|
||||||
|
-d chat_id="$CHAT_ID" \
|
||||||
|
-d text="$message" \
|
||||||
|
-d parse_mode="HTML" > /dev/null
|
||||||
|
else
|
||||||
|
echo "⚠️ Telegram credentials missing, skipping notification."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# START DEPLOYMENT
|
||||||
|
# =========================================================================
|
||||||
|
echo "🚀 Starting Deployment..."
|
||||||
|
send_telegram "⏳ <b>Deployment Started</b>%0A%0A🚀 <b>Project:</b> TrustLab API%0A📅 <b>Date:</b> $(date)"
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Safety check directory
|
||||||
|
if [ ! -d "$PROJECT_PATH" ]; then
|
||||||
|
echo "❌ Error: Project path $PROJECT_PATH does not exist."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git config --global --add safe.directory "$PROJECT_PATH"
|
||||||
|
cd "$PROJECT_PATH"
|
||||||
|
|
||||||
|
trap 'send_telegram "❌ <b>Deployment FAILED!</b>%0A%0A⚠️ Check server logs untuk detail.%0A📅 <b>Date:</b> $(date)"; exit 1' ERR
|
||||||
|
|
||||||
|
# 3. Pull & Clean
|
||||||
|
echo "📥 Pulling latest code..."
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
echo "🧹 Cleaning untracked files..."
|
||||||
|
git clean -fd
|
||||||
|
|
||||||
|
# 4. PHP Dependencies
|
||||||
|
echo "📦 Updating Composer dependencies..."
|
||||||
|
$PHP_BIN /usr/bin/composer install --no-dev --optimize-autoloader --no-interaction
|
||||||
|
|
||||||
|
# 5. Frontend Assets
|
||||||
|
echo "📦 Building frontend assets..."
|
||||||
|
npm install
|
||||||
|
|
||||||
|
echo "🔧 Fixing permissions..."
|
||||||
|
find node_modules -type f \( -path "*/bin/*" -o -path "*/.bin/*" \) -exec chmod +x {} \;
|
||||||
|
if [ -d "node_modules/@esbuild/linux-x64/bin" ]; then
|
||||||
|
chmod +x node_modules/@esbuild/linux-x64/bin/esbuild
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf public/build
|
||||||
|
echo "🏗 Running Vite build..."
|
||||||
|
npx vite build
|
||||||
|
|
||||||
|
echo "🧹 Pruning dev dependencies..."
|
||||||
|
npm prune --omit=dev
|
||||||
|
|
||||||
|
# 6. Environment Setup
|
||||||
|
if [ -f .env.production.editable ]; then
|
||||||
|
echo "📄 Updating .env from .env.production.editable..."
|
||||||
|
cp .env.production.editable .env
|
||||||
|
elif [ ! -f .env ]; then
|
||||||
|
cp .env.production.example .env
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. Laravel Optimizations
|
||||||
|
echo "⚡ Optimizing Laravel..."
|
||||||
|
$PHP_BIN artisan optimize:clear
|
||||||
|
$PHP_BIN artisan migrate --force
|
||||||
|
|
||||||
|
# NEW: Conditional CA Data Migration
|
||||||
|
# $PHP_BIN artisan ca:migrate-data
|
||||||
|
|
||||||
|
$PHP_BIN artisan config:cache
|
||||||
|
$PHP_BIN artisan route:cache
|
||||||
|
$PHP_BIN artisan view:cache
|
||||||
|
|
||||||
|
echo "✅ Deployment SUCCESS!"
|
||||||
|
send_telegram "✅ <b>Deployment Success!</b>%0A%0A📦 <b>Project:</b> TrustLab API%0A📅 <b>Date:</b> $(date)"
|
||||||
Reference in New Issue
Block a user