·7 dk okuma
UpFinance: Borsa İstanbul Yatırımcıları İçin Yeni Nesil Sepet Tabanlı Portföy Yönetim Platformu
Sepet mimarisi, slot sistemi, canlı piyasa verileri, temel analiz kartları, Vercel + Ubuntu + Supabase üçlüsü — UpFinance'i 5 kişilik ekiple nasıl inşa ettik ve canlıya aldık.
Giriş: Neden Böyle Bir Platforma İhtiyaç Duyduk?
Borsa İstanbul'da (BİST) işlem yapan bireysel yatırımcıların en büyük sorunu şu: aracı kurum uygulamaları hisseleri sadece düz bir liste halinde gösteriyor. Uzun vadeli temettü hisseleriniz ile kısa vadeli trade pozisyonlarınız aynı ekranda karışık duruyor. Hangi stratejinin kârda, hangisinin zararda olduğunu anlamak neredeyse imkansız.
İşte bu eksiklik, UpFinance projesinin doğuşuna zemin hazırladı. Yatırımlarınızı "sepet" mantığıyla grupladığınız, her sepete sanal sermaye atadığınız, alım-satım yaptığınız ve performansı gerçek zamanlı takip ettiğiniz profesyonel bir portföy yönetim platformu.
🔗 Proje şu anda canlıda: upfinance-seven.vercel.app
Akademik çerçeve: UpFinance, İstanbul Gedik Üniversitesi Bilgisayar Mühendisliği BLM304 Yazılım Mühendisliği dersi kapsamında hazırlanan prototip raporu ile de akademik olarak belgelenmiştir.
👥 Ekip: Rüya Takım
Böylesine kapsamlı bir platformu hayata geçirmek kesinlikle tek kişilik bir şov değil, muazzam bir takım oyunuydu:
-
Yahya Baltacı — Product Owner: Projenin fikir babası. Piyasadaki eksikliği ilk teşhis eden, yatırımcıların tam olarak hangi metrikleri görmek istediğini belirleyerek UpFinance'in rotasını ve iş mantığını kurgulayan isim.
-
Yusuf Enes Öztürk — Project Manager: Projenin kalbinin ritmini tutan yöneticimiz. Agile/Scrum süreçlerini yönetti, riskleri öngördü ve biz geliştiricilerin tamamen koda odaklanabilmesi için kusursuz bir çalışma ortamı yarattı.
-
Samet Güçlü (Ben), Melih Uyanık, Ahmet Aydın — Full Stack Developers: Mühendislik kasını oluşturan çekirdek geliştirme ekibi. Veritabanı mimarisinden API uç noktalarına, UI komponentlerinden canlı veri entegrasyonuna kadar her satır kodu omuz omuza yazdık.
Benim bu ekip içindeki kişisel odak alanlarım: sepet işlem ekranı (sepet-islem), alım-satım akışı, UI/UX tasarımı ve canlı piyasa verisi entegrasyonu. Özellikle kullanıcının bir hisse alıp sattığında bakiyenin anlık düşmesi, slot ilerleme çubuğunun hareket etmesi, hisse listesinin güncellenmesi gibi sayfa yenilenmeden gerçekleşen eşzamanlı DOM güncellemelerinin pürüzsüz çalışmasını sağlamak benim sorumluluğumdaydı.
🏗️ Mimari: Üç Sac Ayağı
Finansal bir web uygulamasının yavaş çalışma veya çökme lüksü yoktur. Mimariyi üç ana katmana oturttuk:
1. Frontend — Vercel
Vanilla JS, HTML ve CSS ile geliştirdiğimiz karanlık tema destekli arayüzü Vercel üzerinden deploy ediyoruz. GitHub'a push ettiğimiz her commit anında production'a alınıyor — kesintisiz CI/CD.
Vercel'deki vercel.json konfigürasyonu ile /api/* istekleri Ubuntu backend'e yönlendiriliyor, statik dosyalar doğrudan Vercel CDN'den servis ediliyor:
{
"routes": [
{ "src": "/api/(.*)", "dest": "http://130.61.104.4:5500/api/$1" },
{ "src": "/(.*\\.(html|js|css|json))", "dest": "/web/$1" },
{ "src": "/", "dest": "/web/index.html" }
]
}
2. Backend — Ubuntu Sunucu (Python)
Arka planda 1048 satırlık server.py çalışıyor. Bu sunucu:
- Fiyat proxy'si: TradingView Scanner API üzerinden BİST hisse fiyatlarını çekiyor (3 saniye cache TTL)
- Sembol keşfi: TradingView'dan tüm BİST hisselerini tarayıp
symbols_cache.json'a kaydediyor (24 saat TTL) - Temel analiz pipeline'ı: Investing.com scraping + TradingView fallback ile F/K, FAVÖK, PD/DD, EPS gibi metrikleri günlük otomatik yeniliyor
- Piyasa durumu: Türkiye tatil takvimi API'si + seans override dosyası ile borsa açık/kapalı durumunu hesaplıyor
- Grafik verisi: Yahoo Finance chart endpoint'ini proxy'liyor (1G/1H/1A/1Y/Tüm Zamanlar)
3. Veritabanı — Supabase (PostgreSQL)
Supabase bize şunları sağlıyor:
- Auth: Kullanıcı kayıt, giriş, şifre sıfırlama
- PostgreSQL: Sepetler, işlemler, profiller, eğitim içerikleri, sözlük terimleri
- RLS (Row Level Security): Her kullanıcı sadece kendi verilerini görebiliyor
- GitHub Actions CI/CD: Migration'lar otomatik olarak production'a push ediliyor
💼 Çözdüğümüz Temel Problem: Sepet Mimarisi
UpFinance'in kalbinde sepet (basket) kavramı yatıyor. Her sepet aslında bağımsız bir sanal portföy:
- Maksimum 5 sepet oluşturulabilir
- Her sepete 1.000 – 1.000.000 ₺ arası başlangıç sermayesi atanıyor
- İçinde bağımsız alım-satım yapılıyor
- Her sepet kendi kâr/zarar performansını ayrı takip ediyor
Slot Sistemi ve Soft Delete
En ilginç iş mantıklarından biri slot sistemi. Bir sepeti sildiğinizde o slot hemen geri gelmiyor — 30 gün bekleme süresi var. Bu, kullanıcıların düşünmeden sepet silip oluşturmasını engelliyor:
-- Enforce max 5 baskets per user (active + recently deleted)
CREATE OR REPLACE FUNCTION public.enforce_basket_limit()
RETURNS trigger AS $$
DECLARE slot_count integer;
BEGIN
SELECT count(*) INTO slot_count
FROM public.baskets
WHERE user_id = NEW.user_id
AND (deleted_at IS NULL OR deleted_at > now() - interval '30 days');
IF slot_count >= 5 THEN
RAISE EXCEPTION 'Maksimum 5 sepet. Silinen sepetlerin hakkı 30 gün sonra gelir.';
END IF;
RETURN NEW;
END; $$;
Silme işlemi gerçek silme değil, soft delete — deleted_at timestamp'i set ediliyor. Böylece işlem geçmişinin veri bütünlüğü korunuyor.
İşlem Yönetimi — JSONB
İşlemleri (alım/satım) ayrı tablo yerine sepet satırının içinde JSONB dizisi olarak tutuyoruz. Bu yaklaşımın avantajı:
- Tek bir
getBasketById()çağrısı ile sepet + tüm işlemler birlikte geliyor - JOIN gerektirmiyor, performans çok hızlı
- Her işlemin farklı dinamiğini (sembol, miktar, birim fiyat, tarih) şemayı bozmadan tutabiliyoruz
var transaction = {
id: generateId(),
type: tx.type, // 'BUY' veya 'SELL'
symbol: tx.symbol, // 'THYAO.IS'
quantity: tx.quantity, // 100
pricePerUnit: tx.pricePerUnit, // 284.50
totalAmount: totalAmount, // 28450.00
date: now()
};
📊 Canlı Piyasa Verisi Sistemi
Bu kısım benim en çok emek verdiğim alanlardan biri. Kullanıcı uygulamayı açtığında hisselerin fiyatlarını gerçek zamanlıya yakın görmesi gerekiyor.
TradingView Scanner API
Fiyatları tek tek Yahoo Finance'den çekmek yerine, TradingView'ın batch scanner endpoint'ini kullanıyoruz. Tek bir POST isteğiyle 180 hissenin fiyatını aynı anda çekebiliyoruz:
target = "https://scanner.tradingview.com/turkey/scan"
body = {
"symbols": {"tickers": ["BIST:THYAO", "BIST:GARAN", ...], "query": {"types": []}},
"columns": ["name", "close", "change", "change_abs", "time", "update_mode"],
}
Temel Analiz (Fundamentals)
Her hissenin F/K oranı, FAVÖK, piyasa değeri, EPS, ROE gibi metriklerini iki kaynaktan çekiyoruz:
- Birincil: Investing.com web scraping (
cloudscraper+BeautifulSoupile) - Fallback: TradingView Scanner API (Investing'den veri gelmezse)
İki kaynak merge ediliyor — birinde eksik olan metrik diğerinden tamamlanıyor.
Piyasa Durumu Motoru
Backend, BİST'in o an açık mı kapalı mı olduğunu hesaplıyor:
- Hafta sonu kontrolü
- Türkiye resmi tatil takvimi (Nager Date API'si)
- Arefe günleri yarım gün hesaplaması
- Manuel seans override desteği (
session_overrides.json) - Feed freshness probe: Gerçekten veri geliyor mu kontrolü (en son 20 dakika içinde fiyat güncellenmiş mi)
🎨 Arayüz ve Sayfalar
Tüm frontend React CDN + Vanilla JS ile yazıldı — npm build süreci yok, doğrudan tarayıcıda çalışıyor. Sayfalar:
| Sayfa | Dosya | İşlev |
|---|---|---|
| Ana Sayfa | index.html | BİST hisse listesi, arama, favori, fiyat tablosu, detay grafikleri |
| Giriş | login.html | Supabase Auth ile e-posta/şifre girişi |
| Kayıt | register.html | Yeni hesap oluşturma |
| Şifre Sıfırla | sifre-sifirla.html | E-posta ile şifre sıfırlama akışı |
| Sepetlerim | sepetlerim.html | Tüm sepetlerin özet görünümü, slot durumu |
| Sepet Detay | sepet.html | Tekil sepet detayı ve performans |
| Sepet İşlem | sepet-islem.html | Alım-satım ekranı, canlı fiyat, işlem geçmişi |
| Profil | profil.html | Kullanıcı profil yönetimi |
| Eğitim | egitim.html | Borsa terimleri sözlüğü ve eğitim içerikleri |
Sepet İşlem Ekranı — En Karmaşık Sayfa
sepet-islem.html projenin en kritik ve karmaşık ekranı — 126.000+ byte tek dosya. Bu ekranda kullanıcı bir hisse alıp sattığında eşzamanlı olarak:
- Bakiye düşüyor/artıyor
- Slot durumu ilerleme çubuğu güncelleniyor
- Hisse listesine yeni hisse ekleniyor veya mevcut pozisyon güncelleniyor
- İşlem geçmişine yeni kayıt ekleniyor
- Kâr/zarar hesaplaması yeniden yapılıyor
Hepsi sayfa yenilenmeden, DOM manipülasyonu ile anlık gerçekleşiyor. Bu akışın pürüzsüz çalışmasını sağlamak benim en çok ter döktüğüm kısımdı.
🔒 Veritabanı Güvenliği
Supabase tarafında Row Level Security (RLS) ile her kullanıcı sadece kendi verilerine erişebiliyor:
CREATE POLICY "baskets_select_own" ON public.baskets
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "baskets_insert_own" ON public.baskets
FOR INSERT WITH CHECK (auth.uid() = user_id);
Ayrıca veritabanı trigger'ları ile:
- Sepet limiti (max 5) veritabanı seviyesinde zorlanıyor
updated_atalanı otomatik güncelleniyor- Aktif sepetlerde isim benzersizliği partial unique index ile sağlanıyor
🚀 Deployment Pipeline
Frontend (Vercel)
GitHub push → Vercel otomatik build → CDN'den global dağıtım → upfinance-seven.vercel.app
Backend (Ubuntu)
Python server.py Oracle Cloud Ubuntu sunucusunda sürekli çalışıyor (IP: 130.61.104.4:5500). Vercel'den gelen API isteklerini karşılıyor.
Database (Supabase)
GitHub Actions ile migration'lar production'a push ediliyor:
- name: Push migrations to production
run: supabase db push --password "$SUPABASE_DB_PASSWORD"
🔧 Karşılaştığımız Zorluklar ve Çözümler
Zorluk 1: İşlem Geçmişinin Esnekliği
Temettü, sermaye artırımı, komisyon gibi çeşitli işlem tiplerini geleneksel sütunlarla yönetmek çok hantallaştırıyordu. JSONB migration'ı (20260323_add_transactions_jsonb.sql) ile her işlemin dinamiğini tek satırda esnek biçimde tutmaya başladık.
Zorluk 2: DOM Performansı
sepet-islem ekranında bir işlem yapıldığında 5 farklı DOM bölgesi eşzamanlı güncellenmeli — ama tüm sayfayı render etmeden. Modüler state yönetimi kurarak sadece değişen alanlara hedefli DOM manipülasyonu uyguladık.
Zorluk 3: Çoklu Veri Kaynağı Senkronizasyonu
Investing.com scraping bazen cloudflare engeliyle karşılaşıyordu. TradingView fallback + merge stratejisi ile hiçbir hisse fundamental verisi eksik kalmıyor.
Zorluk 4: Borsa Seans Zamanlaması
Tatil günleri, arefe yarım günler, seans override'ları... Borsanın tam olarak ne zaman açık olduğunu hesaplamak beklenenden çok daha karmaşıktı. Türkiye resmi tatil API'si + manuel override dosyası + feed freshness probe ile %100 doğru seans durumu sağladık.
📈 Sonuç ve Gelecek Vizyonumuz
Yahya'nın doğru tespiti, Yusuf Enes'in harika proje yönetimi ve biz Full Stack ekibinin (Melih, Ahmet ve ben) yoğun mühendislik mesaisi sonucunda; yatırımcıların portföylerini profesyonel bir fon yöneticisi disipliniyle yönetebildikleri UpFinance platformunu canlıya aldık.
🔗 Canlı platform: upfinance-seven.vercel.app
Gelecek İyileştirmeler
- WebSocket Gerçek Zamanlı Veri: Ubuntu sunucu üzerinden BİST anlık fiyatları push etmek
- Gelişmiş Grafikler: Sepetlerin getiri eğrilerini (yield curves) görselleştirmek
- Mobil Uygulama: React Native veya Flutter ile native mobil deneyim
- AI Tabanlı Öneriler: Sepet performansına göre akıllı yatırım önerileri
Bu proje bana "Full Stack Developer" olmanın sadece kod yazmak değil; doğru DevOps mimarisini kurmak, takım arkadaşlarıyla uyum içinde çalışmak ve son kullanıcının psikolojisini anlayarak empati kurabilmek olduğunu bir kez daha kanıtladı. UpFinance ekibi olarak yenilikler geliştirmeye devam edeceğiz!