Proje: OkulUp API · Hub: OkulUp API — Decisions
S3 (okulup-dev) Konfigürasyonu ve Disk Birleştirme
Karar
- Bucket:
okulup-dev— dev için. (Başlangıçta dev+staging ortak düşünüldü, prefix önerildi; staging için ayrı bucket açılacağı belli olunca prefix kullanılmadı.) - Prefix yok:
AWS_BUCKET_PREFIXenv opsiyonu kod tarafında destekleniyor (Flysystemroot) ama prod’da boş. İleride başka env aynı bucket’ı paylaşmak isterse prefix tek satır env ile aktif edilebilir. - Tek disk: Tüm kullanıcı yüklemeleri (avatar, etkinlik kapağı, duyuru/ödev/yemek menüsü/belge talebi ekleri, galeri medya, mesaj eki, takip fotosu, ödev teslim, rapor export CSV) tek
s3diskinde toplandı.'public've'local'disk artık kullanıcı içeriği için kullanılmıyor. - Erişim: Bucket public-read (tüm bucket,
Resource: arn:aws:s3:::okulup-dev/*). Resource’lardaStorage::disk('s3')->url(...)ile direkt public URL döndürülüyor. Signed URL şu an gereksiz; ileride özel veri sınıfı eklenirsetemporaryUrl()’ye geçilir.
Gerekçe
okulup-devbucket’ı dev+staging için ortak olduğundan, env’leri birbirine karıştırmamak için prefix şart. Kod seviyesinde 30+->store()/->url()çağrısı var; her birine elle prefix eklemek hata kaynağı — Flysystem'root'ile merkezi.- 4 controller daha önce
'public'(Tracking, Message, Assignment) ve'local'(ReportExport) disk kullanıyordu; mobile’dan üretilen dosyalar EB instance restart’ta kaybolacaktı. AyrıcaAssignmentSubmissionResourceveAssignmentAttachmentResourcezatenStorage::disk('s3')->url(...)döndürüyordu — controllerpublic’e yazdığı için URL’ler bozuktu. Bu refactor o bug’ı da kapattı. - Mobile native (Expo) doğrudan S3’e PUT atmıyor (API üzerinden multipart); bucket CORS şu an gerekmiyor. Presigned URL’e geçilirse şart olur.
Alternatifler (red)
- Kod-içi sabit
'test/'prefix — her controller’da elle eklemek; prod’da silmek gerekirdi. - Bucket-policy/IAM tabanlı
test/daraltma — yazma izni kısıtlardı ama->url()doğru path’i bilmediği için kod yine de prefix’lemek zorundaydı. - Per-disk birden fazla S3 config (
s3_dev,s3_staging) — env bazlı disk seçimi kod karmaşıklığı.
Etkilenen Dosyalar
config/filesystems.php—s3.root = env('AWS_BUCKET_PREFIX', '')app/Http/Controllers/Api/TrackingController.php— 2 yer'public'→'s3'app/Http/Controllers/Api/MessageController.php— 1 yerapp/Http/Controllers/Api/AssignmentController.php— 3 yerapp/Http/Controllers/Api/ReportExportController.php—'local'→'s3'app/Services/ExportService.php— 3 yer'local'→'s3'app/Http/Resources/TrackingEntryResource.php—asset('storage/...')→Storage::disk('s3')->url(...)app/Http/Resources/MessageResource.php—'public'→'s3'- Test dosyaları:
ReportExportTest,AssignmentAttachmentTest,MessageAttachmentTest—Storage::fake('local'|'public')→Storage::fake('s3') .env.example—AWS_BUCKET_PREFIXsatırı + yorum
Sunucu .env (dev EB EC2)
FILESYSTEM_DISK=s3
AWS_ACCESS_KEY_ID=<real>
AWS_SECRET_ACCESS_KEY=<real>
AWS_DEFAULT_REGION=eu-central-1
AWS_BUCKET=okulup-dev
AWS_BUCKET_PREFIX= # boş, prefix kullanılmıyor
AWS_URL= # boş; Laravel default URL üretiyor
AWS_ENDPOINT= # AWS S3 için boş (MinIO için kullanılır)
AWS_USE_PATH_STYLE_ENDPOINT=false
Önemli not: Bucket region eu-central-1. .env’de eksik bırakılırsa SDK us-east-1’e default’lar ve AuthorizationHeaderMalformed hatası verir. Bunu ilk deploy’da 30 dakika harcadık.
IAM (minimum)
Bucket-level public-read policy zaten verildiği için IAM kullanıcısına sadece yazma + silme yetkisi yeterli:
s3:PutObject, s3:GetObject, s3:DeleteObject
Resource: arn:aws:s3:::okulup-dev/*
EC2 EB instance role’üne (aws-elasticbeanstalk-ec2-role) bucket policy yönetim yetkisi yok ve gerekmiyor; bucket policy yönetimi sadece Console’dan admin user ile yapılıyor.
Sanity Check Yöntemi
php artisan tinker→Storage::disk('s3')->put('healthcheck.txt', 'ok')→ S3 console’dahealthcheck.txtgörünüyor mu?- URL’i tarayıcıda aç → AccessDenied geliyorsa Block Public Access (hem bucket hem account-level) ve bucket policy kontrol et.
- Mobile’dan avatar upload → response’taki URL tarayıcıda açılıyor mu?
Bucket Public Read Aktivasyonu (Console’dan)
- Account-level Block Public Access: S3 servisi → sol panel → “Block Public Access settings for this account” → 4 tikini de kaldır.
- Bucket-level Block Public Access: okulup-dev → Permissions → Block public access → 4 tikini kaldır.
- Bucket Policy:
{ "Version": "2012-10-17", "Statement": [{ "Sid": "PublicRead", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::okulup-dev/*" }] }
Account-level BPA’yı atlamak en sık yapılan hata — bucket-level kapatsan bile account-level açıksa hep 403 alırsın.
Related
- medya-isleme — Avatar, galeri, etkinlik kapağı işleme jobs
- veritabani-sema — file_path kolonlu tablolar
- OkulUp API — Decisions