diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md
index f82d974..795e421 100644
--- a/docs/quality/uygulama-durumu.md
+++ b/docs/quality/uygulama-durumu.md
@@ -978,3 +978,10 @@ Taslak türü seçicisine erişilebilir ad eklendi. Üretim derlemesi geçti. Ö
- İkinci sekme yenilendiğinde yalnız ilk sekmenin kaydı geldi; ikinci ürün güncel profil üzerine yeniden eklendi ve iki ürün birlikte başarıyla kaydedildi. Beş kontrol geçti. Kanıt: /Users/hikmettanriverdi/Documents/ChatGPT/ihale/rapor/qa-profile-concurrent-tabs.json.
- Test sadece firma profili için gerçek iki sekme etkileşimini kapsar. Filtrelerin API çakışma kabulü önceki 222 testte mevcut; filtre UI çakışma/kurtarma senaryosu ayrıca açık. Üretim kodu değişmediğinden suite ve derleme tekrar edilmedi.
- Sekmeler kapatıldı; bu test için açılan QA süreci sonlandırıldı (exit 0), geçici depo cleanup akışı tamamlandı. Canlı site veya gerçek firma hesabı değiştirilmedi.
+
+### Ekip kaydında sunucu onayı ve çakışma koruması — 6 Eylül 2026
+- Ekip listesinin iyimser state + effect otomatik kaydı kaldırıldı. Ekleme/çıkarma mevcut ekip içerik sürümüyle sunucuya yazılır; yalnız başarıdan sonra liste ve sürüm güncellenir. Kayıt sürerken işlem kilitlenir; hata ekip formunun yanında gösterilir, ekleme girdileri temizlenmez.
+- API ekip listesi, benzersiz kimlik, ad, görev ve isteğe bağlı e-posta alanlarını doğrular; mevcut plan kotası ve sürüm karşılaştırması birlikte uygulanır. Eski sekme yazımı mevcut listeyi ezmez.
+- Son ekip üyesini kaldırmayı engelleyen arayüz koşulu kaldırıldı; boş ekip listesi geçerlidir. Düğme ve form alanlarına açık etiketler, kayıt sürüyor durumu ve beklerken devre dışı bırakma eklendi. Bu kayıtlar hesap içi görev/sorumlu listesidir; davet gönderilmedi veya başka kullanıcı hesabı oluşturulmadı.
+- 224 otomatik test ve derleme geçti. HTTP testi ekip ekleme, eski sürüm reddi, kota aşımında mevcut kaydın korunması ve son üyeyi silmeyi doğruladı. Geçersiz/yinelenen ekip verisi test edildi.
+- Ekip UI hata/kurtarma ve iki sekmeli etkileşim kabulü henüz yapılmadı. Üye silinince geçmiş ihale sorumlu adı tarihsel kayıtta kalır; otomatik yeniden atama yapılmaz. Favoriler ve diğer genel kullanıcı anahtarları için çakışma koruması açık. Canlıya yayın yapılmadı.
diff --git a/docs/quality/yedek-geri-yukleme.md b/docs/quality/yedek-geri-yukleme.md
index 0299d36..206f0da 100644
--- a/docs/quality/yedek-geri-yukleme.md
+++ b/docs/quality/yedek-geri-yukleme.md
@@ -75,3 +75,5 @@ Kuyruktaki ilanın artık kaynakta bulunmaması, teklif zamanının değişmesi,
### Firma profili / kayıtlı filtre sürüm sözleşmesi
`GET /api/me/data` artık `veri` ile aynı okumaya ait `revisions` döndürür. `firma_profil` ve `saved_filters` PUT/POST istekleri `revision` göndermelidir (yeni kayıt için null). Eksik sürüm 428, değişmiş sürüm 409 üretir; otomatik üzerine yazma veya otomatik tekrar yoktur. Frontend ve backend birlikte sürümlenmelidir. Eski açık sekme 428 alırsa kaydedilmemiş girdiler korunup sayfa yenilenmelidir. Veritabanı şeması değişmez; eski sunucuya dönmek bu iki anahtardaki çakışma korumasını kaldırır. Yayın kabulünde iki sekmenin aynı kaydı değiştirmesi ve reddedilen sekmenin girdilerinin korunması sınanmalıdır.
+
+Ekip kaydı (`ekip`) da aynı içerik sürümü sözleşmesine dahil edildi. Yeni ekip arayüzü sunucu onayını bekler. Eski istemciden sürümsüz ekip yazımı 428 ile reddedilir; frontend/backend birlikte güncellenmelidir. Ekip alanlarının geçersiz veya kimliklerinin yinelenmiş olduğu eski kayıtlar önce düzeltilmelidir; sessiz veri temizliği yapılmaz.
diff --git a/server/index.js b/server/index.js
index a1a6730..7ce5f79 100644
--- a/server/index.js
+++ b/server/index.js
@@ -1,3 +1,4 @@
+import {validateTeam} from '../src/services/teamData.js';
import { executeAnalysisJob } from './analysis-job.mjs';
import { resolveAiJobInput } from './ai-job-source.mjs';
import * as aiJobs from './ai-job-store.mjs';
@@ -1202,10 +1203,11 @@ const server = http.createServer(async (req, res) => {
const k = body.anahtar || anahtar;
if (!k) return json(res, 400, { success: false, error: 'anahtar gerekli' });
// Ekip kotası sunucu tarafında uygulanır
- if (k === 'ekip' && Array.isArray(body.deger)) {
+ if (k === 'ekip') {
+ validateTeam(body.deger);
kotaKontrol(user.email, 'ekip', 0, body.deger.length, { isAdmin: user.isAdmin });
}
- const protectedKey=['firma_profil','saved_filters'].includes(k);
+ const protectedKey=['firma_profil','saved_filters','ekip'].includes(k);
if(protectedKey && (!Object.hasOwn(body,'revision') || (body.revision!==null && (typeof body.revision!=='string' || !/^[a-f0-9]{64}$/.test(body.revision)))))
return json(res,428,{success:false,kod:'VERSION_REQUIRED',error:'Güncel kayıt sürümü gerekli. Sayfayı yenileyip tekrar deneyin.'});
const revision=store.setData(user.email, k, body.deger, protectedKey ? body.revision : undefined);
diff --git a/src/components/RightSidebar.jsx b/src/components/RightSidebar.jsx
index 8cc4a1a..ab96633 100644
--- a/src/components/RightSidebar.jsx
+++ b/src/components/RightSidebar.jsx
@@ -5,7 +5,7 @@ import { firmStats, companyStats } from '../services/analytics';
import { Briefcase, FileText, Calendar, History, Trophy, Eye, Kanban, Radar, ArrowRight, Users, Plus, Trash2 } from 'lucide-react';
export const RightSidebar = () => {
- const { setActiveTab, setQuickFilter, tenders, teamMembers, addTeamMember, removeTeamMember } = useApp();
+ const { setActiveTab, setQuickFilter, tenders, teamMembers, teamSaving, teamError, addTeamMember, removeTeamMember } = useApp();
const [tmName, setTmName] = useState('');
const [tmEmail, setTmEmail] = useState('');
const [tmRole, setTmRole] = useState('Uzman');
@@ -13,11 +13,11 @@ export const RightSidebar = () => {
const cs = companyStats(tenders);
const topFirms = firmStats(tenders).firms.slice(0, 3);
- const handleAddMember = (e) => {
+ const handleAddMember = async (e) => {
e.preventDefault();
if (!tmName.trim()) return;
- addTeamMember({ name: tmName.trim(), email: tmEmail.trim(), role: tmRole });
- setTmName(''); setTmEmail('');
+ const saved=await addTeamMember({ name: tmName.trim(), email: tmEmail.trim(), role: tmRole });
+ if(saved){setTmName('');setTmEmail('');}
};
const records = [
@@ -125,7 +125,7 @@ export const RightSidebar = () => {
- {/* Ekip Yönetimi — gerçek (localStorage) */}
+ {/* Ekip Yönetimi — sunucu kaydı */}