# Dewemoji Operations Runbook This is the single operational guide for local, staging, and production workflows. ## 1) Environment model ### Local (safe default) ```env APP_ENV=local APP_DEBUG=true APP_URL=http://127.0.0.1:8000 DB_CONNECTION=sqlite DEWEMOJI_BILLING_MODE=sandbox DEWEMOJI_LICENSE_ACCEPT_ALL=false DEWEMOJI_ALLOWED_ORIGINS=http://127.0.0.1:8000,http://localhost:8000 ``` ### Staging / Production - Use `DEWEMOJI_BILLING_MODE=live` - Configure real DB + provider credentials - Keep `DEWEMOJI_LICENSE_ACCEPT_ALL=false` For full production variable template, use `production-env.md`. ## 2) Live deployment sequence ### Pre-deploy 1. Confirm env values are set in server/Coolify. 2. Confirm webhook URLs are reachable: - `https:///v1/paypal/webhook` - `https:///webhooks/pakasir` 3. Recommended: ```env DEWEMOJI_BILLING_PENDING_COOLDOWN_SECONDS=120 ``` ### Deploy code ```bash git fetch --all git checkout main git pull origin main composer install --no-dev --optimize-autoloader ``` ### Post-deploy (required order) ```bash php artisan optimize:clear php artisan migrate --force php artisan config:cache ``` Optional: ```bash php artisan route:cache php artisan view:cache php artisan queue:restart ``` ## 3) Ensure admin access Promote existing user: ```bash php artisan tinker --execute="\App\Models\User::where('email','dewemoji@gmail.com')->update(['role'=>'admin']);" ``` Or create missing admin: ```bash php artisan tinker --execute=" \$u=\App\Models\User::firstOrCreate( ['email'=>'dewemoji@gmail.com'], ['name'=>'Dewemoji Admin','password'=>\Illuminate\Support\Facades\Hash::make('ChangeMeNow123!'),'tier'=>'free','email_verified_at'=>now()] ); \$u->role='admin'; \$u->save(); " ``` ## 4) Live smoke tests ### Core routes 1. `/` 2. `/emoji/grinning-face` 3. `/pricing` 4. `/api-docs` 5. `/support` 6. `/privacy` 7. `/terms` 8. `/robots.txt` 9. `/sitemap.xml` ### API checks ```bash BASE=https:///v1 curl -s "$BASE/health" | jq . curl -s "$BASE/categories" | jq 'keys | length' curl -s "$BASE/emojis?q=love&limit=5" | jq '.items | length' ``` ### Billing and webhook checks ```bash tail -n 200 storage/logs/laravel.log php artisan tinker --execute="dump(\App\Models\WebhookEvent::latest()->take(10)->get(['id','provider','event_type','status','created_at'])->toArray());" php artisan tinker --execute="dump(\App\Models\Payment::latest()->take(10)->get(['id','provider','plan_code','status','created_at'])->toArray());" ``` ## 5) Billing runtime validation (staging) Verify these behaviors end-to-end: 1. pending cooldown lock on repeat checkout attempts (`409 pending_cooldown`) 2. resume pending payment via dashboard `Pay` 3. webhook delay handling (`pending` -> `paid` transition) 4. race/edge handling (`payment_not_pending`, `payment_expired`) Minimum assertions: - cooldown response includes `retry_after` - resume PayPal returns `mode=redirect` + `approve_url` - resume Pakasir returns `mode=qris` with expiry data ## 6) Staging SQL sync Set MySQL connection env, then run in container: ```bash cd /var/www/html php artisan migrate php artisan dewemoji:import-live-sql /var/www/html/dewemojiAPI_DB.sql --truncate ``` Sanity check: ```bash php artisan tinker --execute="echo DB::table('emojis')->count().PHP_EOL;" php artisan tinker --execute="echo DB::table('emoji_keywords')->count().PHP_EOL;" ``` Expected: emojis ~2131, emoji_keywords ~13420. ## 7) MySQL GUI access via SSH tunnel For internal-only Coolify MySQL, tunnel to container IP. Resolve MySQL container IP: ```bash MYSQL_IP=$(ssh SERVER_USER@SERVER_HOST "docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \$(docker ps --format '{{.ID}} {{.Names}}' | awk '/mysql|mariadb/{print \$1; exit}')") echo "$MYSQL_IP" ``` Create tunnel: ```bash ssh -N -L 3307:${MYSQL_IP}:3306 SERVER_USER@SERVER_HOST ``` Then connect in Sequel Ace/TablePlus using: - Host `127.0.0.1` - Port `3307` - standard DB credentials ## 8) Local provider parity test (optional) Switch local to live provider mode and verify with real keys. ```bash BASE=http://127.0.0.1:8000/v1 curl -X POST "$BASE/license/verify" -H "Content-Type: application/json" -d '{"key":""}' ``` Also test activate/deactivate cycle, then return local env to sandbox mode. ## 9) APK release dependency note App updater URLs used by the site: - `https://dewemoji.com/downloads/version.json` - `https://dewemoji.com/downloads/dewemoji-latest.apk` For detailed APK build/release flow, use `dewemoji-apk-companion-build-walkthrough.md`. ## 10) Rollback 1. Re-deploy previous known-good commit. 2. Run: ```bash php artisan optimize:clear php artisan config:cache php artisan queue:restart ``` 3. If issue is dataset-specific, switch to a known-good snapshot via admin tooling.