# ModHotels.net — Geliştirme & Deploy Runbook (FTP-only)

> Ortam: cPanel paylaşımlı hosting, **SSH yok**. Senkron: VSCode SFTP eklentisi
> (FTP, `uploadOnSave`, `/public_html`). Tüm komutlar **lokal XAMPP'ta** çalışır.

---

## 0. Lokal ortam (hazır ✅)
- PHP 8.2.12 (XAMPP), gerekli eklentiler açık: json, openssl, pdo_mysql, mbstring,
  curl, fileinfo, gd, intl, zip, tokenizer, ctype, xml. (`C:\xampp\php\php.ini` düzeltildi.)
- Composer 2.9.1, Node 24, npm 11.
- MySQL: XAMPP'ın MySQL/MariaDB servisi (phpMyAdmin ile yönetim).

**Local çalıştırma:**
```bash
composer install
cp .env.example .env && php artisan key:generate
# .env: DB_DATABASE=modhotels_local, DB_USERNAME=root, DB_PASSWORD=
php artisan migrate --seed
npm install && npm run dev      # ayrı terminalde Vite
php artisan serve               # http://127.0.0.1:8000
```

---

## 1. Web kök & güvenlik (KRİTİK)

FTP her şeyi `/public_html`'e yüklüyor. Laravel kodu (`.env`, `app/`, `vendor/`)
web kökünde **görünmemeli**. İki yol:

### Tercih A — Document Root'u değiştir (güvenli, önerilen)
cPanel → **Domains** → modhotels.net → Document Root = `public_html/public`.
- Yükleme yapısı (1:1, lokal ile aynı):
  ```
  /public_html/            → Laravel kökü (app, config, vendor, .env, routes, ...)
  /public_html/public/     → web kökü (index.php, build/, uploads/)  ← docroot
  ```
- `.env` ve kod docroot'un *üstünde* → tarayıcıdan erişilemez. ✅

### Tercih B — Docroot kilitliyse (fallback)
`/public_html/.htaccess` oluştur:
```apache
RewriteEngine On
RewriteRule ^(\.env|composer\.(json|lock)|artisan) - [F,L]
RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(.*)$ /public/$1 [L]
```
Ek olarak `app/`, `config/`, `storage/`, `database/`, `vendor/` klasörlerine
`Deny from all` içeren `.htaccess` konur. (Tercih A daha temiz — mümkünse o.)

---

## 2. İlk deploy (sıra)
1. Lokalde: `composer install --no-dev --optimize-autoloader`
2. Lokalde: `npm run build` → `public/build/` üretilir.
3. `.env.production` hazırla (aşağıdaki değerlerle), sunucuda `.env` olarak yükle.
4. FTP ile **tüm proje** yüklenir (vendor/ dahil; `node_modules/` ignore).
5. cPanel MySQL: veritabanı + kullanıcı oluştur, `.env`'e yaz.
6. Şema: **Bölüm 3**'teki yöntemle migration çalıştır.
7. `storage/` ve `bootstrap/cache/` yazılabilir (755/775) olmalı.
8. `public/uploads/` klasörü var ve yazılabilir olmalı (yükleme hedefi).

### `.env` (production) anahtarları
```
APP_ENV=production
APP_DEBUG=false
APP_URL=https://modhotels.net
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=modhotels_xxx
DB_USERNAME=modhotels_xxx
DB_PASSWORD=********
CACHE_STORE=file
SESSION_DRIVER=database
QUEUE_CONNECTION=database
FILESYSTEM_DISK=public
MAIL_MAILER=smtp        # cPanel SMTP
```

---

## 3. Sunucuda migration (kabuk yok)

### Yöntem 1 — phpMyAdmin (basit, güvenli)
Lokalde şema+seed SQL'i üret, cPanel phpMyAdmin'den import et:
```bash
# lokalde
php artisan migrate:fresh --seed
mysqldump -u root modhotels_local > deploy/schema.sql   # phpMyAdmin > Import
```

### Yöntem 2 — Token korumalı web-route (kolay güncelleme)
`routes/web.php` içinde, `.env`'deki `DEPLOY_TOKEN` ile korunan bir route:
```php
Route::get('/__deploy/{action}', function (string $action, Request $r) {
    abort_unless($r->query('token') === config('app.deploy_token'), 403);
    abort_unless(in_array($action, ['migrate','seed','cache-clear','storage-link']), 404);
    return match ($action) {
        'migrate'      => Artisan::call('migrate', ['--force' => true]),
        'seed'         => Artisan::call('db:seed', ['--force' => true]),
        'cache-clear'  => Artisan::call('optimize:clear'),
    } === 0 ? 'OK: '.$action : 'ERR';
})->where('action', '[a-z\-]+');
```
Kullanım: `https://modhotels.net/__deploy/migrate?token=SECRET`
> Güçlü token kullan; işi bitince route'u kaldırmak istersen kaldır.

---

## 4. Günlük geliştirme akışı
1. Lokalde geliştir + `php artisan serve` ile test et.
2. Yeni migration → lokalde `migrate`, sonra sunucuda Bölüm 3 ile uygula.
3. Frontend değişikliği → `npm run build`, `public/build/` yükle.
4. PHP/Blade/config değişikliği → dosya kaydında FTP otomatik yükler (`uploadOnSave`).
5. composer paketi eklenince → `vendor/` klasörünü elle "Upload Folder" ile yükle.

> ⚠️ `uploadOnSave` yarım dosyayı canlıya gönderebilir. Riskli değişikliklerde
> eklentinin `uploadOnSave`'ini geçici kapatıp iş bitince "Upload" demek daha güvenli.

---

## 5. Güvenlik hatırlatmaları
- `.env`'i asla web köküne koyma (Tercih A bunu garanti eder).
- FTP şifresi `sftp.json`'da düz metin; repo paylaşılırsa **değiştir**. Mümkünse cPanel'de **SFTP (port 22)**'ye geç.
- `APP_DEBUG=false` (production).
- `DEPLOY_TOKEN` uzun ve rastgele olsun.
