# Yükseltme ve geri alma

> Bir QueryProxy kurulumunu nasıl yedekler, yükseltir ve geri alırsınız; v0.3.0'a geçmeden önce okumanız gereken kırıcı değişiklikler ve migration notları.

- Dokümantasyon: Kılavuzlar
- Güncelleme: 2026-10-25
- Kaynak: https://queryproxy.com/tr/docs/yukseltme/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
QueryProxy `0.y.z` sürümlerinde: kırıcı değişiklikler herhangi bir minor
sürümde gelebilir ve [changelog](https://github.com/QueryProxy/QueryProxy/blob/main/CHANGELOG.md)
içinde listelenir. Bu sayfa olağan yükseltme adımlarını, v0.3.0'a geçerken
geçerli olan notları ve nasıl geri döneceğinizi anlatır.

## Olağan akış

Konteyner her açılışta `php artisan migrate --force` çalıştırır; yani yükseltme
veritabanını sizin yerinize migrate eder. Eski bir image başlattığınızda
migration'lar geri alınmaz. Bu yüzden geri dönmenin tek güvenilir yolu yedektir.

1. Sürümünüz ile hedef sürüm arasındaki **her sürümün aşağıdaki notlarını
   okuyun**.
2. Data volume'ü ve `DB_*` MySQL, MariaDB ya da PostgreSQL'e bakıyorsa uygulama
   veritabanını **yedekleyin**. Bkz.
   [Yedekleme ve geri yükleme](/tr/docs/yedekleme-ve-geri-yukleme/).
3. Çalıştıracağınız **image'ı doğrulayın** (bkz.
   [Image doğrulama](#image-doğrulama)).
4. **Onayları durdurun.** `pending` olanlara karar verin ya da kenara ayırın,
   çalışan talepler bitsin. Hiçbir talep `running` durumunda değilken yükseltin.
5. **Yeni image'ı çekin ve konteyneri aynı ayarlarla yeniden oluşturun.**
   `docker rm`'den önce konteynerin ayarlarını kaydetmek dahil adım adım
   komutlar [README](https://github.com/QueryProxy/QueryProxy#upgrading)
   içinde. Compose ile:
   `docker compose pull && docker compose up -d`.
6. **Doctor'ı çalıştırın** ve denetim zincirini kontrol edin:

   ```bash
   docker exec queryproxy php artisan queryproxy:doctor
   docker exec queryproxy php artisan audit:verify
   ```

Bir kurulumun tüm konteynerlerini (web, işçi, zamanlayıcı) aynı sürümde
başlatın. Eski image'daki bir işçi, yeni image'ın zaten migrate ettiği bir
veritabanıyla karşılaşırsa (ya da tersi), kimsenin test etmediği şekillerde
hata verebilir.

### Image doğrulama

Release image'ları cosign ile imzalanır (keyless) ve bir SBOM ile SLSA
provenance attestation taşır. cosign v3 ya da daha yenisini kullanın: eski
sürümler imzaları bulamaz. `0.3.1` yerine kontrol ettiğiniz sürümü yazın.

```sh
cosign verify \
  --certificate-identity-regexp '^https://github\.com/QueryProxy/QueryProxy/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  ghcr.io/queryproxy/queryproxy:0.3.1
```

İmzası doğrulanmayan bir image deploy edilmemelidir.
[Güvenlik politikası](https://github.com/QueryProxy/QueryProxy/blob/main/SECURITY.md)
SBOM'un ve provenance'ın nasıl okunacağını da gösterir.

## v0.3.0'a geçiş

0.3.0 için image yayınlanmadı (release taraması base image'daki açıklı bir
paket yüzünden durdurdu); aynı değişiklikleri taşıyan 0.3.1'i kurun. Aşağıdaki
adımlar 0.2.x'ten 0.3.1'e geçiş için geçerlidir.

v0.3.0 on yeni migration çalıştırır (bunlar
[Migration notları](#migration-notları) altında listelenir). Aşağıdaki
değişiklikler dayanıyor olabileceğiniz davranışları değiştirir; ilk dördü
kırıcıdır; yükseltmeden önce işlem gerektiren iki kırıcı değişiklik daha var: audit migration'ının
istediği [trigger yetkileri](#denetim-zinciri-yetkiler-ve-neyin-değiştirilemez-olduğu)
(yoksa migration düşer ve container başlamaz) ve
[MySQL ile MariaDB saat dilimi](#mysql-ve-mariadb-bağlantılarının-saat-dilimi).

### Chat mesajları redakte edilmiş bir SQL önizlemesi gösterir

`QUERYPROXY_CHAT_INCLUDE_SQL` artık varsayılan olarak `literals_redacted`
değerini alır: Slack ve Teams'teki SQL önizlemesi metin ve sayı literal'lerini
`?` ile değiştirir. Üç değer kabul eder:

| Değer | Önizleme |
| :-- | :-- |
| `literals_redacted` (varsayılan) | Literal'leri `?` ile değiştirilmiş SQL |
| `full` | Gönderildiği haliyle SQL (önceki davranış) |
| `none` | Chat mesajlarında SQL yok |

Eski boolean değerler hâlâ çalışır: `true` `full`, `false` `none` demektir. Bir
ifade güvenle redakte edilemediğinde önizlemede "SQL hidden" yazar.

Denetim ekranı ve denetim CSV'si artık hiçbir rol için ham SQL taşımaz: CSV
sütunu `sql` artık `sql_redacted` oldu ve Auditor, talep listesinde ve talep
detayında redakte edilmiş SQL görür. CSV sütununu adıyla okuyan betikleri
güncelleyin.

### Kullanıcılar soft-delete ile silinir, override için gerekçe gerekir

İki migration, kullanıcılarla talep geçmişinin ilişkisini değiştirir.

- `users` tablosuna `deleted_at` ve `suspended_at` eklenir.
  `query_requests.user_id` ve `reviewed_by` cascade ya da null-on-delete
  yerine `RESTRICT` olur; böylece talep geçmişi artık bir kullanıcıyla birlikte
  kaybolamaz. Kullanıcıları hard-delete eden kod ya da betikler artık foreign
  key hatası alır.
- Bir kullanıcıyı silmek soft delete'tir. Kullanıcının girişi, oturumları ile
  Slack ve Teams kimlikleri çalışmaz hale gelir ve `pending` talepleri
  otomatik iptal edilir (aktör `system` olmak üzere `request.cancelled` olarak
  denetlenir). Onaylanmış ve kuyruğa alınmış talepler etkilenmez. Silinmiş bir
  kullanıcının e-posta adresi ayrılmış kalır.
- Askıya alınmış bir kullanıcı aynı şekilde engellenir ama `pending`
  talepleri kalır; bunlara normal kurallarla karar verilir. Yöneticiler
  kullanıcıları Users ekranında askıya alır ve devam ettirir; kimse kendini
  askıya alamaz ya da silemez.
- Her kanaldaki her admin override onayı artık yazılı bir gerekçe gerektirir
  (en fazla 1000 karakter) ve gerekçe denetim günlüğüne kaydedilir. Override
  olacak bir Slack **Approve** tıklaması uygulanmaz; Slack, web gerekçe formuna
  bir bağlantıyla yanıt verir. Teams action endpoint'i de `approve` için
  `reason` kabul eder ve gerekçesiz bir override'a `422` ile yanıt verir.

Silinmiş ya da askıya alınmış herhangi bir hesap varken kullanıcı migration'ını
geri almak reddedilir; çünkü sütunları kaldırmak bu hesapları yeniden
etkinleştirir. Önce onları kaldırın ya da geri getirin.

### Yeni bağlantılar TLS ister; mevcutlar olduğu gibi kalır

v0.3.0'da oluşturduğunuz her ağ bağlantısı TLS ister ve sunucu sunmuyorsa düz
metne düşmek yerine hata verir.

| Driver | Yeni bağlantı için varsayılan |
| :-- | :-- |
| PostgreSQL | `sslmode=require`. Sertifika doğrulaması için `verify-ca` ya da `verify-full` seçin ve CA sertifikasını yapıştırın |
| MySQL / MariaDB | TLS zorunlu; sunucu sertifikası varsayılan olarak **doğrulanmaz** (self-signed sertifikalar çalışır). Doğrulamak için "Verify the server certificate" kutusunu işaretleyin ve bir CA ekleyin |
| SQL Server | `Encrypt=true`, `TrustServerCertificate=false`. Güvenilmeyen bir CA'nın sertifikası bağlantının başarısız olmasına yol açar; self-signed sertifikalar için `TrustServerCertificate`'i bilerek açın. `pdo_sqlsrv` kurulu olmalıdır |
| SQLite | TLS yok |

Yükseltmeden önce var olan bağlantılar eski davranışını korur ve bağlantı
listesinde işaretlenir: PostgreSQL "TLS not enforced" (`sslmode=prefer`)
gösterir; MySQL, MariaDB ve SQL Server "TLS: driver default" gösterir (sonuç
kurulu driver'a bağlıdır; SQL Server'da ODBC Driver 18 varsayılan olarak
şifreler, Driver 17 şifrelemez). Zorunlu kılmak için her bağlantıyı düzenleyip
TLS modunu `require` (PostgreSQL) ya da "required" (diğerleri) yapın.
`queryproxy:doctor`, TLS'i hâlâ zorunlu kılmayan bağlantıları listeler.

> **SQL Server: zorunluluk driver'a dayanır.** `Encrypt=true`, sunucu şifreleme
> sunmadığında Microsoft'un ODBC driver'ının bağlantıyı kesmesini sağlar. Bu,
> driver'ın belgelenmiş davranışıdır; QueryProxy'nin gerçekleştirdiği bir şey
> değildir ve test paketi TLS sunmayan ya da pre-login paketini değiştiren bir
> sunucuyu simüle edemez. Siz kendiniz kontrol edene kadar sunucuya giden ağ
> yoluna güvenilmez gözüyle bakın.

Migration'ı geri almak, saklanan PEM materyali dahil her bağlantının TLS
ayarlarını kaldırır.

### Teams: Workflows URL'leri artık Adaptive Card alır

`*.powerplatform.com` ve `*.logic.azure.com` (Teams Workflows) üzerindeki
webhook URL'leri artık MessageCard yerine Adaptive Card 1.5 mesajı alır.
`*.powerplatform.com`, varsayılan webhook host allowlist'ine eklenir. Action
token'lı `queryproxy` zarfı payload'ın en üst düzeyinde kalır; böylece onay
akışı çalışmaya devam eder.

> **Özel flow'lar için kırıcı.** MessageCard alanlarını (`title`, `summary`,
> `sections[0].facts`) bir `logic.azure.com` trigger'ından okuyan bir Power
> Automate flow'u artık bunları boş okur. Kartı bunun yerine
> `attachments[0].content` içinden okuyun ya da gövdeyi değiştirmeden iletmeye
> devam edin. Bkz. [Teams entegrasyonu](/tr/docs/teams-entegrasyonu/).

Eski connector URL'leri (`*.webhook.office.com` ve bu host'u
`QUERYPROXY_CHAT_WEBHOOK_ALLOWED_HOSTS`'a eklerseniz `outlook.office.com`)
hâlâ MessageCard alır; ancak Microsoft'un
[kullanımdan kaldırma duyurusu](https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/)
(14 Nisan 2026 güncellemesi), yaygınlaştırmanın 18-22 Mayıs 2026 arasında
yürüdüğünü ve ardından Office 365 Connectors'ın çalışmadığını söylüyor; eski
bir URL şimdiden çalışmıyor olabilir. Bir Workflows URL'sine geçin.

### Okumalar salt okunur bir oturumda çalışır

Bir okuma talebi artık hedef veritabanında, QueryProxy'nin belirlediği bir
statement timeout ve lock timeout ile salt okunur bir oturum içinde çalışır.
Ayrıntılar [SQL korumaları](/tr/docs/sql-korumalari/#kapsam) sayfasında. Sizin
için değişenler:

- PostgreSQL: `SELECT … FOR UPDATE` ve `FOR SHARE`, guard bunları okuma olarak
  sınıflandırsa bile okuma talebi içinde reddedilir ("tried to change data").
- MySQL ve MariaDB: salt okunur ayarı tek bir transaction'a değil, oturuma
  uygulanır. Bu yüzden örtük commit yapan bir ifade (`TRUNCATE` ya da `ALTER`
  gibi) salt okunur modun dışına kaçamaz.
- SQL Server'da engine düzeyinde salt okunur oturum yoktur. Yalnızca `SELECT`
  yetkisi olan ayrı bir okuma kimlik bilgisi kullanın (bkz.
  [Yapılandırma](/tr/docs/yapilandirma/#okuma-kimlik-bilgileri-ve-zaman-aşımları)).
- Bir ifade başladıktan sonra QueryProxy ağ kopmasının ardından artık otomatik
  yeniden bağlanmaz. Kısa bir kopma, çalıştırmayı sessizce yeni bir oturumda
  yeniden koşturmak yerine başarısız kılar.

### Bağlantı slot'ları

Aynı anda bir hedef bağlantıya karşı en fazla `QUERYPROXY_CONNECTION_SLOTS`
talep (varsayılan `2`) çalışır. Diğer talepler `queued` kalır ve bir slot
boşaldığında başlar. Sınırı kapatmak için `0` yapın. Tek bir bağlantıya karşı
bundan fazla işçi çalıştırıyorsanız, daha önce olmayan bir bekleme görmeyi
bekleyin.

### Hatırlatmalar

`QUERYPROXY_PENDING_REMIND_AFTER` saat boyunca (varsayılan `4`, `0` kapatır)
`pending` kalan bir talep, takımın DBA'lerine ve admin'lerine portalda ve
chat'te bir kez hatırlatma gönderir. Talepler asla süresi dolup düşmez.
Zamanlayıcı hatırlatma kontrolünü her 15 dakikada bir çalıştırır; bu yüzden
zamanlayıcıyı çalışır durumda tutun.

### Maskeleme

- `hash` stratejisi kullanımdan kaldırılmıştır ve arayüzde böyle etiketlenir.
  Yeni `hmac` stratejisi takım başına bir anahtar kullanır; bkz.
  [Veri maskeleme](/tr/docs/veri-maskeleme/).
- Yerleşik kart numarası regex'i, yeni varsayılan kural setlerinde bir Luhn
  validator kuralıyla değiştirilir. Mevcut takımlar eski kuralı korur;
  "Add default rules" Luhn kuralını onun yanına ekler. İkisine de ihtiyacınız
  kalmayınca eskisini silin.
- TCKN içerik validator'ı artık bir harfe ya da alt çizgiye yapışık rakam
  dizisini (`TC10000000146`) aday saymaz. Adı belli bir sütun yine sütun
  kuralıyla yakalanır.

### MySQL ve MariaDB bağlantılarının saat dilimi

`config/database.php` artık uygulama veritabanının `mysql` ve `mariadb`
bağlantılarını `+00:00`'a sabitler. `TIMESTAMP` sütunları UTC olarak saklanır
ve oturumun saat diliminde gösterilir. Şimdiye kadar oturum veritabanı
sunucusunun saat dilimini kullanıyordu; bu yüzden UTC'ye ayarlı olmayan bir
sunucuda, yükseltmeden sonra mevcut her `TIMESTAMP` değeri (`created_at`,
`updated_at` ve tüm tablolardaki `*_at` sütunları) sunucunun UTC farkı kadar
kaymış gösterilir. UTC+3'teki bir sunucu değerleri 3 saat önce, UTC-5'teki bir
sunucu 5 saat sonra gösterir. `Europe/Berlin` gibi adlandırılmış bir bölgede
kayma yaz saati uygulamasını izler. `DATETIME` sütunları etkilenmez ve zaten
UTC'de çalışan sunucular hiçbir değişiklik görmez.

Yükseltmeden önce ayarı kontrol edin:

```sql
SELECT @@global.time_zone, @@session.time_zone, @@system_time_zone,
       TIMEDIFF(NOW(), UTC_TIMESTAMP());
```

Varsayılan bir kurulum her iki saat dilimi değişkeni için `SYSTEM` bildirir;
bu yüzden son sütuna bakın: `00:00:00` dışındaki herhangi bir sonuç sunucunun
UTC'de olmadığı ve aşağıdaki kaymanın geçerli olduğu anlamına gelir. (`NOW()`
oturumun saat dilimini kullanır; bunu sade bir oturumda çalıştırın.)

Denetim hash zinciri bu sabitlemeye bağlıdır: `audit_logs.created_at` UTC duvar
saati olarak hash'lenir ve değişmeden geri okunmalıdır.

Açık chat onay token'ları (`chat_approval_tokens.expires_at`, 24 saat ömürlü)
da etkilenir. UTC+N bir sunucuda N saat erken sona erer ve N saatten az ömrü
kalmış bir token hemen geçersiz olur; UTC-N bir sunucuda N saate kadar daha
uzun yaşarlar. Yükseltmeden sonra verilen token'lar kesindir. İki etkiden
kaçınmak için, yükseltmeden önce açık token'ları silin; bu durumda ilgili
talepler yeni bir chat mesajına ihtiyaç duyar (hatırlatma yeni token'lı bir
kartı yeniden gönderir):

```sql
DELETE FROM chat_approval_tokens WHERE used_at IS NULL;
```

### Denetim zinciri: yetkiler ve neyin değiştirilemez olduğu

Denetim migration'ı bir hash zinciri ve `audit_logs` üzerinde `UPDATE` ile
`DELETE`'i (PostgreSQL'de `TRUNCATE`'i de; MySQL ve MariaDB trigger'ları bunu
engelleyemez) reddeden veritabanı trigger'ları ekler. Trigger oluşturmak,
migration kullanıcısının sahip olması gereken yetkileri gerektirir:

- MySQL ve MariaDB: `TRIGGER` yetkisi. Binary logging açıksa ayrıca `SUPER` ya
  da `log_bin_trust_function_creators=1`; aksi halde migration 1419 hatasıyla
  başarısız olur.
- PostgreSQL: tablonun sahipliği.

Mevcut denetim kayıtları migration sırasında ilkinden başlayarak zincirlenir.
Migration kısmi bir başarısızlıktan sonra yeniden çalıştırılabilir. Bkz.
[Denetim zinciri ve SIEM dışa aktarımı](/tr/docs/denetim-kaydi-ve-siem/).

### Dosyadan secret'lar

`APP_KEY`, `APP_PREVIOUS_KEYS`, `DB_PASSWORD`, `MAIL_PASSWORD`,
`REDIS_PASSWORD`, `SLACK_BOT_USER_OAUTH_TOKEN`, `QUERYPROXY_ADMIN_PASSWORD`,
`QUERYPROXY_METRICS_TOKEN` ve `QUERYPROXY_SIEM_WEBHOOK_SECRET` değişkenlerinin
her biri artık aynı adın `_FILE` son ekli haliyle bir dosyadan gelebilir. Bkz.
[Yapılandırma](/tr/docs/yapilandirma/#dosyadan-sırlar).

### Siz açana kadar kapalı olan yeni özellikler

`/metrics` ([İzleme](/tr/docs/izleme/)), SIEM sink'leri
([Denetim zinciri ve SIEM dışa aktarımı](/tr/docs/denetim-kaydi-ve-siem/)) ve
`queryproxy:doctor`, onları yok sayan kurulumlara ek iş yüklemez. Zamanlayıcı
ise üç yeni iş kazanır: günlük bir `audit:checkpoint`, her 15 dakikada bir
`requests:remind` ve cache'e bir zaman damgası yazan bir dakikalık heartbeat
(`database` cache store'unda dakikada bir yazma).

## Migration notları

| Migration | Ekler | Geri alınca |
| :-- | :-- | :-- |
| `2026_10_19_100000_add_read_credentials_to_connections_table` | Bağlantı başına isteğe bağlı okuma kullanıcı adı ve parolası | İki sütunu da siler |
| `2026_10_20_000001_add_hash_chain_to_audit_logs_table` | Hash zinciri, kilit tablosu, unique index'ler, trigger'lar; mevcut kayıtları zincirler | Hepsini kaldırır |
| `2026_10_20_000002_add_masking_key_to_teams_table` | Takım başına bir maskeleme anahtarı, backfill ile | Anahtarları kalıcı olarak siler; `hmac:` değerleri eşleşmez olur |
| `2026_10_21_000001_add_reminder_columns_to_query_requests_table` | `reminded_at`, `chat_renewed_at` | İkisini de siler |
| `2026_10_21_000002_add_sensitive_filter_columns_to_query_requests_table` | Sensitive-filter rozetinin okuduğu `sensitive_filter_columns` | Sütunu siler |
| `2026_10_21_000003_add_soft_delete_and_suspension_to_users_table` | `deleted_at`, `suspended_at` | Silinmiş ya da askıya alınmış hesap varken reddedilir |
| `2026_10_21_000004_protect_request_history_from_user_deletion` | `RESTRICT` foreign key'ler | Cascade ya da null-on-delete'i geri getirir |
| `2026_10_21_000005_add_backend_pid_to_query_requests_table` | Stop düğmesi için `backend_pid` | Sütunu siler |
| `2026_10_21_000006_record_tls_settings_on_connections` | Mevcut bağlantılara TLS bayrakları | Tüm TLS ayarlarını ve saklanan PEM'i kaldırır |
| `2026_10_21_000007_create_metric_samples_table` | `/metrics` sayaçları için depolama | Tabloyu siler |

## Geri alma

`migrate:rollback` değil, yedeği kullanın.

1. Konteyneri durdurun.
2. Data volume'ü ve varsa uygulama veritabanını, yükseltmeden önce aldığınız
   yedekten geri yükleyin. Komutlar
   [Yedekleme ve geri yükleme](/tr/docs/yedekleme-ve-geri-yukleme/#geri-yükleme)
   sayfasında.
3. Önceki sürüm etiketini aynı ortam dosyasıyla başlatın.

Eski bir image'ı daha yeni bir image'ın migrate ettiği veritabanına karşı
başlatmayın. Yukarıdaki her migration için `php artisan migrate:rollback`
vardır; ama attığı veri (maskeleme anahtarları, TLS ayarları, denetim zinciri)
geri gelmez ve zincir trigger'larının doğru sırayla kaldırılması gerekir.
Yedeği geri yüklemek bunların hepsinden kaçınır.

## Sonraki adımlar

- [Yedekleme ve geri yükleme](/tr/docs/yedekleme-ve-geri-yukleme/)
- [Sorun giderme](/tr/docs/sorun-giderme/)
- [Üretim güvenliği](/tr/docs/uretim-guvenligi/)
