diff --git a/public/app.js b/public/app.js
new file mode 100644
index 0000000..d480572
--- /dev/null
+++ b/public/app.js
@@ -0,0 +1,172 @@
+// Numex Depo Yönetim Sistemi - Frontend mantığı
+const api = {
+ list: (p) => fetch('/api/' + p).then(r => r.json()),
+ post: (p, body) => fetch('/api/' + p, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body)
+ }).then(async r => ({ ok: r.ok, veri: await r.json() })),
+ del: (p) => fetch('/api/' + p, { method: 'DELETE' }).then(r => r.json())
+};
+
+// --- Sekme geçişleri ---
+document.querySelectorAll('.sekm').forEach(btn => {
+ btn.addEventListener('click', () => {
+ document.querySelectorAll('.sekm').forEach(b => b.classList.remove('secili'));
+ document.querySelectorAll('.panel').forEach(p => p.classList.remove('aktif'));
+ btn.classList.add('secili');
+ document.getElementById('sekme-' + btn.dataset.sekme).classList.add('aktif');
+ yenile();
+ });
+});
+
+// --- Evrensel yenileme ---
+function yenile() {
+ lokasyonlariYukle();
+ urunleriYukle();
+ stoguYukle();
+ gecmisiYukle();
+ uyarilariYukle();
+}
+
+// --- Lokasyonlar ---
+async function lokasyonlariYukle() {
+ const lokasyonlar = await api.list('lokasyonlar');
+ const t = document.getElementById('lokasyon-tablo');
+ t.innerHTML = lokasyonlar.length ? lokasyonlar.map(l => `
+
+ | ${l.id} | ${l.ad} | ${l.sehir || '-'} |
+ ${new Date(l.olusturuldu).toLocaleDateString('tr-TR')} |
+ |
+
`).join('') : '| Henüz lokasyon yok |
';
+
+ // Transfer form dropdownları
+ durumlariDoldur('transfer-kaynak', lokasyonlar);
+ durumlariDoldur('transfer-hedef', lokasyonlar);
+}
+
+function durumlariDoldur(id, lokasyonlar) {
+ const s = document.getElementById(id);
+ const mevcut = s.value;
+ s.innerHTML = lokasyonlar.map(l => ``).join('');
+ if (lokasyonlar.some(l => l.id === Number(mevcut))) s.value = mevcut;
+}
+
+async function lokasyonSil(id) {
+ if (!confirm('Bu lokasyon silinsin mi?')) return;
+ await api.del('lokasyonlar/' + id);
+ yenile();
+}
+
+document.getElementById('lokasyon-form').addEventListener('submit', async (e) => {
+ e.preventDefault();
+ await api.post('lokasyonlar', {
+ ad: document.getElementById('lokasyon-ad').value,
+ sehir: document.getElementById('lokasyon-sehir').value
+ });
+ e.target.reset();
+ yenile();
+});
+
+// --- Ürünler ---
+async function urunleriYukle() {
+ const urunler = await api.list('urunler');
+ const t = document.getElementById('urun-tablo');
+ t.innerHTML = urunler.length ? urunler.map(u => `
+
+ | ${u.id} | ${u.ad} | ${u.birim} |
+ ${u.dusukStokEsigi} |
+ |
+
`).join('') : '| Henüz ürün yok |
';
+
+ const s = document.getElementById('transfer-urun');
+ s.innerHTML = urunler.map(u => ``).join('');
+}
+
+async function urunSil(id) {
+ if (!confirm('Bu ürün silinsin mi?')) return;
+ await api.del('urunler/' + id);
+ yenile();
+}
+
+document.getElementById('urun-form').addEventListener('submit', async (e) => {
+ e.preventDefault();
+ await api.post('urunler', {
+ ad: document.getElementById('urun-ad').value,
+ birim: document.getElementById('urun-birim').value,
+ dusukStokEsigi: document.getElementById('urun-esik').value
+ });
+ e.target.reset();
+ yenile();
+});
+
+// --- Stok ---
+async function stoguYukle() {
+ const veri = await api.list('stok');
+ const g = document.getElementById('stok-gorunum');
+ if (!veri.length) { g.innerHTML = 'Lokasyon ekleyin ve stok girişi yapın.
'; return; }
+
+ g.innerHTML = veri.map(l => `
+
+
🏬 ${l.lokasyonAd} (${l.sehir || 'Şehir yok'})
+
+ | Ürün | Birim | Miktar | Durum |
+
+ ${l.stok.length ? l.stok.map(k => {
+ const dusuk = k.miktar <= k.dusukStokEsigi;
+ return `
+ | ${k.urunAd} | ${k.birim} | ${k.miktar} |
+ ${dusuk ? '⬇ Düşük stok' : '✓ Yeterli'} |
+
`;
+ }).join('') : '| Bu lokasyonda stok yok |
'}
+
+
+
`).join('');
+}
+
+// --- Transfer ---
+document.getElementById('transfer-form').addEventListener('submit', async (e) => {
+ e.preventDefault();
+ const mesaj = document.getElementById('transfer-mesaj');
+ const sonuc = await api.post('transferler', {
+ kaynakId: document.getElementById('transfer-kaynak').value,
+ hedefId: document.getElementById('transfer-hedef').value,
+ urunId: document.getElementById('transfer-urun').value,
+ miktar: document.getElementById('transfer-miktar').value
+ });
+ mesaj.className = 'mesaj ' + (sonuc.ok ? 'ok' : 'hata');
+ mesaj.textContent = sonuc.ok
+ ? '✅ Transfer başarılı!'
+ : (sonuc.veri.hata || 'Transfer yapılamadı') + (Array.isArray(sonuc.veri.hata) ? '' : '');
+ if (sonuc.ok) e.target.reset();
+ yenile();
+});
+
+// --- Transfer geçmişi ---
+async function gecmisiYukle() {
+ if (!document.getElementById('sekme-gecmis').classList.contains('aktif')) return;
+ const veri = await api.list('transferler');
+ const t = document.getElementById('gecmis-tablo');
+ t.innerHTML = veri.length ? veri.map(g => `
+
+ | ${new Date(g.tarih).toLocaleString('tr-TR')} |
+ ${g.urunAd} | ${g.kaynakAd} | → |
+ ${g.hedefAd} | ${g.miktar} |
+
`).join('') : '| Henüz transfer yapılmadı |
';
+}
+
+// --- Düşük stok uyarıları ---
+async function uyarilariYukle() {
+ if (!document.getElementById('sekme-uyari').classList.contains('aktif')) return;
+ const veri = await api.list('stok/uyari/dusuk');
+ const t = document.getElementById('uyari-tablo');
+ t.innerHTML = veri.length ? veri.map(u => `
+
+ | ${u.lokasyonAd} | ${u.urunAd} |
+ ${u.miktar} | ${u.dusukStokEsigi} |
+ ⚠ Stok az |
+
`).join('') : '| 🎉 Tüm stok seviyeleri yeterli |
';
+}
+
+// Başlangıç
+yenile();