Table of contents
- İçindekiler
- 1. Amaç ve Kapsam
- 2. Genel Mimari
- 3. Repository Yapısı
- 4. Frontend Mimarisi
- 4.1 Teknoloji Yığını
- 4.2 Routing
- 4.3 Layout ve Navigasyon
- 4.4 State Yönetimi
- 4.5 API / Service Katmanı (services/)
- 4.6 Form Mimarisi — itService.ts ve İki Ayrı Kimlik Doğrulama Yolu
- 4.7 Public Form / PublicITView
- 4.8 Admin / Edit Mode
- 4.9 Responsive Davranış (Frontend Uygulaması)
- 4.10 Tema / UI Component Yapısı
- 4.11 PDF / Export Frontend Davranışı
- 4.12 Bildirim / Modal / Popup Yapısı
- 4.13 Component Ağacı — components/it/
- 5. Backend Mimarisi
- 5.1 Katman Mimarisi (Genel Bakış)
- 5.2 Entrypoint — server.js
- 5.3 Express App Factory — createApp(deps)
- 5.4 app.js Router Mount Haritası
- 5.5 Middleware Pipeline
- 5.6 Routes → Controllers → Services → Repositories Katmanlaşması
- 5.7 Servis Katmanı Envanteri
- 5.8 InfraRecordService — Ana İş Mantığı
- 5.9 Controller/Validator Katmanı
- 5.10 MongoDB Bağlantısı (config/db.js)
- 5.11 Hata İşleme Sözleşmesi
- 5.12 Health Endpoint
- 5.13 Loglama
- 5.14 Graceful Shutdown
- 5.15 API Versiyonlama
- 6. Kimlik Doğrulama ve Yetkilendirme
- 6.1 Authentication — Admin/Personel JWT Akışı
- 6.2 Authorization — Rol/İzin Modeli
- 6.3 Middleware Katmanı
- 6.4 Public Erişim — Ayrı Bir Mekanizma
- 6.5 Ortak Secret Kısıtı
- 6.6 Frontend Guard'ları — UX Kolaylığı, Güvenlik Sınırı Değil
- 7. Public / Müşteri Erişim Mimarisi
- 7.1 Mail Linki → Session Bootstrap Akışı
- 7.2 Cookie Ayarları — HttpOnly, Secure, SameSite
- 7.3 Session Doğrulaması — requirePublicSession
- 7.4 Müşteri Hangi Kayıt Üzerinde İşlem Yapabiliyor
- 7.5 Başka Kayda Erişim Nasıl Engelleniyor
- 7.6 Session Expiration
- 7.7 Public Uç Nokta Envanteri
- 7.8 OpenVPN Sabit IP — Müşteriye Kasıtlı Olarak Açık
- 8. Veri Modelleri
- 8.1 MongoDB Koleksiyonları (iqvizyon veritabanı)
- 8.2 InfraRecord — Ana Alan Tablosu
- 8.3 Nested Yapılar — Detaylı Şekiller
- 8.4 steps[] — Süreç Geçmişi (Append-Only Log)
- 8.5 organizations ve iqvizyon-users Şemaları
- 9. Infra Form Domain Yapısı
- 10. Form Bölümleri ve Alan Davranışları
- 11. Progress / Tamamlandı Mekanizması
- 12. Makine Yönetimi
- 13. Proje Tipi / Durum Yönetimi
- 14. Ekler ve Dosya Yönetimi
- 15. E-posta ve Bildirim Altyapısı
- 16. PDF / Export
- 17. API Endpointleri
- 17.1 Kimlik Doğrulama — auth.routes.js
- 17.2 Personel/Kullanıcı — people.routes.js
- 17.3 Organizasyonlar — organizations.routes.js
- 17.4 Infra Kayıtları (Admin) — infraRecord.routes.js
- 17.5 IQVizyon Kontrolü (Admin Review) — infraAdminReview.routes.js
- 17.6 IT / Bil (Gemini) — it.routes.js
- 17.7 Hatırlatıcı — reminder.routes.js
- 17.8 İşlem Logu — infraLog.routes.js
- 17.9 Sağlık Kontrolü — health.routes.js
- 17.10 Dokümantasyon — docs.routes.js
- 17.11 Public/Müşteri — infraPublicRecord.routes.js
- 18. Environment Variables
- 19. Docker ve Deployment
- 19.1 docker-compose.yml
- 19.2 Dockerfile'lar
- 19.3 nginx.conf
- 19.4 Native Kurulum (Docker'sız)
- 19.5 Production vs. Development Farkları
- 20. Test Altyapısı
- 21. CI / Quality Pipeline
- 22. Responsive / Mobil / Tablet
- 23. Güvenlik
- 24. Bakım Kuralları ve Bilinen Kısıtlar
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
IQV Infra — Teknik Dokümantasyon
Bu doküman IQV Infra projesinin mevcut kaynak kodu üzerinden çıkarılmış teknik referansıdır. Hedef kitle frontend/backend geliştiricileri, DevOps ekipleri, sistem yöneticileri, teknik destek ekipleri ve projeyi devralacak/bakım yapacak mühendislerdir.
Bu dokümandaki teknik bilgiler gerçek kaynak kod üzerinden doğrulanmıştır. Kaynak koddan kesin olarak doğrulanamayan noktalar ayrıca belirtilmiştir. Secret değerler dokümana dahil edilmemiştir.
İçindekiler
- Amaç ve Kapsam
- Genel Mimari
- Repository Yapısı
- Frontend Mimarisi
- Backend Mimarisi
- Kimlik Doğrulama ve Yetkilendirme
- Public / Müşteri Erişim Mimarisi
- Veri Modelleri
- Infra Form Domain Yapısı
- Form Bölümleri ve Alan Davranışları
- Progress / Tamamlandı Mekanizması
- Makine Yönetimi
- Proje Tipi / Durum Yönetimi
- Ekler ve Dosya Yönetimi
- E-posta ve Bildirim Altyapısı
- PDF / Export
- API Endpointleri
- Environment Variables
- Docker ve Deployment
- Test Altyapısı
- CI / Quality Pipeline
- Responsive / Mobil / Tablet
- Güvenlik
- Bakım Kuralları ve Bilinen Kısıtlar
1. Amaç ve Kapsam
IQV Infra, IQVizyon'un müşteri sahalarındaki teknoloji altyapısını (sunucu, ağ, uzaktan erişim, güvenlik, tezgah/makine bilgileri) kayıt altına alan; bu bilgileri token'sız (session cookie tabanlı) bir "public" müşteri formu ile müşteriye doldurtan; IQVizyon tarafında kontrol/onay ("IQVizyon Kontrolü" ve "Kurulum Kararı") sürecini yöneten ve tüm bu süreci e-posta/Telegram bildirimleriyle destekleyen bir kurum-içi web uygulamasıdır.
Uygulamanın iki ana bileşeni vardır:
- Backend (
backend/): Node.js (CommonJS modül sistemi) + Express 4, MongoDB resmi sürücüsü (mongodbnpm paketi — ODM/Mongoose kullanılmaz), JWT tabanlı kimlik doğrulama (Bearer token), Swagger/OpenAPI ile kendini otomatik belgeler (/api-docs,/openapi.json). - Frontend (
dashboard/): React 18 + TypeScript + Vite 4, antd 5 (UI bileşen kütüphanesi) ve@iqvizyonui/react-components(kurumsal tasarım sistemi), Redux Toolkit +redux-persist(oturum kalıcılığı), React Router 6.
Bu dokümanın kapsamı yalnızca iqv-react-dashboard reposudur. Doküman; mimari kararları, veri modellerini, iş kurallarını, güvenlik sınırlarını, deployment/test/CI altyapısını ve bilinen kısıtları/legacy alanları kapsar. Uygulamanın kullanım kılavuzu ayrı bir belgededir (IQV_Infra_Son_Kullanici_Kilavuzu.md) ve bu dokümanın konusu değildir.
Kaynaklar: README.md, backend/package.json, dashboard/package.json, repository dizin ağacının doğrudan gözlemi.
2. Genel Mimari
[Tarayıcı] --(HTTPS)--> [nginx (Docker) / static-server.mjs (native)]
|-- statik dosyalar (React SPA build çıktısı)
|-- /api/, /organizations, /infra-record,
| /infra-public-*, /infra-logs/, /infra-admin-*,
| /it/public*, /health, /api-docs, /openapi.json
| --(reverse proxy)--> [Express backend :4000]
|-- MongoDB (iqvizyon veritabanı)
|-- SMTP (Office365, opsiyonel)
|-- Telegram Bot API (opsiyonel)
|-- Gemini API (opsiyonel, /api/it/bil)
Docker Compose ortamında üç servis çalışır: mongo, backend, dashboard (bkz. bölüm 19). Docker olmadan (native) kurulumda scripts/common/static-server.mjs, nginx'in yerini alan bağımlılıksız bir Node.js statik dosya + reverse-proxy sunucusudur ve aynı proxy path sözleşmesini uygular — böylece dev/native/Docker/prod ortamları arasında hangi path'in backend'e, hangisinin SPA'ya gittiği tutarlıdır.
Backend ile frontend tek bir kök .env dosyasını paylaşır (bkz. bölüm 18) — bu, iki bağımsız .env dosyasının birbirinden sapmasını (drift) yapısal olarak engeller.
Kimlik doğrulama iki tamamen ayrı mekanizma kullanır:
- Admin/personel tarafı: JWT (Bearer token),
localStorage+redux-persistile istemcide saklanır (bkz. bölüm 6). - Müşteri/public form tarafı: HttpOnly session cookie (
iqv_infra_public_session), token URL'de hiçbir zaman taşınmaz (bkz. bölüm 7).
Bu iki mekanizma aynı JWT_SECRET ile imzalanır ama purpose alanı ile ayrıştırılır (bkz. bölüm 6.3 ve 23.2) — mimari olarak bilinçli bir kısıt olarak dokümante edilmiştir.
Kaynaklar: docker-compose.yml, dashboard/nginx.conf, scripts/common/static-server.mjs, backend/src/app.js, README.md.
3. Repository Yapısı
iqv-react-dashboard/
├── backend/
│ ├── src/
│ │ ├── app.js # Express router mount haritası (createApp)
│ │ ├── server.js # Entrypoint — HTTP sunucu başlatma
│ │ ├── config/ # env.js, db.js
│ │ ├── controllers/ # HTTP request/response sözleşmeleri
│ │ ├── docs/ # OpenAPI/Swagger üretimi + özel gruplama eklentisi
│ │ ├── middleware/ # auth, publicSession, errorHandler
│ │ ├── models/ # ham MongoDB collection sarmalayıcıları
│ │ ├── repositories/ # MongoDB CRUD katmanı
│ │ ├── routes/ # Express Router tanımları
│ │ ├── services/ # iş mantığı
│ │ ├── utils/ # apiError, asyncHandler, publicSession, regex, infraStatus…
│ │ └── validators/ # request body doğrulama
│ └── tests/ # unit / integration / auth / security / contract
├── dashboard/
│ ├── src/
│ │ ├── components/it/ # Infra form domain'inin tamamı (form, önizleme, public görünüm)
│ │ ├── components/hooks/ # useBreakpoint vb. paylaşılan hook'lar
│ │ ├── routes/ # api.tsx, web.tsx, browserRouter.tsx, guard'lar
│ │ ├── services/ # axios tabanlı API istemcileri
│ │ ├── store/ # Redux Toolkit + redux-persist
│ │ ├── interfaces/models/it.ts # domain veri modeli (TypeScript, 710 satır)
│ │ └── utils/
│ ├── nginx.conf, Dockerfile, vite.config.ts
│ └── tests/ # unit / component (Vitest)
├── tests/e2e/ # Playwright uçtan uca testler
├── scripts/ # kurulum/güncelleme/kaldırma (linux/windows × docker/native), CI script'leri
├── docs/ # MkDocs dokümantasyon sitesi
├── .github/workflows/ # ci.yml, docs.yml
├── docker-compose.yml
├── .env.example
└── README.md
Kaynaklar: repository dizin ağacının device_list_dir ile doğrudan gözlemi, backend/src/app.js, README.md.
4. Frontend Mimarisi
4.1 Teknoloji Yığını
React 18 + TypeScript, Vite 4 (build/dev sunucusu), antd 5 (UI bileşenleri: Table, Modal, Form, Select…), @iqvizyonui/react-components (IQVizyon kurumsal tasarım sistemi — Field/Input/Label/Select gibi bileşenler için), Redux Toolkit + redux-persist (oturum kalıcılığı), React Router 6 (createBrowserRouter), @loadable/component (route bazlı code-splitting), dayjs (tarih işleme), vite-plugin-pwa (Service Worker/PWA desteği), axios (HTTP istemcisi).
Kaynaklar: dashboard/package.json, dashboard/vite.config.ts, dashboard/src/components/it/ITForm.tsx.
4.2 Routing
dashboard/src/routes/web.tsx yol sabitlerini, dashboard/src/routes/browserRouter.tsx gerçek route ağacını (createBrowserRouter) tanımlar. api.tsx ise backend API path sabitlerini tutar (React route'u değildir — bkz. bölüm 5.2 ile karşılaştırma).
| Route | Bileşen | Koruma/Yetki | Açıklama |
|---|---|---|---|
| / | Redirect | — | Giriş durumuna göre /infra veya /login'e yönlendirir. |
| /login | Login | AuthLayout (korumasız) | Kullanıcı adı/parola girişi, başarılı girişte JWT alınır. |
| /infra | Dashboard | RequireAuth + Layout | Ana Infra kayıt listesi/özet ekranı. |
| /users | Users | RequireAuth + RequirePermission('users.read') | Personel/kullanıcı yönetimi. |
| /personel | → /users yönlendirme | RequireAuth | Geriye dönük uyumluluk alias'ı (eski link). |
| /it | ITPage | RequireAuth + Layout | Yeni kayıt oluşturma + kayıt seçimi/önizleme akışının admin girişi. |
| /hatirlatici | ReminderPage | RequireAuth + Layout | Hatırlatıcı planlama ekranı. |
| /form | PublicITView | Yok (public, token'sız — HttpOnly session cookie ile) | Müşterinin dolduracağı public form; RequireAuth/Layout ağacının bilinçli olarak dışında. |
- | NotFoundPage | — | Eşleşmeyen tüm path'ler. /api-docs, /api-docs/, /openapi.json | — (React route'u DEĞİL) | — | Backend tarafından servis edilir (bkz. bölüm 5.2); nginx/proxy bu path'leri SPA'ya değil doğrudan backend'e yönlendirir.
24.2 Genel Bakım Kuralları (kod içi yorumlardan çıkarılan proje kültürü)
- Yeni bir alan/uç nokta eklerken var olan isimlendirme sözleşmesine uyulmalı (
snake_casealan adları,section_*whitelist deseni,*_requirementmetin alan deseni). - Public tarafa asla mass-assignment ile yazma açılmamalı — her yeni public alan,
submitPublicProgress/setPublicSectionStatusiçinde açıkça whitelist'e eklenmelidir. steps[]'e eklenen her yeni adım derin kopya olmalı; var olan adımlar asla güncellenmemeli/silinmemeli (audit trail bütünlüğü).- Yeni bir secret/env değişkeni eklenirken
.env.example'a şablon (değersiz) olarak eklenmeli, koda gömülmemeli. docs:checkCI gate'i, yeni bir endpoint OpenAPI şemasına yansıtılmadan eklenirse pipeline'ı kırar — yeni route eklerkenbackend/src/docs/güncellenmelidir.- Yeni bir kalem/madde (
REQUIREMENT_ITEMSlistesine) eklenirken hem frontendconstants.tshem backendinfraRecord.service.js'teki bağımsız sabit listeler birlikte güncellenmelidir — bu ikisi kasıtlı olarak birbirinden bağımsız sabit kodlanmıştır (istemciden gelen ham değerlere güvenilmemesi için), bu yüzden tek taraflı güncelleme veri tutarsızlığına yol açar. - Var olan alanlar yeniden adlandırılmaz; yeni bir ihtiyaç doğduğunda mevcut alana ek/yeni bir alt-alan eklenir (bkz.
it.tsiçindeki "MEVCUT alanların HİÇBİRİ yeniden adlandırılmadı" yorumları) — bu, eski kayıtlarla geriye dönük uyumluluğu korumak için proje genelinde tutarlı biçimde izlenen bir kuraldır. - Yeni bir kapasite/gereksinim alt-nesnesi eklenirken var olan
{ device_type, cpu_core, ram_gb/ram_unit, disk_ssd_gb/disk_ssd_unit, operating_system }şekli tekrar kullanılır, ikinci bir benzer şekil icat edilmez (bkz.provided_capacity/requested_capacity'nin birebir aynı şekli paylaşması).
Kaynaklar: yukarıdaki tüm bölümlerde atıfta bulunulan dosyalar; backend/src/repositories/infraRecord.repository.js, backend/src/services/bil.service.js, dashboard/src/routes/browserRouter.tsx, dashboard/src/services/itService.ts, dashboard/src/interfaces/models/it.ts.
Doküman sonu.
</html> </html># IQV Infra — Teknik DokümantasyonBu doküman IQV Infra projesinin mevcut kaynak kodu üzerinden çıkarılmış teknik referansıdır. Hedef kitle frontend/backend geliştiricileri, DevOps ekipleri, sistem yöneticileri, teknik destek ekipleri ve projeyi devralacak/bakım yapacak mühendislerdir.
Bu dokümandaki teknik bilgiler gerçek kaynak kod üzerinden doğrulanmıştır. Kaynak koddan kesin olarak doğrulanamayan noktalar ayrıca belirtilmiştir. Secret değerler dokümana dahil edilmemiştir.
İçindekiler
- [Amaç ve Kapsam](#1-amaç-ve-kapsam)
- [Genel Mimari](#2-genel-mimari)
- [Repository Yapısı](#3-repository-yapısı)
- [Frontend Mimarisi](#4-frontend-mimarisi)
- [Backend Mimarisi](#5-backend-mimarisi)
- [Kimlik Doğrulama ve Yetkilendirme](#6-kimlik-doğrulama-ve-yetkilendirme)
- [Public / Müşteri Erişim Mimarisi](#7-public--müşteri-erişim-mimarisi)
- [Veri Modelleri](#8-veri-modelleri)
- [Infra Form Domain Yapısı](#9-infra-form-domain-yapısı)
- [Form Bölümleri ve Alan Davranışları](#10-form-bölümleri-ve-alan-davranışları)
- [Progress / Tamamlandı Mekanizması](#11-progress--tamamlandı-mekanizması)
- [Makine Yönetimi](#12-makine-yönetimi)
- [Proje Tipi / Durum Yönetimi](#13-proje-tipi--durum-yönetimi)
- [Ekler ve Dosya Yönetimi](#14-ekler-ve-dosya-yönetimi)
- [E-posta ve Bildirim Altyapısı](#15-e-posta-ve-bildirim-altyapısı)
- [PDF / Export](#16-pdf--export)
- [API Endpointleri](#17-api-endpointleri)
- [Environment Variables](#18-environment-variables)
- [Docker ve Deployment](#19-docker-ve-deployment)
- [Test Altyapısı](#20-test-altyapısı)
- [CI / Quality Pipeline](#21-ci--quality-pipeline)
- [Responsive / Mobil / Tablet](#22-responsive--mobil--tablet)
- [Güvenlik](#23-güvenlik)
- [Bakım Kuralları ve Bilinen Kısıtlar](#24-bakım-kuralları-ve-bilinen-kısıtlar)
1. Amaç ve Kapsam
IQV Infra, IQVizyon'un müşteri sahalarındaki teknoloji altyapısını (sunucu, ağ, uzaktan erişim, güvenlik, tezgah/makine bilgileri) kayıt altına alan; bu bilgileri token'sız (session cookie tabanlı) bir "public" müşteri formu ile müşteriye doldurtan; IQVizyon tarafında kontrol/onay ("IQVizyon Kontrolü" ve "Kurulum Kararı") sürecini yöneten ve tüm bu süreci e-posta/Telegram bildirimleriyle destekleyen bir kurum-içi web uygulamasıdır.
Uygulamanın iki ana bileşeni vardır:
- Backend (
backend/): Node.js (CommonJS modül sistemi) + Express 4, MongoDB resmi sürücüsü (mongodbnpm paketi — ODM/Mongoose kullanılmaz), JWT tabanlı kimlik doğrulama (Bearer token), Swagger/OpenAPI ile kendini otomatik belgeler (/api-docs,/openapi.json). - Frontend (
dashboard/): React 18 + TypeScript + Vite 4, antd 5 (UI bileşen kütüphanesi) ve@iqvizyonui/react-components(kurumsal tasarım sistemi), Redux Toolkit +redux-persist(oturum kalıcılığı), React Router 6.
Bu dokümanın kapsamı yalnızca iqv-react-dashboard reposudur. Doküman; mimari kararları, veri modellerini, iş kurallarını, güvenlik sınırlarını, deployment/test/CI altyapısını ve bilinen kısıtları/legacy alanları kapsar. Uygulamanın kullanım kılavuzu ayrı bir belgededir (IQV_Infra_Son_Kullanici_Kilavuzu.md) ve bu dokümanın konusu değildir.
Kaynaklar: README.md, backend/package.json, dashboard/package.json, repository dizin ağacının doğrudan gözlemi.
2. Genel Mimari
[Tarayıcı] --(HTTPS)--> [nginx (Docker) / static-server.mjs (native)]
|-- statik dosyalar (React SPA build çıktısı)
|-- /api/, /organizations, /infra-record,
| /infra-public-*, /infra-logs/, /infra-admin-*,
| /it/public*, /health, /api-docs, /openapi.json
| --(reverse proxy)--> [Express backend :4000]
|-- MongoDB (iqvizyon veritabanı)
|-- SMTP (Office365, opsiyonel)
|-- Telegram Bot API (opsiyonel)
|-- Gemini API (opsiyonel, /api/it/bil)
Docker Compose ortamında üç servis çalışır: mongo, backend, dashboard (bkz. bölüm 19). Docker olmadan (native) kurulumda scripts/common/static-server.mjs, nginx'in yerini alan bağımlılıksız bir Node.js statik dosya + reverse-proxy sunucusudur ve aynı proxy path sözleşmesini uygular — böylece dev/native/Docker/prod ortamları arasında hangi path'in backend'e, hangisinin SPA'ya gittiği tutarlıdır.
Backend ile frontend tek bir kök .env dosyasını paylaşır (bkz. bölüm 18) — bu, iki bağımsız .env dosyasının birbirinden sapmasını (drift) yapısal olarak engeller.
Kimlik doğrulama iki tamamen ayrı mekanizma kullanır:
- Admin/personel tarafı: JWT (Bearer token),
localStorage+redux-persistile istemcide saklanır (bkz. bölüm 6). - Müşteri/public form tarafı: HttpOnly session cookie (
iqv_infra_public_session), token URL'de hiçbir zaman taşınmaz (bkz. bölüm 7).
Bu iki mekanizma aynı JWT_SECRET ile imzalanır ama purpose alanı ile ayrıştırılır (bkz. bölüm 6.3 ve 23.2) — mimari olarak bilinçli bir kısıt olarak dokümante edilmiştir.
Kaynaklar: docker-compose.yml, dashboard/nginx.conf, scripts/common/static-server.mjs, backend/src/app.js, README.md.
3. Repository Yapısı
iqv-react-dashboard/
├── backend/
│ ├── src/
│ │ ├── app.js # Express router mount haritası (createApp)
│ │ ├── server.js # Entrypoint — HTTP sunucu başlatma
│ │ ├── config/ # env.js, db.js
│ │ ├── controllers/ # HTTP request/response sözleşmeleri
│ │ ├── docs/ # OpenAPI/Swagger üretimi + özel gruplama eklentisi
│ │ ├── middleware/ # auth, publicSession, errorHandler
│ │ ├── models/ # ham MongoDB collection sarmalayıcıları
│ │ ├── repositories/ # MongoDB CRUD katmanı
│ │ ├── routes/ # Express Router tanımları
│ │ ├── services/ # iş mantığı
│ │ ├── utils/ # apiError, asyncHandler, publicSession, regex, infraStatus…
│ │ └── validators/ # request body doğrulama
│ └── tests/ # unit / integration / auth / security / contract
├── dashboard/
│ ├── src/
│ │ ├── components/it/ # Infra form domain'inin tamamı (form, önizleme, public görünüm)
│ │ ├── components/hooks/ # useBreakpoint vb. paylaşılan hook'lar
│ │ ├── routes/ # api.tsx, web.tsx, browserRouter.tsx, guard'lar
│ │ ├── services/ # axios tabanlı API istemcileri
│ │ ├── store/ # Redux Toolkit + redux-persist
│ │ ├── interfaces/models/it.ts # domain veri modeli (TypeScript, 710 satır)
│ │ └── utils/
│ ├── nginx.conf, Dockerfile, vite.config.ts
│ └── tests/ # unit / component (Vitest)
├── tests/e2e/ # Playwright uçtan uca testler
├── scripts/ # kurulum/güncelleme/kaldırma (linux/windows × docker/native), CI script'leri
├── docs/ # MkDocs dokümantasyon sitesi
├── .github/workflows/ # ci.yml, docs.yml
├── docker-compose.yml
├── .env.example
└── README.md
Kaynaklar: repository dizin ağacının device_list_dir ile doğrudan gözlemi, backend/src/app.js, README.md.
4. Frontend Mimarisi
4.1 Teknoloji Yığını
React 18 + TypeScript, Vite 4 (build/dev sunucusu), antd 5 (UI bileşenleri: Table, Modal, Form, Select…), @iqvizyonui/react-components (IQVizyon kurumsal tasarım sistemi — Field/Input/Label/Select gibi bileşenler için), Redux Toolkit + redux-persist (oturum kalıcılığı), React Router 6 (createBrowserRouter), @loadable/component (route bazlı code-splitting), dayjs (tarih işleme), vite-plugin-pwa (Service Worker/PWA desteği), axios (HTTP istemcisi).
Kaynaklar: dashboard/package.json, dashboard/vite.config.ts, dashboard/src/components/it/ITForm.tsx.
4.2 Routing
dashboard/src/routes/web.tsx yol sabitlerini, dashboard/src/routes/browserRouter.tsx gerçek route ağacını (createBrowserRouter) tanımlar. api.tsx ise backend API path sabitlerini tutar (React route'u değildir — bkz. bölüm 5.2 ile karşılaştırma).
| Route | Bileşen | Koruma/Yetki | Açıklama |
|---|---|---|---|
/ |
Redirect |
— | Giriş durumuna göre /infra veya /login'e yönlendirir. |
/login |
Login |
AuthLayout (korumasız) |
Kullanıcı adı/parola girişi, başarılı girişte JWT alınır. |
/infra |
Dashboard |
RequireAuth + Layout |
Ana Infra kayıt listesi/özet ekranı. |
/users |
Users |
RequireAuth + RequirePermission('users.read') |
Personel/kullanıcı yönetimi. |
/personel |
→ /users yönlendirme |
RequireAuth |
Geriye dönük uyumluluk alias'ı (eski link). |
/it |
ITPage |
RequireAuth + Layout |
Yeni kayıt oluşturma + kayıt seçimi/önizleme akışının admin girişi. |
/hatirlatici |
ReminderPage |
RequireAuth + Layout |
Hatırlatıcı planlama ekranı. |
/form |
PublicITView |
Yok (public, token'sız — HttpOnly session cookie ile) | Müşterinin dolduracağı public form; RequireAuth/Layout ağacının bilinçli olarak dışında. |
* |
NotFoundPage |
— | Eşleşmeyen tüm path'ler. |
/api-docs, /api-docs/, /openapi.json |
— (React route'u DEĞİL) | — | Backend tarafından servis edilir (bkz. bölüm 5.2); nginx/proxy bu path'leri SPA'ya değil doğrudan backend'e yönlendirir. |
/form, paylaşılan RequireAuth/Layout ağacının bilinçli olarak dışında ayrı bir üst-seviye route'tur — Layout yalnızca nested <Outlet/> içeren bir parent bileşen olduğu ve RequireAuth token yoksa koşulsuz /login'e yönlendirdiği için, bu iki paylaşılan bileşene dokunmadan token'sız bir genel-erişim görünümü başka türlü ayrıştırılamaz.
Kaynaklar: dashboard/src/routes/web.tsx, dashboard/src/routes/browserRouter.tsx, dashboard/src/routes/api.tsx.
4.3 Layout ve Navigasyon
Korumalı sayfalar (/infra, /users, /it, /hatirlatici) ortak bir Layout bileşeni altında (kenar menü + üst bar + <Outlet/>) render edilir; AuthLayout, /login gibi korumasız sayfalar için ayrı, sadeleştirilmiş bir kabuk sağlar. /form (public) hiçbir ortak layout'u kullanmaz — kendi bağımsız sayfa kabuğuna sahiptir, böylece müşteri hiçbir admin navigasyon öğesini (menü, kullanıcı adı, çıkış butonu vb.) görmez.
Auth Guard'ları:
requireAuth.tsx: JWT'nin yapısal geçerliliğini (3 parça, exp süresi) render öncesi senkron kontrol eder; token yoksa/yapısı bozuksa/süresi dolmuşsa protected içerik hiç render edilmeden /login'e yönlendirir. Ardından GET /api/v1/auth/me ile backend'e karşı gerçek doğrulama yapılır ("protected page flash" düzeltmesi) — 401 dönerse oturum temizlenir, ağ hatası/5xx durumunda önceki geçerli oturuma güvenilmeye devam edilir (kullanıcı sonsuz login döngüsüne düşmesin diye).
requirePermission.tsx: RequireAuth'ın içinde kullanılan, backend'deki PermissionKey sözleşmesiyle birebir aynı frontend izin çözümlemesi (utils/permissions.ts) — yalnızca users.read/create/update/delete izinleri tanımlıdır (Infra'da ayarlar/sözlük modülü yoktur). Bu yalnızca bir UI kolaylığıdır; gerçek, sahtelenemez yetki kontrolü her zaman backend'dedir (people.routes.js → requirePermission middleware'i) — bu ayrım bölüm 6.6'da tekrar vurgulanmıştır.
Kaynaklar: dashboard/src/routes/requireAuth.tsx, dashboard/src/routes/requirePermission.tsx, dashboard/src/utils/permissions.ts, dashboard/src/services/authApi.ts, dashboard/src/routes/browserRouter.tsx.
4.4 State Yönetimi
Tek bir Redux slice (adminSlice) — { token, user } şeklinde Admin state'i, redux-persist ile localStorage'da saklanır (persist anahtarı CONFIG.appName). store/index.tsx'te combineReducers({ admin }) + persistReducer ile store kurulur. Projede ikinci bir domain-seviyesi slice yoktur — Infra formunun kendisi (bölüm 9) global Redux state'i ile değil, bileşen içi useState/useEffect ile yönetilir; bu bilinçli bir tasarım tercihidir (form akışı tek bir sayfa/bileşen ağacında yaşar, çapraz sayfa paylaşımına ihtiyaç yoktur).
| Slice | Dosya | State şekli | Amaç |
|---|---|---|---|
admin |
store/slices/adminSlice.tsx |
{ token: string | null, user: object | null } |
JWT ve giriş yapmış kullanıcı bilgisi; redux-persist ile kalıcı. |
Kaynaklar: dashboard/src/store/index.tsx, dashboard/src/store/slices/adminSlice.tsx.
4.5 API / Service Katmanı (services/)
Paylaşılan bir axios instance (http) Bearer token interceptor'ı ve 401 → otomatik logout davranışını uygular; bunun üzerine kurulu servis modülleri:
| Servis dosyası | Kapsadığı uçlar | Not |
|---|---|---|
authApi.ts |
/api/v1/auth/login, /api/v1/auth/me |
Login sonrası /me ile ikinci doğrulama. |
peopleApi.ts |
/api/v1/users CRUD |
Personel yönetimi. |
reminderService.ts |
/api/reminders, /api/reminders/assignees |
Hatırlatıcı listesi/plan kaydetme. |
infraLogService.ts |
/infra-logs/event |
Yalnızca istemci tarafı olaylar (logout, pdf_downloaded) — diğer tüm loglar zaten backend'de üretilir. |
itService.ts |
Infra formunun tüm admin + public uçları | Bkz. 4.6 — projenin en kritik service dosyası. |
Kaynaklar: dashboard/src/services/authApi.ts, peopleApi.ts, reminderService.ts, infraLogService.ts, itService.ts.
4.6 Form Mimarisi — itService.ts ve İki Ayrı Kimlik Doğrulama Yolu
itService.ts, Infra formunun tüm backend çağrılarını topluyor ve bilinçli olarak iki farklı HTTP istemcisi kullanıyor:
- Admin/personel uçları (
getOrganizations,listInfraRecords,saveInfraInfo,sendInfraMail,sendReviewResultMail,askBil,closeAdminReview,saveAdminGeneralNote) → paylaşılanhttp(Bearer token + 401→logout). - Public/müşteri uçları (
exchangePublicSession,getPublicInfraRecord,submitPublicProgress,setPublicSectionStatus) → düzaxios+withCredentials: true(token yok;http'nin 401→logout davranışı burada anlamsız olurdu çünkü public tarafta hiç JWT yok).
Önemli bulgu — kısmen ölü kod: itService.getPublicProgress ve itService.savePublicProgressDraft, backend'de karşılığı olmayan /infra-public-progress (GET/POST) uç noktasını çağırır. Bu iki fonksiyon proje genelinde (dashboard/src) hiçbir bileşen tarafından çağrılmaz — grep ile doğrulanmıştır. Aktif kullanım referansı tespit edilemedi. Gerçek "kısmi taslak kaydetme" işlevi yerine submitPublicProgress (final gönderim) ve setPublicSectionStatus (bölüm bazlı tik) kullanılmaktadır (bkz. bölüm 24.1).
withInfraBase() yardımcı fonksiyonu, VITE_INFRA_API_BASE_URL/VITE_API_BASE_URL env değişkeni boşsa relative path'e düşer (prod'da aynı origin üzerinden nginx proxy ile çözülür).
Kaynaklar: dashboard/src/services/itService.ts, backend/src/routes/infraPublicRecord.routes.js (karşılaştırma için), proje geneli grep taraması.
4.7 Public Form / PublicITView
PublicITView.tsx, müşterinin /form adresinde gördüğü kapsayıcı bileşendir. Mount olduğunda önce exchangePublicSession (bootstrap — yalnızca bir kez, mail linkinden gelen 302 sonrası zaten cookie yazılmış durumdadır ama sayfa doğrudan /form'a atlanırsa da session'ın var olup olmadığı kontrol edilir), ardından getPublicInfraRecord (GET /infra-public-record, cookie otomatik gider) ile whitelist'li kaydı çeker. mode='public' prop'u ile ITPreview.tsx'i render eder — bu modda: admin-only alanlar (IQVizyon Kontrolü paneli, Kurulum Kararı, tam steps[] geçmişi) hiç render edilmez, yalnızca müşterinin doldurması gereken alanlar (Sunucu Odası/Statik IP, Tezgah Bilgileri, Sistem Kapasitesi "Sağlanan" kolonu, Uzaktan Erişim, Genel Not) düzenlenebilir haldedir, "Gönder" butonu görünür.
Kaynaklar: dashboard/src/components/it/PublicITView.tsx, ITPreview.tsx, itService.ts.
4.8 Admin / Edit Mode
Admin tarafı iki alt-moda ayrılır (mode prop'u ITPreview.tsx'e üç değerden biri olarak geçer): 'new' (ilk kayıt oluşturma — ITForm.tsx), 'admin-existing' (var olan bir kaydın önizleme/düzenleme ekranı — ITPreview.tsx, tam yetkiyle). admin-existing modunda: tüm bölümler düzenlenebilir (müşterinin doldurduğu "İstenen" kapasite gönderim sonrası kilitlenir — bkz. bölüm 5.4/11), "IQVizyon Kontrolü" paneli (AdminReviewPanel.tsx) görünür ve 27 kalemlik onay/not girişine izin verir, "Kurulum Kararı" seçimi (ready/conditional_ready/not_ready) yapılabilir, "Süreç Geçmişi" (WorkflowHistory.tsx) tüm steps[] adımlarını zaman çizelgesi olarak gösterir, "Mail Gönder" ve "Kontrol Sonucu Maili" butonları aktiftir.
Kaynaklar: dashboard/src/components/it/index.tsx, ITForm.tsx, ITPreview.tsx, AdminReviewPanel.tsx, WorkflowHistory.tsx.
4.9 Responsive Davranış (Frontend Uygulaması)
Frontend, useBreakpoint(breakPoint = 768) adlı kendi hook'unu (components/hooks/breakpoint.ts) kullanarak window.innerWidth < breakPoint mantığıyla mobil/masaüstü ayrımı yapar; bu hook antd'nin kendi grid md/lg breakpoint sistemiyle birlikte (ITForm.tsx, ServerAndMachineSection.tsx grid kırılımları için) kullanılır. Kesme noktalarının tam değerleri ve gerekçesi bölüm 22'de kapsamlı olarak ele alınmıştır — bu alt bölüm yalnızca hangi frontend mekanizmasının (hook + CSS + antd grid) bu davranışı ürettiğini belgeler, sayısal detaylar için bölüm 22'ye bakınız.
Kaynaklar: dashboard/src/components/hooks/breakpoint.ts, dashboard/src/components/it/ITForm.tsx, ServerAndMachineSection.tsx.
4.10 Tema / UI Component Yapısı
UI bileşenleri iki katmandan gelir: antd 5 (genel amaçlı Table, Modal, Form, Select, DatePicker vb.) ve @iqvizyonui/react-components (IQVizyon kurumsal tasarım sistemi — Field, Input, Label, Select gibi marka standardına uygun sarmalayıcı bileşenler, ör. ITForm.tsx içinde doğrudan import edilerek kullanılır). Domain'e özgü bileşenler (components/it/*) bu iki katmanı birleştirerek üretilmiştir; ayrı bir üçüncü, projeye özel "tema sistemi"/design-token dosyası bu turda tespit edilmemiştir — Kaynak koddan kesin olarak doğrulanamadı (kapsamlı bir tema dosyası taraması bu turda yapılmadı, yalnızca bileşen importlarından çıkarım yapılmıştır).
Kaynaklar: dashboard/src/components/it/ITForm.tsx, dashboard/package.json (antd, @iqvizyonui/react-components bağımlılıkları).
4.11 PDF / Export Frontend Davranışı
PDF butonu hem admin hem public ekranda, sayfa başlığının yanında (headerActionsContainer portalı ile) render edilir; tıklandığında pdfLoading state'i butonun tekrar tıklanmasını engeller (çift üretim/tıklama koruması). Public tarafta PDF indirme, infraLogService.logInfraClientEvent('pdf_downloaded', infraId) ile backend'e loglanır — bu, infra-logs koleksiyonuna yazılan, istemci tarafında üretildiği için backend'in doğrudan gözlemleyemediği iki olaydan biridir (diğeri logout). PDF üretiminin kendisi tamamen istemci tarafında (PDFReport.ts) gerçekleşir; backend'de ayrı bir PDF-render uç noktası yoktur. Detaylı içerik/alan kapsamı için bölüm 16'ya bakınız.
Kaynaklar: dashboard/src/components/it/PDFReport.ts, ITPreview.tsx (PDF buton mantığı grep ile doğrulandı), infraLogService.ts.
4.12 Bildirim / Modal / Popup Yapısı
Kullanıcıya dönük anlık bildirimler antd'nin message/notification API'leri üzerinden verilir (ör. kayıt kaydedildi/güncellendi, mail gönderildi, hata mesajları) — antd bir bağımlılık olduğundan bu API'ler projede kullanılabilir durumdadır; kapsamlı bir kullanım noktası envanteri bu turda çıkarılmamıştır. Modal bileşenleri belirgin iki noktada kullanılır: AuthorizedPersonModal.tsx (yetkili kişi ekle/düzenle) ve MachinePickerModal.tsx (sabit marka listesinden çoklu makine seçimi, "Diğer" serbest metin dahil). Bölüm bazlı durum kontrolü (SectionStatusControl.tsx) ayrı bir modal değil, satır-içi tik/kalem kontrolüdür (bkz. bölüm 11).
Kaynaklar: dashboard/src/components/it/AuthorizedPersonModal.tsx, MachinePickerModal.tsx, SectionStatusControl.tsx.
4.13 Component Ağacı — components/it/
| Dosya | Sorumluluk |
|---|---|
index.tsx |
Sayfa kapsayıcısı — yeni kayıt / mevcut kayıt seçimi, ITForm + ITPreview orkestrasyonu. |
ITForm.tsx |
İlk kayıt formu: Firma/Müşteri, Yetkili Kişi, Düzenleyen, Düzenleme Tarihi, Makine, Sistem, Durum. |
ITPreview.tsx (2616 satır — projenin en büyük dosyası) |
Kayıt önizleme + tüm form bölümlerinin (Kaynak…Kontrol) render'ı, admin/public mod ayrımı, Gönder/Kaydet/Güncelle/Tamamlandı-Tamamlanmadı akışları, PDF butonu. |
AdminReviewPanel.tsx |
"IQVizyon Kontrolü" (12. bölüm) — 27 kalemlik konsolide inceleme, onay/not, Kurulum Kararı. |
ServerAndMachineSection.tsx (1890 satır) |
Server ve Tezgah/Makine Bilgileri tabloları, Sunucu Odası/Statik IP, Sağlanan Kapasite. |
RemoteAccessPanel.tsx |
Uzaktan erişim (VPN/AnyDesk) seçimi ve alanları. |
RequirementSection.tsx |
Gereksinim grupları için ortak tablo yapısı (Sunucu/Ağ/Uzaktan Erişim gereksinimleri). |
SecurityControlTable.tsx |
10. Güvenlik Kontrolü tablosu (satır bazlı Evet/Hayır + not). |
SectionStatusControl.tsx |
Bölüm bazlı "Durum ✓/✎" tik/kalem kontrolü. |
WorkflowHistory.tsx (923 satır) |
Süreç geçmişi (steps[]) zaman çizelgesi görünümü. |
AuthorizedPersonModal.tsx |
Yetkili kişi ekle/düzenle modalı. |
MachinePickerModal.tsx |
Sabit marka listesinden çoklu makine seçimi ("Diğer" serbest metin dahil). |
PublicITView.tsx |
Müşteri public form kapsayıcısı (bkz. bölüm 4.7 ve 7). |
constants.ts |
27 kalemlik REQUIREMENT_ITEMS, sabit metinler, seçenek listeleri (bkz. bölüm 10). |
helpers.ts (1005 satır) |
Ortak saf fonksiyonlar (normalizasyon, hasPendingCustomerSubmission, tarih formatlama…). |
PDFReport.ts |
PDF üretim mantığı (bkz. bölüm 16). |
Kaynaklar: dashboard/src/components/it/*.tsx, *.ts (satır sayıları wc -l ile doğrulandı).
5. Backend Mimarisi
5.1 Katman Mimarisi (Genel Bakış)
routes/ --> controllers/ --> services/ --> repositories/ --> models/ (raw collection) --> MongoDB
|
middleware/ (auth, publicSession, errorHandler)
|
utils/ (apiError, asyncHandler, authorizedPeople, frontendUrl,
infraStatus, publicSession, regex)
ODM kullanılmaz — tüm repository'ler MongoDB resmi sürücüsünün ham collection() API'sini kullanır ({ _id, ...rest } → { _id: hex string, ...rest } dönüşümü ortak bir toRecord fonksiyonuyla her repository'de tekrarlanır). Katmanlar arası bağımlılık her zaman tek yönlüdür: bir controller asla bir repository'yi doğrudan çağırmaz, bir servis asla bir route dosyasını import etmez — bağımlılıklar app.js seviyesinde (dependency injection benzeri) monte edilir.
Kaynaklar: backend/src/repositories/*.js, backend/src/models/*.js.
5.2 Entrypoint — server.js
backend/src/server.js, Express uygulamasını (createApp) çalıştırılabilir bir HTTP sunucusuna bağlayan giriş noktasıdır: config/env.js'ten yapılandırmayı okur, config/db.js ile MongoDB'ye bağlanır, bağlantı başarılıysa app.listen(PORT) çağrılır. Uygulamanın MongoDB'siz başlamadığı — yani veritabanı bağlantısı sunucu açılışının bir ön koşulu olduğu — config/db.js'teki bağlantı akışından çıkarılabilir.
Kaynaklar: backend/src/server.js, backend/src/config/db.js, backend/src/config/env.js.
5.3 Express App Factory — createApp(deps)
backend/src/app.js, createApp(deps) adlı bir fabrika fonksiyonu ihraç eder: bağımlılıklar (repository/servis örnekleri, jwtSecret vb.) parametre olarak enjekte edilir, böylece testler gerçek MongoDB bağlantısı kurmadan sahte (mock/in-memory) bağımlılıklarla tam bir Express app örneği oluşturabilir (bkz. bölüm 20 — backend integration testleri bu deseni kullanır). Bu, projenin test edilebilirlik için bilinçli bir mimari tercihidir.
Kaynaklar: backend/src/app.js, backend/tests/integration/*.test.js.
5.4 app.js Router Mount Haritası
app.js şu router'ları mount eder: /api/v1/auth, /api/v1/users (people), /organizations (prefix'siz, kasıtlı istisna), /infra-record (prefix'siz), /health, /api/it (bil), /api/reminders, /infra-logs, kök seviyede (prefix'siz) infraPublicRecord router'ı (/infra-public-session, /infra-public-record, /infra-public-progress-submit, /infra-public-section-status, /it/public-access/:token, geriye dönük /it/public*) ve yine kök seviyede infraAdminReview router'ı (/infra-public-review-close, /infra-admin-general-note). Swagger UI /api-docs ve /openapi.json da backend'den servis edilir (React route'u değildir — bkz. bölüm 4.2).
/organizations ve /infra-record'un /api/v1 prefix'i almaması bilinçli bir istisnadır — bu iki uç, dev'de Vite proxy listesine ve prod'da nginx'e ayrıca eklenmiştir (bkz. bölüm 19.3).
Kaynaklar: backend/src/app.js, backend/src/routes/infraPublicRecord.routes.js, backend/src/routes/infraAdminReview.routes.js, dashboard/src/routes/api.tsx.
5.5 Middleware Pipeline
İstek işleme sırası (genel → özel): (1) CORS (CORS_ORIGIN'e göre yapılandırılmış), (2) JSON body parser, (3) route-özel rate limiter'lar (loginLimiter, publicLimiter — express-rate-limit), (4) route-özel kimlik doğrulama middleware'i — admin uçlarında createAuthMiddleware(jwtSecret) (Bearer JWT doğrular, req.user'ı doldurur), public uçlarında requirePublicSession (HttpOnly cookie doğrular, req.publicSession'ı doldurur), (5) route handler (controller), (6) merkezi errorHandler.middleware.js — zincirin sonunda, tüm route'lardan sonra mount edilen tek bir hata yakalayıcı.
Kaynaklar: backend/src/middleware/auth.middleware.js, publicSession.middleware.js, errorHandler.middleware.js, backend/src/app.js.
5.6 Routes → Controllers → Services → Repositories Katmanlaşması
Her domain (auth, people, organizations, infraRecord, infraPublicRecord, infraAdminReview, it/bil, reminder, infraLog) bu dört katmanı ayrı ayrı dosyalarda uygular: route dosyası yalnızca HTTP method/path/middleware bağlar; controller yalnızca HTTP request/response sözleşmesini (body okuma, status kodu, hata fırlatma) yönetir; service iş mantığını (doğrulama, iş kuralı, whitelist, bildirim tetikleme) içerir; repository yalnızca MongoDB sorgusu/yazması yapar. infraPublicRecord.controller.js ve infraAdminReview aynı InfraRecordService'i kullanır — ikinci bir servis kopyası yoktur, bu da public ve admin akışlarının iş kurallarının (ör. whitelist, steps[] append mantığı) tek bir yerde tutarlı kalmasını garanti eder.
Kaynaklar: backend/src/controllers/*.js, backend/src/services/*.js, backend/src/repositories/*.js.
5.7 Servis Katmanı Envanteri
| Servis | Sorumluluk |
|---|---|
auth.service.js |
Login (bcrypt + JWT imzalama), me() (JWT doğrulanmış kullanıcı bilgisi). |
people.service.js |
Kişi (kullanıcı) CRUD, kendi hesabında yetki yükseltme engeli. |
organizations.service.js |
Yalnızca list() — ince katman. |
infraRecord.service.js (1443 satır) |
Infra kaydı CRUD, public token/session, mail gönderimi, admin review kapanışı, müşteri gönderim işleme, bölüm durumu — bkz. bölüm 5.8. |
infraLog.service.js |
Merkezi kullanıcı işlem logu (infra-logs koleksiyonu) — asla ana işlemi bozmaz. |
infraSubmitNotifier.service.js |
Müşteri "Gönder" sonrası mail+Telegram bildirimi (birbirinden bağımsız, hatasız asla exception fırlatmaz). |
reminder.service.js (483 satır) |
Hatırlatıcı listesi (mevcut Infra kayıtlarından türetilen görünüm) + plan kaydetme. |
reminderNotifier.service.js |
Zamanı gelmiş hatırlatıcı planları için Telegram bildirimi — periyodik setInterval döngüsü. |
mailService.js |
Nodemailer SMTP transporter (Office365 587/STARTTLS), önbelleğe alınmış tekil transporter. |
telegram.service.js |
Telegram Bot API tek gönderim noktası. |
bil.service.js |
/api/it/bil — Gemini tabanlı sistem kapasitesi önerisi. |
health.service.js |
Liveness/readiness. |
Kaynaklar: backend/src/services/*.js.
5.8 InfraRecordService — Ana İş Mantığı
En kritik servistir; öne çıkan noktalar:
- Public token üretimi:
crypto.randomBytes(24).toString('base64url')— 24 byte, tahmin edilemez. Eski kayıtlarda token yoksaensurePublicToken()ile bir kez üretilip kalıcı hale getirilir. hasPendingCustomerSubmission/hasAnyCustomerSubmission: yeni bir durum alanı icat edilmeden, kaydınsteps[]dizisi üzerinden türetilen iş kuralları (son müşteri adımı soniqvizyon_controladımından sonra mı?). Frontend (helpers.ts) ile birebir aynı mantık backend'de de bağımsız olarak uygulanır — güvenlik amaçlı çift kontrol.REQUESTED_CAPACITY_FIELDSkilidi: müşteri formu bir kez gönderildiyse, admin PUT'u "İstenen" kapasite alanlarını (device_type,cpu_core,ram_gb, …) artık değiştiremez —update()bu alanları payload'dan siler.submitPublicProgress: mass-assignment yok — yalnızca 6 bilinen alan (customer_general_note,public_progress,server_room_available,customer_static_ip,machine_details,provided_capacity,remote_access) gövdeden okunur. Yeni bircustomer_controladımı derin kopya olaraksteps[]'e eklenir; aynı andaadmin_review_progresssıfırlanır (yeni kontrol turu), Kurulum Kararı ve önceki karar notu temizlenir,status: 0. Başarılı DB yazımından sonra (asla önce değil) mail+Telegram bildirimi tetiklenir; bildirim katmanı hata verse bile kayıt geri alınmaz. 60 saniyelik dedupe penceresi (SUBMIT_NOTIFY_DEDUPE_MS) çift tıklamada tekrar bildirim gitmesini engeller.closeAdminReview:decisionalanına görestatus(0/1) vereview_status(open/closed) belirlenir — bu, dashboard'daki "Durum"/"Kurulum" ayrımının tek kaynağıdır (bkz.utils/infraStatus.js). Yeni biriqvizyon_controladımısteps[]'e eklenir.getPublicRecord: açık bir whitelist (PUBLIC_FIELDS, ~40 alan) ile admin-içi alanlar (ör.reviewed_by_id,user_id, tamadmin_review_progress) dışarıda bırakılır.remote_accessiçindeki parolalarmaskRemoteAccess()ile her zaman maskelenir — public yanıtta hiçbir zaman ham parola dönmez.- Mail gönderimi: her alıcıya ayrı ayrı
sendMailçağrısı yapılır (topluto: [a,b]kullanılmaz) — her alıcı yalnızca kendi adresini görsün diye.
Kaynaklar: backend/src/services/infraRecord.service.js (~1443 satır).
5.9 Controller/Validator Katmanı
infraRecord.controller.js ve infraRecord.validation.js: request/response sözleşmeleri, ObjectId doğrulama, sunucu tarafında mail alıcısı çözümlemesi (req.user'dan bağımsız güvenilir kaynak), server-assigned/removed alan listeleri. infraPublicRecord.controller.js ve infraAdminReview aynı InfraRecordService'i kullanır.
Kaynaklar: backend/src/controllers/infraRecord.controller.js, backend/src/validators/infraRecord.validation.js.
5.10 MongoDB Bağlantısı (config/db.js)
config/db.js, MONGODB_URI/MONGODB_DB env değişkenlerinden resmi mongodb sürücüsüyle tek bir bağlantı kurar ve db referansını server.js/app.js'e döner; koleksiyon adları da env'den okunur (bkz. bölüm 18) — bu sayede test ortamı farklı bir veritabanı adı/host kullanarak prod verisinden izole çalışabilir.
Kaynaklar: backend/src/config/db.js, .env.example.
5.11 Hata İşleme Sözleşmesi
errorHandler.middleware.js, zincirin sonunda mount edilen tek merkezi hata yakalayıcıdır. utils/apiError.js'teki ApiError sınıfı (statusCode + mesaj) fırlatılan hatalar doğrudan o status kodu ve mesajla; beklenmeyen (fırlatılmamış tip) hatalar ise 500 + genel bir mesajla döner — ham stack trace veya iç sistem detayı istemciye asla sızdırılmaz (bkz. bölüm 23.1, hata sanitizasyonu). utils/asyncHandler.js, her async route handler'ı sarmalayarak reddedilen promise'lerin otomatik olarak bu merkezi handler'a düşmesini sağlar — controller'larda tekrar tekrar try/catch yazılmasını gereksiz kılar.
Kaynaklar: backend/src/middleware/errorHandler.middleware.js, backend/src/utils/apiError.js, backend/src/utils/asyncHandler.js.
5.12 Health Endpoint
GET /health (liveness — sunucu sürecinin ayakta olduğunu doğrular, bağımlılık kontrolü yapmaz) ve GET /health/ready (readiness — gerçek bir MongoDB ping'i içerir; Mongo erişilemezse "unhealthy" döner). Docker backend servisinin HEALTHCHECK'i bu /health/ready ucunu kullanır (bkz. bölüm 19.2).
Kaynaklar: backend/src/services/health.service.js, backend/src/routes/health.routes.js, backend/Dockerfile.
5.13 Loglama
Uygulama içi iş-olayı logu (infra-logs koleksiyonu, infraLog.service.js) kullanıcı bazlı, tek dokümana $push ile eklenen bir audit-trail'dir — bu genel amaçlı bir sistem/HTTP access log çerçevesi (ör. winston, morgan) değildir. backend/package.json bağımlılıklarında ayrı bir genel loglama kütüphanesi bu turda tespit edilmemiştir — Kaynaklar koddan kesin olarak doğrulanamadı (kapsamlı bir package.json taraması bu amaçla yapılmadı); konsola (console.log/console.error) yapılan olası doğrudan loglamalar bu turda satır satır incelenmedi.
Kaynaklar: backend/src/services/infraLog.service.js.
5.14 Graceful Shutdown
Bu turda server.js içinde SIGTERM/SIGINT sinyallerini yakalayıp HTTP sunucusunu ve MongoDB bağlantısını düzenli kapatan açık bir graceful-shutdown bloğu doğrulanmamıştır — Kaynak koddan kesin olarak doğrulanamadı. Docker Compose'da backend servisi bir healthcheck'e sahiptir (bkz. bölüm 19.1) ama bu, süreç seviyesinde bir graceful-shutdown garantisi vermez; konteyner orkestrasyonu (Docker/Compose) varsayılan SIGTERM davranışına güvenir.
Kaynaklar: backend/src/server.js (bu turda graceful-shutdown bloğu için özel olarak taranmadı).
5.15 API Versiyonlama
Kısmi ve tutarsız bir versiyonlama vardır: auth ve people (users) route'ları /api/v1/... prefix'i altında mount edilirken, organizations, infra-record, infra-public-*, infra-logs, infra-admin-*, /api/it, /api/reminders gibi uçların hiçbiri v1 taşımaz (bazıları hiç /api prefix'i bile almaz — bkz. bölüm 5.4). Bu, projenin tutarlı, tek bir API versiyonlama stratejisi uygulamadığının açık bir göstergesidir; yeni bir major sürüm (ör. v2) ihtiyacı doğarsa, hangi uçların nasıl taşınacağına dair önceden tanımlı bir plan kaynak kodda mevcut değildir.
Kaynaklar: backend/src/app.js, tüm backend/src/routes/*.js dosyalarının path önekleri.
6. Kimlik Doğrulama ve Yetkilendirme
6.1 Authentication — Admin/Personel JWT Akışı
POST /api/v1/auth/login → auth.service.js: kullanıcı adı case-insensitive tam eşleşme (user.repository.js — buildExactInsensitiveRegex), status !== 'active' ise reddedilir, bcrypt.compare ile parola doğrulanır, JWT { _id, username, full_name, role, permissions, company_id, organization_id } payload'ıyla JWT_SECRET ile imzalanır (JWT_EXPIRES_IN, varsayılan 12h). GET /api/v1/auth/me, doğrulanmış req.user._id'den kullanıcıyı tekrar okur (spoof edilemez — payload'daki diğer alanlara güvenilmez, yalnızca _id bir DB sorgusu tetikler).
Kaynaklar: backend/src/services/auth.service.js, backend/src/repositories/user.repository.js.
6.2 Authorization — Rol/İzin Modeli
PermissionKey yalnızca users.read/create/update/delete içerir (Infra'da başka bir modül/kaynak için izin tanımı yoktur). Roller: superadmin, companyadmin, organizationadmin, admin → bu dört rol tam yetkiye (tüm users.* izinlerine) sahiptir; user rolü → varsayılan olarak hiçbir izne sahip değildir (none-by-default). Buna ek olarak satır-seviyesi bir kısıtlama vardır: user rolündeki bir kullanıcı yalnızca kendi kaydını görebilir/düzenleyebilir (self-record restriction). isSelfPrivilegeEscalationRestricted — bir kullanıcı kendi rolünü/durumunu/iznini değiştiremez (admin-tier olmayan roller için), yalnızca değer gerçekten değişiyorsa engellenir (no-op istekler serbesttir). Tüm bu kontroller yalnızca server-side'dır — auth.middleware.js ve people.service.js içinde uygulanır.
Kaynaklar: backend/src/middleware/auth.middleware.js, backend/src/services/people.service.js, backend/src/routes/people.routes.js (requirePermission('users.read'|'users.create'|'users.update'|'users.delete')).
6.3 Middleware Katmanı
createAuthMiddleware(jwtSecret) Bearer token'ı doğrular (Authorization: Bearer <jwt> header'ından okur), geçersiz/süresi dolmuş token'da 401 döner, geçerliyse req.user'a JWT payload'ını yerleştirir. requirePermission(key), req.user.permissions (veya rol bazlı tam-yetki kısayolu) üzerinden route-level yetkilendirme sağlayan ikinci bir middleware katmanıdır — createAuthMiddleware'in sonrasında, route-özel olarak zincire eklenir (yalnızca people.routes.js bu ikinci katmanı kullanır; diğer admin route'ları yalnızca kimlik doğrulaması ister, ek bir izin kontrolü yapmaz).
Kaynaklar: backend/src/middleware/auth.middleware.js.
6.4 Public Erişim — Ayrı Bir Mekanizma
Müşteri/public form tarafı, JWT Bearer akışını hiç kullanmaz. Bunun yerine bootstrap sırasında kurulan bir HttpOnly session cookie'sine dayanan tamamen ayrı bir mekanizma çalışır (requirePublicSession middleware'i) — bu mekanizmanın tam akışı, cookie ayarları ve session doğrulaması bölüm 7'de ayrıntılı olarak ele alınmıştır. Burada vurgulanması gereken mimari nokta: admin JWT'si ile public session token'ı aynı JWT_SECRET ile imzalanır ama purpose alanı ('infra_public_session') ile ayrıştırılır — bkz. 6.5.
Kaynaklar: backend/src/middleware/publicSession.middleware.js, backend/src/utils/publicSession.js.
6.5 Ortak Secret Kısıtı
JWT admin oturumu ile müşteri public session'ı aynı JWT_SECRET ile imzalanır — yeni bir secret icat edilmemiştir, ancak purpose: 'infra_public_session' alanı ile ayrıştırılır. verifyPublicSessionToken, purpose uyuşmayan bir token'ı (örn. bir admin JWT'si cookie'ye elle yerleştirilirse) geçersiz sayar; ancak kriptografik anahtar aynı olduğu için, tek bir sızmış JWT_SECRET her iki jeton türünü de sahtelenebilir kılar — bu, bölüm 23.2'de "Bilinen Güvenlik Kısıtları" altında tekrar ele alınmıştır.
Kaynaklar: backend/src/utils/publicSession.js.
6.6 Frontend Guard'ları — UX Kolaylığı, Güvenlik Sınırı Değil
RequireAuth ve RequirePermission (bkz. bölüm 4.3), backend'deki gerçek kontrolleri birebir taklit eden ama sahtelenebilir istemci-taraflı kontrollerdir. Kaynak kod bunu açıkça belirtir: requirePermission.tsx'in izin çözümlemesi backend'deki PermissionKey sözleşmesiyle birebir aynıdır fakat "bu yalnızca bir UI kolaylığıdır" — gerçek, sahtelenemez yetki kontrolü her zaman backend'dedir (people.routes.js → requirePermission middleware'i). Bir kullanıcı tarayıcı geliştirici araçlarıyla frontend guard'ını atlatsa bile, backend auth.middleware.js/requirePermission kontrolleri isteği yine de reddeder.
Kaynaklar: dashboard/src/routes/requireAuth.tsx, dashboard/src/routes/requirePermission.tsx, backend/src/middleware/auth.middleware.js.
7. Public / Müşteri Erişim Mimarisi
7.1 Mail Linki → Session Bootstrap Akışı
Mail linki: {FRONTEND_BASE_URL}/it/public-access/<public_token>
↓ GET (backend, React SPA'ya HİÇ uğramaz)
infraPublicRecord.controller.js -> publicAccessRedirect
↓ token doğrulanır (PUBLIC_TOKEN_PATTERN + DB lookup)
↓ HttpOnly session cookie yazılır: iqv_infra_public_session
↓ 302 redirect
/form (React SPA burada mount edilir — token URL'de HİÇBİR ZAMAN görünmez)
↓ PublicITView.tsx -> GET /infra-public-record (cookie otomatik gider)
Session, GET /it/public-access/:publicToken uç noktasında (kök seviyede mount edilen infraPublicRecord router'ı, bkz. bölüm 5.4) oluşturulur — mail linkindeki public_token, bu tek istekte doğrulanır ve hemen ardından cookie'ye dönüştürülür; token bu noktadan sonra hiçbir istekte tekrar taşınmaz. Alternatif olarak POST /infra-public-session uç noktası da aynı bootstrap işlemini gövdede gönderilen bir publicToken ile yapar (SPA zaten /form'daysa ve session henüz kurulmamışsa kullanılan yol).
Eski /it/public ve /it/public/<token> linkleri (route rename öncesi) backend tarafında aynı şekilde /form'a 302 ile yönlendirilir (geriye dönük uyumluluk) — hem dashboard/nginx.conf hem vite.config.ts dev proxy'sinde bu path'ler backend'e proxy'lenir (SPA fallback'e düşmemesi için).
Kaynaklar: backend/src/routes/infraPublicRecord.routes.js, dashboard/src/components/it/PublicITView.tsx, dashboard/src/routes/web.tsx, dashboard/nginx.conf, dashboard/vite.config.ts, tests/e2e/public-form.spec.ts.
7.2 Cookie Ayarları — HttpOnly, Secure, SameSite
utils/publicSession.js, cookie'yi şu bayraklarla yazar: httpOnly: true (JavaScript'ten okunamaz — XSS ile çalınamaz), sameSite: 'lax' (çapraz-site POST'larda gönderilmez, aynı-site navigasyonda gönderilir — mail linkinden gelen GET navigasyonu için doğru denge), secure: NODE_ENV === 'production' (yalnızca prod'da HTTPS zorunluluğu; local/dev'de HTTP üzerinden de çalışabilmesi için NODE_ENV !== 'production' iken secure: false). Cookie içeriği: { infraId, purpose: 'infra_public_session' } payload'lı bir JWT, JWT_SECRET ile imzalı, TTL 24 saat. cookie-parser bağımlılığı eklenmemiş — tek, bilinen cookie adı için minimal, elle yazılmış bir ayrıştırıcı kullanılır.
Kaynaklar: backend/src/utils/publicSession.js.
7.3 Session Doğrulaması — requirePublicSession
publicSession.middleware.js içindeki requirePublicSession, gelen isteğin iqv_infra_public_session cookie'sini okur, verifyPublicSessionToken ile doğrular (imza + exp + purpose === 'infra_public_session'). verifyPublicSessionToken hiçbir koşulda throw etmez — geçersiz/süresi dolmuş/purpose uyuşmayan (örn. bir admin JWT'si cookie'ye elle yerleştirilirse) her durumda null döner ve middleware bu durumda isteği 401 ile reddeder. Doğrulama başarılıysa req.publicSession = { infraId } set edilir; sonraki controller'lar (getRecord, submitProgress, setSectionStatus) bu infraId'yi kullanır.
Kaynaklar: backend/src/middleware/publicSession.middleware.js, backend/src/utils/publicSession.js.
7.4 Müşteri Hangi Kayıt Üzerinde İşlem Yapabiliyor
Müşteri yalnızca kendisine mail ile gönderilen public_token'ın işaret ettiği tek bir Infra kaydı üzerinde işlem yapabilir — session cookie'sindeki infraId, bootstrap anında bu token'dan çözülüp cookie'ye gömülür ve sonraki her istekte (GET /infra-public-record, POST /infra-public-progress-submit, POST /infra-public-section-status) bu sabit infraId kullanılır. İstek gövdesinde/URL'inde farklı bir kayıt kimliği kabul edilmez — gövdeden id/infra_id gibi bir alan okunmaz, tamamen cookie'deki değere güvenilir.
Kaynaklar: backend/src/controllers/infraPublicRecord.controller.js, backend/src/middleware/publicSession.middleware.js.
7.5 Başka Kayda Erişim Nasıl Engelleniyor
Bir müşteri başka bir Infra kaydına erişmeye çalıştığında iki bağımsız engel devreye girer: (1) cookie'deki infraId sabittir ve müşteri tarafından değiştirilemez (HttpOnly — JavaScript ile okunup değiştirilemez; imzalı JWT olduğu için ham metin olarak da manipüle edilemez — imza doğrulaması başarısız olur). (2) Farklı bir kayda erişmek isteyen bir müşteri, o kaydın kendi public_token'ını (kendi mail linkini) bilmedikçe hiçbir zaman o kayıt için bir session kuramaz — public_token 24 byte crypto.randomBytes ile üretildiği için tahmin edilemez (bkz. bölüm 5.8, 23.1).
Kaynaklar: backend/src/utils/publicSession.js, backend/src/services/infraRecord.service.js (public token üretimi).
7.6 Session Expiration
Session cookie'si 24 saatlik sabit bir TTL ile imzalanır (JWT exp claim'i). Süre dolduğunda verifyPublicSessionToken null döner ve requirePublicSession isteği 401 ile reddeder — müşteri tekrar mail linkine tıklayarak (veya POST /infra-public-session ile, eğer henüz elindeki token geçerliyse) yeni bir session bootstrap etmesi gerekir. public_token'ın kendisinin (mail linkindeki asıl anahtar) ayrı bir süre sınırı kaynak kodda tespit edilmemiştir — token kayıt var olduğu sürece geçerli görünmektedir (ensurePublicToken yalnızca eksikse üretir, süre kontrolü yapmaz). Kaynak koddan kesin olarak doğrulanamadı: public_token'ın kendisi için ayrı bir expiry/rotasyon mekanizması bu turda tespit edilememiştir.
Kaynaklar: backend/src/utils/publicSession.js, backend/src/services/infraRecord.service.js.
7.7 Public Uç Nokta Envanteri
| Method | Path | Auth | Not |
|---|---|---|---|
POST |
/infra-public-session |
publicToken (gövdede, tek seferlik) |
Bootstrap — cookie yazar, kayıt döndürmez. |
GET |
/it/public-access/:publicToken |
publicToken (URL) |
Mail linkinin gerçek hedefi — 302 → /form. |
GET |
/it/public/:publicToken, GET /it/public |
publicToken |
Geriye dönük uyumluluk — 302 → /form. |
GET |
/infra-public-record |
requirePublicSession (cookie) |
Müşteri ekranının okuduğu whitelist'li kayıt. |
POST |
/infra-public-progress-submit |
requirePublicSession |
Final "Gönder". |
POST |
/infra-public-section-status |
requirePublicSession |
Bölüm bazlı Durum tik/kalem. |
Rate limit: tüm public uçlar express-rate-limit ile 5 dakikada 60 istek (publicLimiter), auth.routes.js'teki loginLimiter ile aynı desen.
Aktif kullanım doğrulandı — /infra-public-progress (GET/POST) backend'de tanımlı değildir; frontend'deki karşılığı (itService.getPublicProgress/savePublicProgressDraft) da hiçbir yerden çağrılmaz (bkz. bölüm 4.6). Bu iki endpoint projenin gerçek akışının parçası değildir.
7.8 OpenVPN Sabit IP — Müşteriye Kasıtlı Olarak Açık
FIXED_REQUIREMENT_TEXT sabiti (dashboard/src/components/it/constants.ts), müşteriye gösterilecek standart gereksinim metinlerini içerir — bunlardan biri gerçek, kasıtlı olarak müşteriye açık, statik OpenVPN IP adresidir: 135.181.251.237. Bu bir sızıntı değildir; müşterinin VPN kurulumunda kullanması gereken sabit IQVizyon uç noktasıdır ve FIXED_REQUIREMENT_TEXT içinde kasıtlı olarak yer alır — public form üzerinden müşteriye normal iş akışının bir parçası olarak gösterilir.
Kaynaklar: backend/src/routes/infraPublicRecord.routes.js, dashboard/src/components/it/constants.ts.
8. Veri Modelleri
8.1 MongoDB Koleksiyonları (iqvizyon veritabanı)
| Koleksiyon (env değişkeni) | Varsayılan ad | Amaç |
|---|---|---|
MONGODB_USERS_COLLECTION |
iqvizyon-users |
Admin/personel kullanıcıları. |
MONGODB_ORGANIZATIONS_COLLECTION |
organizations |
Firma/Müşteri listesi. |
MONGODB_INFRA_RECORD_COLLECTION |
infra-record |
Ana Infra kaydı (tüm form + steps[] süreç geçmişi). |
MONGODB_INFRA_REMINDER_COLLECTION |
infra-reminder |
Hatırlatıcı planları — her tarih/saat ayrı kayıt. |
| (sabit, env'den değil) | infra-logs |
Kullanıcı başına tek doküman, işlem satırları $push ile eklenir. |
Kaynaklar: .env.example, backend/src/config/env.js, backend/src/models/*.js, backend/src/repositories/infraLogs.repository.js, backend/src/repositories/infraReminder.repository.js.
8.2 InfraRecord — Ana Alan Tablosu
dashboard/src/interfaces/models/it.ts (710 satır) domain'in tek gerçek kaynağıdır; backend loosely-typed (MongoDB, çoğu alan opsiyonel) olduğu için bu tip tanımı da neredeyse tüm alanları opsiyonel bırakır. Aşağıdaki tablo InfraRecord arayüzünün gerçek alan adlarını listeler:
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
_id |
string |
Hayır (yalnızca yanıtta) | MongoDB ObjectId'nin hex string hali. |
public_token |
string |
Hayır | Public müşteri linkinin anahtarı (bootstrap kaynağı). |
organization_id, organization_name |
string |
Hayır | Firma/organizasyon referansı. |
company_name, company |
string |
Hayır | Görüntülenen firma adı (iki alan aynı bilgiyi taşıyabilir — geriye dönük uyumluluk). |
user_id |
string |
Hayır | Kaydı oluşturan admin kullanıcının id'si. |
created_at, updated_at |
ISO string | Hayır (backend her kayıtta atar) | Dashboard sıralaması ve "Kurulum" özet kartı için. |
authorized_person |
AuthorizedPersonPayload[] |
Hayır | Yetkili kişi listesi — { name, permission, mail, phone }. Ek geriye dönük alan adları (authority, role, yetkisi) da kabul edilir. |
edited_by, edited_at |
string |
Hayır | Kaydı düzenleyen kişi/tarih (form üstü meta bilgi). |
machine_count |
number | string |
Hayır | Makine sayısı. |
machines |
string[] |
Hayır | Seçilen makine markaları listesi. |
machine_list |
string |
Hayır | Virgülle ayrılmış makine listesi (görüntü amaçlı). |
system, system_source |
string |
Hayır | Sistem tipi/kaynağı (Cloud/Local). |
source_status |
string |
Hayır | Proje tipi — Satış/Demo (bkz. bölüm 13). |
device_type, cpu_core, ram_gb/ram_unit, disk_ssd_gb/disk_ssd_unit, operating_system |
çeşitli | Hayır | "İstenen" (requested) sistem kapasitesi — REQUESTED_CAPACITY_FIELDS kilidi kapsamındadır (bkz. bölüm 5.8, 11). |
provided_capacity |
nesne (aynı 5 alt-alan: device_type, cpu_core, ram_gb/ram_unit, disk_ssd_gb/disk_ssd_unit, operating_system) |
Hayır | Müşterinin/admin'in girdiği "Sağlanan" kapasite — ayrı, opsiyonel alt-nesne. |
administrator_requirement, virtualization_requirement, sleep_shutdown_requirement, automatic_start_requirement, machine_access_requirement, server_ip_requirement, iqvizyon_access_requirement, installation_update_access_requirement, vpn_requirement, anydesk_requirement, outbound_traffic_requirement, inbound_traffic_requirement |
string |
Hayır | 12 sabit gereksinim metni alanı (Sunucu/Ağ/Uzaktan Erişim/Güvenlik gereksinim grupları). |
remote_access |
RemoteAccess ({ type: 'vpn'|'anydesk', vpn?, anydesk? }) |
Hayır | Uzaktan erişim yöntemi ve detayları; parolalar public yanıtta maskelenir. |
status |
number (0/1) |
Hayır | Kayıt seviyesi Kurulum durumu — tek kaynak closeAdminReview (bkz. bölüm 11). |
review_status |
string (open/closed) |
Hayır | Admin kontrol turunun açık/kapalı olduğu. |
reviewed_by, reviewed_by_id, reviewed_at |
çeşitli | Hayır | Son kontrolü yapan admin bilgisi. |
installation_decision |
'' | 'ready' | 'conditional_ready' | 'not_ready' |
Hayır | Kurulum Kararı seçimi. |
public_progress |
Record<string, RequirementRowState> |
Hayır | Müşteri tarafı kalem/bölüm bazlı tamamlanma durumu (bkz. bölüm 11). |
admin_review_progress |
Record<string, AdminRequirementReviewItem> |
Hayır | IQVizyon tarafı 27-kalemlik onay/not durumu (bkz. bölüm 12/17-kalem tablosu). |
customer_general_note |
string |
Hayır | Müşterinin public formda yazdığı genel not. |
internal_general_note |
string |
Hayır | IQVizyon'un kendi iç notu — public whitelist'te yer almaz, müşteri ekranına asla ulaşmaz. |
general_notes |
{ customer?, admin? } |
Hayır | Not alanlarının yapılandırılmış görünümü (admin notu: { note, updated_at, updated_by }). |
server_room_available, customer_static_ip |
string |
Hayır | Sunucu Odası/Statik IP alt-bölümü. |
machine_details |
MachineDetail[] |
Hayır | Tezgah/Makine Bilgileri tablosu satırları (bkz. bölüm 12). |
steps |
WorkflowStep[] |
Hayır | Süreç geçmişi — append-only audit trail (bkz. 8.3). |
workflow_state, locked |
çeşitli | Hayır | Bazı yanıt şekillerinde görülen ek durum bayrakları. |
iqvizyon_note |
string |
Hayır (yalnızca public GET) | IQVizyon genel notunun salt-okunur public görünümü (kaynak internal_general_note — public whitelist üzerinden sızdırılmadan, ayrı bir salt-okunur alan olarak sunulur). |
iqvizyon_review_notes |
Record<string,string> |
Hayır (yalnızca public GET) | IQVizyon'un onaylamadığı satırlara yazdığı notlar ({itemKey | machine-<no>: not}). |
Kaynaklar: dashboard/src/interfaces/models/it.ts (710 satır, tam okundu), backend/src/services/infraRecord.service.js, backend/src/validators/infraRecord.validation.js.
8.3 Nested Yapılar — Detaylı Şekiller
| Yapı | Alanlar | Not |
|---|---|---|
AuthorizedPerson (form) |
name, email, phone, permission |
Ekrandaki serbest metin girişi. |
AuthorizedPersonPayload (backend'e giden) |
name, permission, mail, phone |
Alan adları backend sözleşmesiyle hizalı (email→mail). |
MachineDetail |
no, machine_name, brand, model_type, control_unit, ip_address, completed, note, notes?: string[] |
Tezgah Bilgileri tablosu satırı; notes[] açıklama geçmişidir (append-only). |
RemoteAccessVpn |
ip, username, password, has_password? |
Public GET'te password boş/maskeli döner, has_password bayrağı dolu olup olmadığını belirtir. |
RemoteAccessAnyDesk |
id, password, unattended_access, auto_start, has_password? |
Aynı maskeleme kuralı geçerlidir. |
RequirementRowState (public_progress değeri) |
completed, note, notes?: string[] |
27 kalemlik gereksinim listesinin her satırı için müşteri durumu. |
AdminRequirementReviewItem (admin_review_progress değeri) |
approved, completed, note, notes?: string[], machines?: [{no, approved, completed, note, notes?}] |
IQVizyon'un onay/tik/not girişi; makine satırları için ayrı bir alt-liste. |
WorkflowStep |
type (iqvizyon_created|customer_control|iqvizyon_control), status, note, date/created_at, + o adımın ürettiği alanların derin kopyası (public_progress, admin_review_progress, provided_capacity, requested_capacity, source, 12 gereksinim metni, decision, installation_decision*, vb.) |
Bkz. 8.4 — append-only audit trail. |
Kaynaklar: dashboard/src/interfaces/models/it.ts.
8.4 steps[] — Süreç Geçmişi (Append-Only Log)
Her kayıt yaşam döngüsü boyunca üç tür adım biriktirir; hiçbir adım güncellenmez/silinmez, yalnızca sona eklenir:
iqvizyon_created— ilk kayıt anında (InfraRecordService.create), IQVizyon'un müşteriye ilk gönderdiği talebin derin kopya snapshot'ı (company_name,organization_id,authorized_person,source_statusdahil).customer_control— müşterinin her "Gönder" işleminde (submitPublicProgress), o andakipublic_progress,provided_capacity,requested_capacity,remote_access,source(machine_count/machines/machine_list/system/system_source), 12 gereksinim metninin derin kopyası.iqvizyon_control— IQVizyon'un her Tamamlandı/Tamamlanmadı kararında (closeAdminReview),decision,review_status,reviewed_by/reviewed_by_id/reviewed_at,installation_decision/installation_decision_label/installation_decision_noteveadmin_review_progress'in derin kopyası.
Bu tasarım, sonradan ana kayıt güncellense bile geçmiş adımların değişmemesini garanti eder (audit trail) — bkz. bölüm 23.1.
Kaynaklar: backend/src/services/infraRecord.service.js, dashboard/src/interfaces/models/it.ts (WorkflowStep), dashboard/src/components/it/WorkflowHistory.tsx.
8.5 organizations ve iqvizyon-users Şemaları
organizations: { _id, company_id, company_name, organization_name, location?, city?, department?, manager_id?, status? } — yalnızca status boş/yok/active (case-insensitive) olan kayıtlar dropdown'da listelenir (kök neden düzeltmesi: eski kayıtlarda status alanı hiç yoktu, katı {status:'active'} filtresi listeyi boş gösteriyordu).
iqvizyon-users: { _id, username, password (bcrypt hash), full_name?, email?, role?, permissions?, company_id?, organization_id?, company_name?, status? } — parola hash'i toSafeUser() ile her API yanıtından önce çıkarılır.
Kaynaklar: backend/src/models/organization.model.js, backend/src/models/user.model.js, backend/src/repositories/organizations.repository.js.
9. Infra Form Domain Yapısı
Form iki aşamalı bir akış izler:
- Yeni kayıt (
ITForm.tsx): Firma/Müşteri, Yetkili Kişi(ler), Düzenleyen, Düzenleme Tarihi, Makine (sabit marka listesinden çoklu seçim + "Diğer" serbest metin), Sistem, Durum (Proje Tipi) —POST /infra-recordile kaydedilir;iqvizyon_createdadımı otomatik oluşur vepublic_tokenüretilir. - Önizleme/Detay (
ITPreview.tsx): tüm bölümlerin (10-15. bölümler arası, form içeriği) render'ı; admin modunda düzenlenebilir + Kaydet/Güncelle, public modunda müşterinin doldurabileceği alanlar + Gönder.
mode prop'u üç değer alır: 'new', 'admin-existing', 'public' — bu, hangi alanların salt-okunur, hangi butonların görünür olduğunu belirler (bkz. bölüm 4.8).
Müşteri formu (PublicITView.tsx → ITPreview.tsx mode='public') ile admin düzenleme ekranı (mode='admin-existing') aynı bileşen ağacını (ITPreview.tsx) paylaşır — iki ayrı form implementasyonu yoktur; hangi alanların düzenlenebilir olduğu tamamen mode prop'una göre koşullu render ile belirlenir. Bu, iki tarafın alan adlarının/davranışının hiçbir zaman birbirinden sapmamasını sağlayan bilinçli bir tasarım kararıdır.
Kaynaklar: dashboard/src/components/it/index.tsx, ITForm.tsx, ITPreview.tsx, PublicITView.tsx.
10. Form Bölümleri ve Alan Davranışları
constants.ts'teki REQUIREMENT_ITEMS (27 kalem), 8 grup altında toplanır: Kaynak, Sistem Kapasite Bilgileri, Sunucu ve Gereksinimleri, Ağ (Network) Gereksinimleri, Uzaktan Erişim Gereksinimleri, Güvenlik Gereksinimleri, Server, Makine Bilgileri. Buna ek olarak UI'da ayrıca: Sunucu Odası/Statik IP alt-bölümü (ServerAndMachineSection.tsx), Tezgah/Makine Bilgileri tablosu, 10. Güvenlik Kontrolü tablosu (SecurityControlTable.tsx), 12. IQVizyon Kontrolü paneli (AdminReviewPanel.tsx), Süreç Geçmişi (WorkflowHistory.tsx).
| Grup | İçerik / Örnek Alanlar | Kimin Doldurduğu |
|---|---|---|
| Kaynak | Makine sayısı, makine markaları, sistem (Cloud/Local), proje tipi (Satış/Demo) | Admin (kayıt oluşturma anında) |
| Sistem Kapasite Bilgileri | İstenen vs. Sağlanan: Sunucu tipi, CPU çekirdek, RAM, SSD, işletim sistemi | İstenen: admin/Bil önerisi; Sağlanan: müşteri/admin |
| Sunucu ve Gereksinimleri | administrator_requirement, virtualization_requirement, sleep_shutdown_requirement, automatic_start_requirement |
Sabit metin (IQVizyon politikası) + müşteri tik/not |
| Ağ (Network) Gereksinimleri | machine_access_requirement, server_ip_requirement, iqvizyon_access_requirement, installation_update_access_requirement |
Sabit metin + müşteri tik/not |
| Uzaktan Erişim Gereksinimleri | vpn_method/vpn_requirement, anydesk_method/anydesk_requirement |
Sabit metin + müşteri seçim/tik |
| Güvenlik Gereksinimleri | outbound_traffic_requirement, inbound_traffic_requirement |
Sabit metin + müşteri tik/not |
| Server | Sunucu Odası mevcut mu, Statik IP | Müşteri |
| Makine Bilgileri | Tezgah tablosu satırları (machine_details[]) |
Müşteri |
FIXED_REQUIREMENT_TEXT sabiti, müşteriye gösterilecek standart gereksinim metinlerini içerir — bunlardan biri gerçek, kasıtlı olarak müşteriye açık, statik OpenVPN IP adresidir: 135.181.251.237 (bkz. bölüm 7.8 — bu bir sızıntı değildir).
Kaynaklar: dashboard/src/components/it/constants.ts (394 satır), ServerAndMachineSection.tsx, SecurityControlTable.tsx.
11. Progress / Tamamlandı Mekanizması
İki bağımsız "tamamlandı" kavramı vardır — birbirine karıştırılmamalıdır:
- Bölüm bazlı müşteri "Durum" tiki (
public_progress.section_*) —SectionStatusControl.tsxüzerinden,POST /infra-public-section-statusile anında (Gönder'i beklemeden) kaydedilir; sayfa yenilendiğinde kaybolmaması için. 10 sabitsection_*anahtarı (SECTION_STATUS_KEYS, hem frontendconstants.ts'te hem backendinfraRecord.service.js'te bağımsız olarak sabit kodlanmıştır — istemciden gelen ham string asla doğrudan bir MongoDB alan yolu parçası olarak kullanılmaz — bkz. bölüm 23.1). - Kalem bazlı tamamlanma (
public_progress.<itemKey>.completed,RequirementRowState) — 27 kalemlik gereksinim listesinin her satırında müşterinin tik attığı, notlarla birlikte tutulan alan bazlı durum. - Admin tarafı 27-kalemlik onay (
admin_review_progress.<itemKey>.approved/.completed) — IQVizyon'un "IQVizyon Kontrolü" panelinde her kalemi tek tek onayladığı, ayrı bir onay katmanı (müşterinincompletedtiki ile karıştırılmaz — müşteri "tamamladım" der, IQVizyon "onaylıyorum" der). - Kayıt seviyesi Kurulum durumu (
status: 0 | 1) — tek kural:status === 1⇒ "Kurulum" (tamamlandı), aksi halde "Durum" (tamamlanmadı). Bu değeri yalnızca IQVizyon'uncloseAdminReview(Tamamlandı/Tamamlanmadı) kararı değiştirir.source_status(Satış/Demo/Kurulum proje tipi) bu kararda kullanılmaz (bkz. bölüm 13).
Bu dört katman birlikte, "müşteri ne dedi" (public_progress) ile "IQVizyon ne onayladı" (admin_review_progress) ile "kayıt resmi olarak kapandı mı" (status) sorularını birbirinden ayıran bir üç-seviyeli onay zinciri oluşturur.
Kaynaklar: backend/src/utils/infraStatus.js, backend/src/services/infraRecord.service.js (setPublicSectionStatus, closeAdminReview), dashboard/src/components/it/SectionStatusControl.tsx, AdminReviewPanel.tsx, constants.ts.
12. Makine Yönetimi
İki farklı "makine" kavramı vardır:
- Makine listesi (Kaynak bölümü):
MachinePickerModal.tsxile sabit marka listesinden (MACHINE_BRAND_OPTIONS: FANUC, Siemens, Mitsubishi, Heidenhain, Haas, Mazak, DMG MORI, Okuma, Makino, Brother, Doosan, Hurco, Quaser, Spinner, YCM — + "Diğer" serbest metin) çoklu seçim; virgülle ayrılmışmachine_liststring'ine yazılır,machines[]dizisi de ayrıca tutulur. - Tezgah Bilgileri tablosu (Makine Bilgileri bölümü):
ServerAndMachineSection.tsxiçinde her satırda No, Tezgah Adı (machine_name), Marka (brand), Model Tipi (model_type), Kontrol Ünitesi (control_unit), IP Adresi (ip_address) alanları — müşterinin doldurduğu,machine_details[](MachineDetail[]) olaraksubmitPublicProgressile kaydedilen ayrı bir veri yapısı. Her satırın kendicompletedbayrağı venote/notes[](açıklama geçmişi) alanı vardır. Bir satırın tamamlanma koşulu dört ana alanın (machine_name,brand,model_type,control_unit—ServerAndMachineSection.tsx'te tanımlı) tamamının dolu olmasıdır (tek kaynak,ServerAndMachineSection.tsxiçinde).
IQVizyon tarafı, AdminRequirementReviewItem.machines[] alt-listesi üzerinden her makine satırını ayrı ayrı onaylayabilir ({no, approved, completed, note, notes?}) — bu, admin_review_progress'in makine bölümüne özgü, satır-bazlı bir alt-yapısıdır.
Kaynaklar: dashboard/src/components/it/MachinePickerModal.tsx, ServerAndMachineSection.tsx, constants.ts (MACHINE_BRAND_OPTIONS), dashboard/src/interfaces/models/it.ts (MachineDetail, AdminRequirementReviewItem.machines).
13. Proje Tipi / Durum Yönetimi
source_status (Satış/Demo), SOURCE_STATUS_OPTIONS sabitinden gelir ve yalnızca bilgilendirme/raporlama amaçlıdır — isInfraRecordCompleted kararına dahil değildir (bölüm 11). Demo modunda (isDemoSourceStatus) /api/it/bil'e hiç istek atılmaz; DEMO_MINIMUM_REQUIREMENTS sabit değerleri kullanılır (Bil önerisi yerine).
Kayıt seviyesi durum (bölüm 11'de anlatılan status: 0|1 ve review_status: open|closed), proje tipinden bağımsız, tek bir state machine izler:
[Kayıt oluşturuldu] --(iqvizyon_created)--> status=0, review_status=open (kayıt yoksa)
|
v
[Müşteri "Gönder"] --(customer_control)--> status=0, admin_review_progress SIFIRLANIR,
| installation_decision temizlenir
v
[IQVizyon "Tamamlandı" kararı] --(iqvizyon_control, decision='completed')--> status=1, review_status='closed'
veya
[IQVizyon "Tamamlanmadı" kararı] --(iqvizyon_control, decision='incomplete')--> status=0, review_status='open'
Müşteri her yeni "Gönder" yaptığında (yeni bir customer_control adımı), önceki admin kontrol turu sıfırlanır — bu, IQVizyon'un her yeni müşteri gönderimini baştan değerlendirmesini garanti eder (eski onayların yanlışlıkla yeni veriye uygulanmasını engeller).
Kaynaklar: dashboard/src/components/it/constants.ts (SOURCE_STATUS_OPTIONS, DEMO_MINIMUM_REQUIREMENTS), ITForm.tsx (isDemoSourceStatus importu), backend/src/utils/infraStatus.js, backend/src/services/infraRecord.service.js (submitPublicProgress, closeAdminReview).
14. Ekler ve Dosya Yönetimi
Projede klasik dosya-yükleme (attachment) uç noktası veya alanı tespit edilmemiştir — backend/src/routes ve infraRecord.service.js içinde herhangi bir multipart/upload/multer referansı bulunmamaktadır; InfraRecord/MachineDetail/WorkflowStep tip tanımlarında (dashboard/src/interfaces/models/it.ts) dosya/URL/attachment tipinde herhangi bir alan yoktur. Formda yer alan tüm bilgi türleri (kapasite değerleri, gereksinim metinleri, uzaktan erişim bilgileri, tezgah bilgileri) yapılandırılmış metin/sayı/boolean alanlarıdır — ikili dosya içeriği (belge, fotoğraf, sertifika vb.) hiçbir noktada kabul edilmez veya saklanmaz.
Bu özellik kaynak kodda mevcut değildir. Bir dosya ekleme ihtiyacı doğarsa: backend'e multer (veya benzeri) tabanlı bir upload middleware'i, bir depolama katmanı (yerel disk/S3 uyumlu nesne depolama) ve InfraRecord/MachineDetail tiplerine yeni bir attachments[] alanı eklenmesi gerekecektir — bunların hiçbiri şu an mevcut değildir.
Kaynaklar: backend/src/app.js, backend/src/services/infraRecord.service.js, dashboard/src/interfaces/models/it.ts (alan taraması), backend/package.json (bağımlılık listesinde multer yok).
15. E-posta ve Bildirim Altyapısı
15.1 SMTP (Office365)
mailService.js: Nodemailer, secure: false + requireTLS: true (587/STARTTLS, Office365 için doğru kombinasyon), önbelleğe alınmış tekil transporter. SMTP_HOST/SMTP_USER/SMTP_PASSWORD eksikse getTransporter() açıkça "SMTP yapılandırması eksik: ..." hatası fırlatır — uygulama yine de başlar, yalnızca mail-gönderen istekler 500 döner. Modül ilk yüklendiğinde bir kez verifyTransporter() çağrılır (teşhis amaçlı, isteğe bağlı). Geriye dönük uyumluluk: SMTP_PASSWORD yoksa eski SMTP_PASS, SMTP_TLS yoksa eski SMTP_REQUIRE_TLS okunur — Legacy/uyumluluk amacıyla tutulduğu doğrulandı.
15.2 Mail Tetikleyicileri
| Tetikleyici | Servis fonksiyonu | Alıcı | İçerik |
|---|---|---|---|
| Admin "Mail Gönder" | sendEditLinkMail |
authorized_person[].mail (her birine ayrı) |
Public form linki. |
| IQVizyon Kontrol kararı | sendReviewResultMail |
Aynı | Tamamlandı/Tamamlanmadı sonucu + eksik kalemler (varsa, incomplete_items). |
| Müşteri "Gönder" | infraSubmitNotifier.notifyCustomerSubmit |
MAIL_TO (env, tek adres — IQVizyon ekibi) |
Firma/başlık/Infra ID + varsa genel not. |
MAIL_TO boşsa müşteri gönderim maili sessizce atlanır (SKIPPED, hata değil) — uygulama akışı bloklanmaz.
Her alıcıya ayrı ayrı sendMail çağrısı yapılır (toplu to: [a,b] kullanılmaz) — her alıcı yalnızca kendi adresini görsün diye (bkz. bölüm 5.8, 23.1).
15.3 Telegram
telegram.service.js: Bot API sendMessage/getMe, 10 sn timeout. İki kullanım noktası:
- (a) müşteri "Gönder" bildirimi →
INFRA_TELEGRAM_CHAT_ID(sabit grup). - (b) hatırlatıcı bildirimi →
reminderNotifier.service.js, her kişinin kenditelegram_id'sine, periyodiksetInterval(varsayılan/min 15000 ms,REMINDER_NOTIFY_INTERVAL_MS) ile — zaten gönderilmiş kişi-plan çiftlerinotified_person_idsile tekrar bildirilmez.
Her iki bildirim kanalı da (mail + Telegram) birbirinden bağımsız denenir, biri başarısız olsa diğeri etkilenmez, hiçbiri DB yazımını geri almaz — infraSubmitNotifier.service.js hiçbir koşulda exception fırlatmaz. Aktif kullanım doğrulandı.
Kaynaklar: backend/src/services/mailService.js, infraSubmitNotifier.service.js, telegram.service.js, reminderNotifier.service.js, .env.example.
16. PDF / Export
components/it/PDFReport.ts (370 satır) PDF üretimini tamamen istemci tarafında yapar; PDF_STANDARD sabiti (constants.ts) documentCode: IQV-IT-SRV-001 gibi standart doküman meta bilgilerini taşır. PDF butonu hem admin hem public ekranda, sayfa başlığının yanında (headerActionsContainer portalı ile) render edilir; tıklandığında pdfLoading state'i butonun tekrar tıklanmasını engeller. Public tarafta PDF indirme, infraLogService.logInfraClientEvent('pdf_downloaded', infraId) ile backend'e loglanır. Backend'de ayrı bir PDF render/export uç noktası yoktur — PDF üretimi bir HTTP isteği değil, tarayıcıda çalışan bir istemci fonksiyonudur.
Kaynak koddan kesin olarak doğrulanamadı: PDF'in tam sayfa/alan içeriği (hangi bölümlerin, hangi sırada, hangi biçimde PDF'e yansıdığı) bu turda satır satır incelenmedi (dosya adı ve constants.ts'teki PDF_STANDARD sabiti üzerinden genel amacı doğrulandı).
Kaynaklar: dashboard/src/components/it/PDFReport.ts (satır sayısı ve import noktası doğrulandı), constants.ts, ITPreview.tsx (PDF buton mantığı grep ile doğrulandı), infraLogService.ts.
17. API Endpointleri
Aşağıdaki tablo, backend/src/routes/*.js altındaki her router dosyasının tanımladığı tüm uç noktaları listeler (route dosyası bazında gruplanmıştır).
17.1 Kimlik Doğrulama — auth.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
POST |
/api/v1/auth/login |
Yok (rate-limited: loginLimiter) |
— | Kullanıcı adı/parola ile giriş, JWT üretir. |
GET |
/api/v1/auth/me |
Bearer JWT | — | Token'ın geçerliliğini ve kullanıcı bilgisini yeniden doğrular. |
17.2 Personel/Kullanıcı — people.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
GET |
/api/v1/users |
Bearer JWT | users.read |
Kullanıcı listesi. |
POST |
/api/v1/users |
Bearer JWT | users.create |
Yeni kullanıcı oluşturma. |
PUT |
/api/v1/users/:id |
Bearer JWT | users.update |
Kullanıcı güncelleme. |
PATCH |
/api/v1/users/:id |
Bearer JWT | users.update |
Kullanıcı kısmi güncelleme. |
DELETE |
/api/v1/users/:id |
Bearer JWT | users.delete |
Kullanıcı silme. |
17.3 Organizasyonlar — organizations.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
GET |
/organizations |
Bearer JWT | — | Firma/Müşteri listesi (prefix'siz — bilinçli istisna, bkz. 5.4). |
17.4 Infra Kayıtları (Admin) — infraRecord.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
GET |
/infra-record |
Bearer JWT | — | Tüm Infra kayıtları listesi. |
GET |
/infra-record/:id |
Bearer JWT | — | Tek kayıt detayı. |
POST |
/infra-record |
Bearer JWT | — | Yeni kayıt oluşturma (iqvizyon_created adımı otomatik). |
PUT |
/infra-record/:id |
Bearer JWT | — | Kayıt güncelleme (REQUESTED_CAPACITY_FIELDS kilidi uygulanır). |
POST |
/infra-record/:id/send-mail |
Bearer JWT | — | Public link maili (sendEditLinkMail). |
POST |
/infra-record/:id/review-mail |
Bearer JWT | — | Kontrol sonucu maili (sendReviewResultMail). |
17.5 IQVizyon Kontrolü (Admin Review) — infraAdminReview.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
POST |
/infra-public-review-close |
Bearer JWT | — | Kurulum Kararı (Tamamlandı/Tamamlanmadı) — closeAdminReview. |
POST |
/infra-admin-general-note |
Bearer JWT | — | Kurulum Kararı/iç not kaydı (debounce'lu). |
17.6 IT / Bil (Gemini) — it.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
POST |
/api/it/bil |
Bearer JWT | — | Gemini tabanlı sistem kapasitesi önerisi; GEMINI_API_KEY yoksa kontrollü GEMINI_API_KEY_MISSING hatası. |
17.7 Hatırlatıcı — reminder.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
GET |
/api/reminders |
Bearer JWT | — | Hatırlatıcı listesi. |
GET |
/api/reminders/assignees |
Bearer JWT | — | Atanabilir kişi listesi. |
PATCH |
/api/reminders/:id |
Bearer JWT | — | Plan kaydetme. |
17.8 İşlem Logu — infraLog.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
POST |
/infra-logs/event |
Bearer JWT | — | Yalnızca istemci-taraflı olaylar (logout, pdf_downloaded); kullanıcı bilgisi req.user'dan, firma adı DB'den — gövdeden güvenilmez veri okunmaz. |
17.9 Sağlık Kontrolü — health.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
GET |
/health |
Yok | — | Liveness. |
GET |
/health/ready |
Yok | — | Readiness (gerçek Mongo ping). |
17.10 Dokümantasyon — docs.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
GET |
/openapi.json |
Yok | — | OpenAPI şeması (JSON). |
GET |
/api-docs (+ /api-docs/) |
Yok | — | Swagger UI (özel gruplama eklentisiyle). |
17.11 Public/Müşteri — infraPublicRecord.routes.js
| Method | Endpoint | Auth | Yetki/Session | Açıklama |
|---|---|---|---|---|
POST |
/infra-public-session |
Yok (rate-limited: publicLimiter) |
publicToken (gövdede, tek seferlik) |
Session bootstrap — cookie yazar, kayıt döndürmez. |
GET |
/it/public-access/:publicToken |
Yok (rate-limited) | publicToken (URL) |
Mail linkinin gerçek hedefi — 302 → /form. |
GET |
/it/public/:publicToken |
Yok (rate-limited) | publicToken (URL) |
Geriye dönük uyumluluk → 302 → /form. |
GET |
/it/public |
Yok (rate-limited) | — | Geriye dönük uyumluluk (token'sız eski landing) → 302 → /form. |
GET |
/infra-public-record |
Yok (rate-limited) | requirePublicSession (cookie) |
Müşteri ekranının okuduğu whitelist'li kayıt (PUBLIC_FIELDS). |
POST |
/infra-public-progress-submit |
Yok (rate-limited) | requirePublicSession |
Final "Gönder" — yeni customer_control adımı. |
POST |
/infra-public-section-status |
Yok (rate-limited) | requirePublicSession |
Bölüm bazlı Durum tik/kalem. |
Not: /infra-public-progress (GET/POST) backend'de tanımlı değildir — frontend'in ilgili istemci fonksiyonları (itService.getPublicProgress/savePublicProgressDraft) da kullanılmamaktadır (bkz. bölüm 4.6, 7.7, 24.1).
Kaynaklar: backend/src/app.js, tüm backend/src/routes/*.js dosyaları (grep -nE "router\.(get|post|put|patch|delete)" ile doğrudan doğrulandı).
18. Environment Variables
Tek, paylaşılan kök .env dosyası — hem backend/src/config/env.js (../../../env göreli yolu, çalışma dizininden değil, dosyanın kendi konumundan çözülür) hem dashboard/vite.config.ts (envDir: '..') aynı dosyayı okur. Yalnızca VITE_ önekli değişkenler frontend bundle'ına girer.
| Değişken | Zorunlu | Default | Kullanıldığı Yer | Açıklama |
|---|---|---|---|---|
PORT |
Hayır | 4000 |
backend/src/server.js |
Backend HTTP portu. |
NODE_ENV |
Hayır | — | backend/src/utils/publicSession.js, config/env.js |
production iken public session cookie secure: true. |
MONGODB_URI |
Evet (pratikte) | mongodb://127.0.0.1:27017 |
config/db.js |
MongoDB bağlantı adresi. |
MONGODB_DB |
Hayır | iqvizyon |
config/db.js |
Veritabanı adı. |
MONGODB_USERS_COLLECTION |
Hayır | iqvizyon-users |
repositories/user.repository.js |
Kullanıcı koleksiyonu adı. |
MONGODB_ORGANIZATIONS_COLLECTION |
Hayır | organizations |
repositories/organizations.repository.js |
Firma koleksiyonu adı. |
MONGODB_INFRA_RECORD_COLLECTION |
Hayır | infra-record |
repositories/infraRecord.repository.js |
Ana Infra koleksiyonu adı. |
MONGODB_INFRA_REMINDER_COLLECTION |
Hayır | infra-reminder |
repositories/infraReminder.repository.js |
Hatırlatıcı koleksiyonu adı. |
JWT_SECRET |
Evet | Yok (fallback yok) | auth.service.js, utils/publicSession.js |
JWT imzalama — hem admin hem public session için (tek paylaşılan secret, bkz. 6.5/23.2). |
JWT_EXPIRES_IN |
Hayır | 12h |
auth.service.js |
Admin JWT ömrü. |
CORS_ORIGIN |
Hayır | http://localhost:5173 |
app.js |
Virgülle ayrılmış izinli origin listesi. |
FRONTEND_BASE_URL |
Hayır | boş | utils/frontendUrl.js |
Mail linki origin önceliği. |
PUBLIC_API_BASE_URL |
Hayır | boş | docs/ (OpenAPI üretimi) |
OpenAPI "Production" sunucu girdisi. |
SMTP_HOST |
Hayır | boş | mailService.js |
SMTP sunucu adresi. |
SMTP_PORT |
Hayır | boş | mailService.js |
SMTP portu (587 önerilir). |
SMTP_SECURE |
Hayır | boş | mailService.js |
TLS/SSL modu. |
SMTP_TLS (alias: SMTP_REQUIRE_TLS) |
Hayır | boş | mailService.js |
STARTTLS zorunluluğu. |
SMTP_USER |
Hayır | boş | mailService.js |
SMTP kullanıcı adı. |
SMTP_PASSWORD (alias: SMTP_PASS) |
Hayır | boş | mailService.js |
SMTP parolası — secret, dokümana yazılmaz. |
SMTP_FROM |
Hayır | boş | mailService.js |
Giden mail "from" adresi. |
MAIL_TO |
Hayır | boş | infraSubmitNotifier.service.js |
Müşteri "Gönder" bildirim maili alıcısı; boşsa sessizce atlanır. |
TELEGRAM_BOT_TOKEN |
Hayır | boş | telegram.service.js |
Telegram bot token'ı — secret, dokümana yazılmaz; boşsa bildirim sessizce atlanır. |
INFRA_TELEGRAM_CHAT_ID |
Hayır | boş | infraSubmitNotifier.service.js |
Müşteri gönderim bildirim grubu id'si. |
REMINDER_NOTIFY_INTERVAL_MS |
Hayır | (min 15000 uygulanır) | reminderNotifier.service.js |
Hatırlatıcı döngü aralığı. |
GEMINI_API_KEY |
Hayır | boş | bil.service.js |
/api/it/bil için Gemini API anahtarı — secret, dokümana yazılmaz; boşsa GEMINI_API_KEY_MISSING kontrollü hatası. |
GEMINI_MODEL |
Hayır | gemini-3.1-flash-lite (README) |
bil.service.js |
Kullanılacak Gemini model adı. |
VITE_API_BASE_URL |
Hayır | boş (same-origin) | dashboard/src/services/* |
Frontend API taban adresi. |
VITE_DEMO_MODE |
Hayır | — | frontend | Demo modu anahtarı. |
VITE_REQRES_API_KEY |
Hayır | — | — | Eski demo entegrasyonu — aktif kullanım referansı tespit edilemedi (bkz. bölüm 24.1). |
VITE_DEV_API_PROXY_TARGET |
Hayır | http://localhost:4000 |
dashboard/vite.config.ts |
Dev proxy hedefi. |
IQV_INFRA_HTTP_PORT |
Hayır | 8080 |
docker-compose.yml |
Docker'da dışa açılan port. |
E2E_* |
Hayır | — | tests/e2e/* |
Yalnızca Playwright test çalıştırıcıları için. |
K6_* |
Hayır | — | scripts/ (k6 testleri) |
Yalnızca k6 yük testi çalıştırıcıları için. |
Hiçbir gerçek secret değeri bu dokümana yazılmamıştır. OpenVPN sabit IP'si (135.181.251.237, bkz. bölüm 7.8) bir environment variable değildir — constants.ts içinde sabit kodlanmış, kasıtlı olarak müşteriye açık bir metindir; bu yüzden bu tabloda yer almaz.
Kaynaklar: .env.example, backend/src/config/env.js, README.md (Environment Variables tablosu ile çapraz doğrulandı).
19. Docker ve Deployment
19.1 docker-compose.yml
3 servis: mongo (image mongo:7, dışa port açılmaz, iqv-infra-net iç ağı, healthcheck), backend (kendi Dockerfile'ından build, env_file: .env, MONGODB_URI compose içinde mongodb://mongo:27017 olarak override edilir, yalnızca expose: 4000 — dışa port yok), dashboard (nginx runtime, depends_on: backend healthy, dışa açılan port ${IQV_INFRA_HTTP_PORT:-8080}:80). Named volume iqv-infra-mongo-data MongoDB verisinin kalıcılığını sağlar. backend'in dışa hiç port açmaması, tüm dış trafiğin yalnızca dashboard (nginx) üzerinden reverse-proxy ile backend'e ulaşabildiği anlamına gelir — backend doğrudan internete açık değildir.
19.2 Dockerfile'lar
backend/Dockerfile: çok aşamalı (deps → runtime), node:22-alpine, npm ci --omit=dev, root olmayan node kullanıcısı, .env imaja gömülmez (compose volume ile bağlanır), HEALTHCHECK gerçek bir /health/ready isteği atar (Mongo ping başarısızsa unhealthy).
dashboard/Dockerfile: node:22-alpine build aşaması (npm run build, VITE_API_BASE_URL build-arg, prod'da boş bırakılır — API aynı origin'den nginx proxy ile çağrılır) → nginx:1.27-alpine runtime (yalnızca statik dosyalar + nginx, Node/kaynak kod yok). HEALTHCHECK kök / adresine wget.
19.3 nginx.conf
Statik varlıklar için 30 günlük cache; index.html no-cache; güvenlik başlıkları (X-Content-Type-Options, X-Frame-Options: SAMEORIGIN, Referrer-Policy); backend uçları (/api/, /health, /openapi.json, /api-docs — ^~ ile regex önceliği bilinçli olarak aşılır, aksi halde statik dosya regex'i /api-docs/assets/*.css gibi istekleri yakalayıp 404 dönerdi —, /organizations, /infra-record, tüm /infra-public-*, /it/public-access, /it/public, /infra-logs/) iqv_infra_backend upstream'ine proxy'lenir; geri kalan her şey SPA fallback (try_files ... /index.html).
19.4 Native Kurulum (Docker'sız)
Docker olmadan PM2 ile iki süreç (iqv-infra-backend, iqv-infra-frontend); frontend scripts/common/static-server.mjs ile servis edilir (nginx'in bağımlılıksız native karşılığı), aynı proxy path listesini uygular (bölüm 19.3'teki path'lerle tutarlı — böylece hangi ortamda çalışılırsa çalışılsın SPA-fallback/backend-proxy davranışı sapmaz). Varsayılan portlar: frontend 5173, backend 4000. scripts/ altında hem Linux hem Windows, hem Docker hem native varyantları için ayrı kurulum/güncelleme/kaldırma script'leri bulunur.
19.5 Production vs. Development Farkları
| Yön | Development | Production (Docker) |
|---|---|---|
| Statik dosya sunumu | Vite dev server (HMR) | nginx (build çıktısı) |
| API proxy | Vite server.proxy (vite.config.ts) |
nginx location blokları |
Public session cookie secure |
false (NODE_ENV !== 'production') |
true (NODE_ENV === 'production') |
| Backend portu | Doğrudan 4000 erişilebilir |
Yalnızca iç ağda expose, dışa kapalı |
.env konumu |
Repo kökü, geliştirici tarafından elle yönetilir | env_file: .env, container'a mount edilir (imaja gömülmez) |
Kaynaklar: docker-compose.yml, backend/Dockerfile, dashboard/Dockerfile, dashboard/nginx.conf, dashboard/vite.config.ts, README.md (Installation bölümü, scripts/ listesi doğrulandı).
20. Test Altyapısı
| Test Katmanı | Framework | Konum | Kapsam |
|---|---|---|---|
| Backend unit | Node.js yerleşik node --test |
backend/tests/unit/*.test.js (10 dosya) |
Servis/utility fonksiyonları izole test. |
| Backend integration | node --test |
backend/tests/integration/*.test.js (3 dosya) |
createApp(deps) fabrikası üzerinden uçtan uca HTTP-seviyesi testler (mock bağımlılıklarla). |
| Backend auth | node --test |
backend/tests/auth/*.test.js (1 dosya) |
Login/JWT akışı. |
| Backend security | node --test |
backend/tests/security/*.test.js (1 dosya) |
Güvenlik odaklı senaryolar (whitelist, mass-assignment koruması vb.). |
| Backend contract (OpenAPI) | node --test |
backend/tests/contract/*.test.js (1 dosya) |
OpenAPI şeması ↔ gerçek router tutarlılığı (docs:check ile aynı amaç, test seviyesinde). |
| Frontend unit + component | Vitest | dashboard/tests/unit/, dashboard/tests/component/ (toplam 8 *.test.ts* dosyası) |
Saf fonksiyonlar (helpers.ts vb.) ve bileşen davranışları. |
| E2E | Playwright | tests/e2e/*.spec.ts (6 spec dosyası) |
Tarayıcı seviyesinde uçtan uca senaryolar. |
| Yük testi | k6 | scripts/ (K6_* env değişkenleri ile) |
Performans/yük testi — kapsamı bu turda ayrıntılı incelenmedi. |
E2E spec dosyaları: api-docs, infra-form, infra-list, login, public-form, theme.
Backend test reporter'ları hem spec (stdout) hem junit/json/özel html formatında backend/tests/reports/ altına yazar. Kök package.json, npm run test:all (scripts/run-tests.js) ile tüm katmanları tek komutta çalıştırır; test:full bayraklı sürümü de vardır.
public-form.spec.ts (97 satır, tam okundu) gerçek e2e senaryoları doğrular: session yokken /form doğrudan açılır ama kayıt göstermez; mail linkinin 302 ile /form'a yönlendirdiği ve token'ın adreste kalmadığı; refresh sonrası session'ın (HttpOnly cookie) korunduğu; eski /it/public linklerinin /form'a yönlendirildiği; public token'ın hiçbir sayfa HTML'inde render edilmediği.
Test sayılarının (kaç adet it()/test() bloğu içerdiği) kesin toplamı bu turda gerçek bir test çalıştırması ile doğrulanmamıştır — Kaynak koddan/gerçek çalıştırmadan kesin olarak doğrulanamadı; yukarıdaki dosya sayıları find/dizin listelemesi ile sayılmıştır, blok içi test adedi değildir.
Kaynaklar: backend/tests/**, dashboard/tests/**, tests/e2e/*.spec.ts, package.json (root), backend/package.json, dashboard/package.json.
21. CI / Quality Pipeline
.github/workflows/ci.yml ("IQV Infra CI") main dalına push/PR ve workflow_dispatch ile tetiklenir. İş adımları:
- Security Precheck (
scripts/ci/security-precheck.mjs) — commit edilmiş.env, private key, token, kimlikli Mongo URI taraması; secret sızıntısı bulursa pipeline en baştan kırılır. - Workflow Lint —
actionlint+ shellcheck (workflow YAML ve script kalitesi). - Backend testleri — unit/integration/auth/security/contract (bkz. bölüm 20).
- Frontend testleri — unit/component (Vitest).
- E2E — Playwright.
- Lint — kod stili/statik analiz.
docs:check— OpenAPI şeması ↔ canlı router farkı; fark varsa CI kırılır (yeni bir endpoint OpenAPI'ye yansıtılmadan eklenirse bu adım pipeline'ı durdurur).quality-report.mjs—iqv-infra-quality-reportartifact'i üretir (REPORT.md/REPORT.json/QUALITY.svg),actions/upload-artifact@v4ileif: always()(test başarısız olsa bile rapor yüklenir).runtime-smoke.mjs— gerçek build/deploy sonrası/,/form,/health,/api-docs,/api-docs/,/api-docs/assets/swagger-ui.css,/openapi.jsonadreslerine gerçek HTTP isteği atarak canlı sağlık kontrolü yapar.
.github/workflows/docs.yml ayrı bir iş akışıdır: MkDocs build --strict → GitHub Pages deploy, yalnızca main'e docs/mkdocs.yml değişikliği içeren push'ta çalışır; PR'larda yalnızca build yapılır (deploy yok). Bu ayrım, dokümantasyon sitesinin uygulama CI'sından bağımsız, kendi tetikleyicisiyle yayınlanmasını sağlar.
Kaynaklar: .github/workflows/ci.yml, .github/workflows/docs.yml, README.md (CI/CD bölümü ile çapraz doğrulandı), scripts/ci/*.mjs (dosya listesi doğrulandı).
22. Responsive / Mobil / Tablet
Frontend'in kendi useBreakpoint(breakPoint = 768) hook'u (components/hooks/breakpoint.ts), window.innerWidth < breakPoint mantığıyla mobil/masaüstü ayrımı yapar (varsayılan eşik 768px). components/it/it.css içinde doğrudan tespit edilen @media kesme noktaları:
| Kesme noktası | Anlamı |
|---|---|
| 767px | Mobil görünüm üst sınırı. |
| 768px | Mobil eşiği — useBreakpoint hook'u ile tutarlı. |
| 1199px | Tablet/masaüstü ayrımı — ServerAndMachineSection.tsx'in grid kırılımı için kullanılır. |
ServerAndMachineSection.tsx yorum satırında açıkça belirtilen grid davranışı: "768–991px (md): Makine tam satır, Sistem+Durum yarı yarıya; ≥992px (lg): Makine|Sistem|Durum 3 eşit kolon" — bu, antd grid sisteminin kendi md/lg breakpoint'lerini (antd varsayılanları: md=768, lg=992) kullanır, it.css'teki özel @media sorgularından ayrı bir mekanizmadır.
Bu nedenle projede iki paralel responsive mekanizma vardır: (1) useBreakpoint hook'u + it.css özel @media sorguları (768/767/1199px), (2) antd'nin kendi grid md/lg sistemi (768/992px). İkisi birbirine yakın ama özdeş olmayan eşik değerleri kullanır — bu bir çelişki değil, iki farklı katmanın (özel CSS vs. antd grid) kendi varsayılanlarıyla birlikte kullanılmasıdır.
Mobil, tablet-portrait, tablet-landscape ve masaüstü için birbirinden bağımsız, dört ayrı, açıkça adlandırılmış eşik değeri (ör. ayrı bir tailwind.config.mjs breakpoint tablosu) bu turda tespit edilmemiştir — Kaynak koddan kesin olarak doğrulanamadı: tailwind.config.mjs (varsa) bu turda kapsamlı olarak incelenmedi; projede Tailwind kullanılıp kullanılmadığı da bu turda kesin olarak doğrulanamadı.
Kaynaklar: dashboard/src/components/hooks/breakpoint.ts, dashboard/src/components/it/it.css (@media satırları grep ile doğrulandı), dashboard/src/components/it/ServerAndMachineSection.tsx (yorum satırı), ITForm.tsx.
23. Güvenlik
23.1 Uygulanan Güvenlik Kontrolleri
- JWT (admin): Bearer token,
JWT_SECRETile imzalı,JWT_EXPIRES_IN(varsayılan 12h) ile sınırlı ömür;GET /api/v1/auth/meher sayfa yüklemesinde token'ı backend'e karşı yeniden doğrular (bkz. bölüm 6.1). Kaynak:backend/src/services/auth.service.js. - HttpOnly session cookie (public):
httpOnly,sameSite: lax, prod'dasecure: true, 24 saat TTL,purposealanıyla admin JWT'den ayrıştırılmış (bkz. bölüm 7.2). Kaynak:backend/src/utils/publicSession.js. - CORS:
CORS_ORIGINenv değişkeni ile virgülle ayrılmış izinli origin listesi (bkz. bölüm 18/23.2). Kaynak:backend/src/app.js,config/env.js. - Validation:
infraRecord.validation.jsile request body doğrulaması, ObjectId format kontrolü. Kaynak:backend/src/validators/infraRecord.validation.js. - Mass-assignment/whitelist koruması:
getPublicRecord(PUBLIC_FIELDSwhitelist'i),submitPublicProgress(yalnızca 6 sabit alan gövdeden okunur),setPublicSectionStatus(SECTION_STATUS_KEYSsabit anahtar listesi) — istemciden gelen hiçbir alan adı doğrudan bir MongoDB yol parçası olarak kullanılmaz. Kaynak:backend/src/services/infraRecord.service.js. - Rate limiting: login (
loginLimiter) ve tüm public uçlar (publicLimiter)express-rate-limitile 5 dakikada 60 istek sınırına tabidir. Kaynak:backend/src/routes/auth.routes.js,infraPublicRecord.routes.js. - Hata sanitizasyonu:
errorHandler.middleware.js, ham stack trace/iç sistem detayını istemciye asla döndürmez — yalnızcaApiError'ın statusCode+mesajı ya da genel 500 mesajı döner (bkz. bölüm 5.11). Kaynak:backend/src/middleware/errorHandler.middleware.js. - Yetki kontrolü:
requirePermissionroute-level middleware'i,PermissionKeysözleşmesiyleusers.*uçlarını korur; kendi hesabında yetki yükseltme engeli (isSelfPrivilegeEscalationRestricted) (bkz. bölüm 6.2). Kaynak:backend/src/middleware/auth.middleware.js,people.service.js. - Audit trail (
steps[]): her kayıt için append-only, değiştirilemez süreç geçmişi — kim ne zaman ne yaptı sorgusunu garanti altına alır (bkz. bölüm 8.4). Kaynak:backend/src/services/infraRecord.service.js. - Secret yönetimi: tüm secret'lar (
JWT_SECRET,SMTP_PASSWORD,TELEGRAM_BOT_TOKEN,GEMINI_API_KEY) yalnızca env üzerinden okunur, koda gömülmez;.envDocker imajına dahil edilmez (bkz. bölüm 19.2). Kaynak:backend/src/config/env.js,backend/Dockerfile. - Parola/credential loglama koruması:
mailService.js,infraLog.service.js(SENSITIVE_KEY_PATTERNile hassas alan adlarının değerleri hiç yazılmaz),telegram.service.js(token URL'de değil header'da/path'te, hata mesajlarında yer almaz). Kaynak: yukarıdaki dosyalar. - Remote access parolaları: public yanıtta her zaman
maskRemoteAccess()ile maskelenir; boş gelen parola, önceki kayıtlı parolayı korur (public GET parolayı asla döndürmediği için). Kaynak:backend/src/services/infraRecord.service.js. REQUESTED_CAPACITY_FIELDSkilidi: müşteri gönderdikten sonra admin bile "İstenen" değerleri PUT ile değiştiremez. Kaynak:backend/src/services/infraRecord.service.js.- Regex injection/ReDoS koruması:
utils/regex.jskullanıcı girdisini escape eder, Türkçe karakter sınıflarını genişletir. Kaynak:backend/src/utils/regex.js.
23.2 Bilinen Güvenlik Kısıtları
- Tek paylaşılan
JWT_SECRET: hem admin oturum JWT'si hem müşteri public session JWT'si aynı secret ile imzalanır (purposealanı ile ayrıştırılır, ama kriptografik anahtar aynıdır). Secret sızarsa her iki jeton türü de sahtelenebilir. Kaynak:backend/src/utils/publicSession.js. CORS_ORIGINvarsayılanı:.env.example'da varsayılanhttp://localhost:5173— prod ortamında bu değerin gerçek domain(ler)e ayarlanması operasyonel bir zorunluluktur; yanlış yapılandırılırsa (*verilirse) CORS koruması etkisiz kalır. Kaynak:.env.example,backend/src/config/env.js.- SMTP kimlik doğrulama diagnostiği:
verifyTransporter()hersendEditLinkMail/sendReviewResultMailçağrısında SMTP'ye gerçek bir doğrulama isteği atar — bu, yanlış yapılandırılmış SMTP durumunda gecikme/ek yük yaratabilir (fonksiyonel bir açık değil, operasyonel bir not). Kaynak:backend/src/services/infraRecord.service.js. - Dosya yükleme/ek mekanizması yoktur — bu bir güvenlik açığı değil ama beklenen bir özellik ise eksiktir (bkz. bölüm 14).
/infra-public-progressuç noktası backend'de yok — frontend'de tanımlı ama çağrılmayan ölü kod, güvenlik riski oluşturmaz ancak bakım karmaşası yaratabilir (bkz. bölüm 7.7, 24.1).public_tokeniçin ayrı bir expiry/rotasyon mekanizması tespit edilmemiştir (bkz. bölüm 7.6) — session cookie'sinin 24 saatlik TTL'i vardır ama mail linkinin kendisinin (asıl token) ne zaman geçersiz sayılacağı kaynak kodda açık değildir. Kaynak koddan kesin olarak doğrulanamadı.- API versiyonlama tutarsızlığı: yalnızca
auth/people/api/v1altındadır, diğer uçların çoğu versiyonsuzdur (bkz. bölüm 5.15) — bu doğrudan bir güvenlik açığı değildir ama gelecekteki breaking-change yönetimini zorlaştırır. Kaynak:backend/src/app.js.
Kaynaklar: yukarıda madde madde belirtilen dosyalar; .env.example.
24. Bakım Kuralları ve Bilinen Kısıtlar
24.1 Bilinen Kısıtlar
| Öğe | Sınıflandırma | Gerekçe |
|---|---|---|
vpn_priority / anydesk_priority alanları |
Legacy/uyumluluk amacıyla tutulduğu doğrulandı. | UI sıralaması artık hardcoded; infraRecord.repository.js update() her PUT'ta bu alanları fırsatçı biçimde $unset eder. |
remote_vpn / remote_anydesk eski progress anahtarları |
Legacy/uyumluluk amacıyla tutulduğu doğrulandı. | Tek remote_access anahtarı ile değiştirildi. |
customer_machine_details progress-flag anahtarı |
Legacy/uyumluluk amacıyla tutulduğu doğrulandı. | Satır bazlı makine tamamlanma kontrolü ile değiştirildi. |
Eski device_type değerleri "Server"/"Desktop" |
Legacy/uyumluluk amacıyla tutulduğu doğrulandı. | Yalnızca eski kayıtların görüntülenmesi için; yeni kayıtlarda yalnızca "Sanal Sunucu"/"Fiziksel Sunucu" üretilir. |
SMTP_PASS, SMTP_REQUIRE_TLS env adları |
Legacy/uyumluluk amacıyla tutulduğu doğrulandı. | env.js'te sırasıyla SMTP_PASSWORD/SMTP_TLS için fallback. |
/it/public, /it/public/:token route'ları |
Legacy/uyumluluk amacıyla tutulduğu doğrulandı. | /form'a 302 yönlendirme; eski mail linkleri için. |
/personel route'u |
Legacy/uyumluluk amacıyla tutulduğu doğrulandı. | Canonical route /users'tır; /personel yalnızca eski linkler için /users'a yönlendiren bir alias'tır (browserRouter.tsx). |
itService.getPublicProgress / savePublicProgressDraft |
Aktif kullanım referansı tespit edilemedi. | Backend'de karşılık gelen route yok, frontend'de hiçbir bileşenden çağrılmıyor (grep ile doğrulandı). |
VITE_REQRES_API_KEY env değişkeni |
Aktif kullanım referansı tespit edilemedi. Kaynak koddan kesin olarak doğrulanamadı (bu turda kaynak kod içinde kullanım noktası kapsamlı aranmadı, yalnızca .env.example'da tanımlı olduğu görüldü). |
Yorum satırlarından (itService.ts, apiRoutes) "eski ReqRes demo entegrasyonunun artık kullanılmadığı, gerçek backend'e taşındığı" anlaşılıyor. |
| Dosya ekleme (attachment) özelliği | Kaynak kodda mevcut değil. | Bkz. bölüm 14 — herhangi bir upload middleware'i/alanı tespit edilmedi. |
| API versiyonlama tutarsızlığı | Aktif/bilinçli tasarım tercihi olarak doğrulanamadı — muhtemelen zaman içinde organik biçimde oluştu. Kaynak koddan kesin olarak doğrulanamadı. | Bkz. bölüm 5.15. |
public_token expiry/rotasyon mekanizması |
Kaynak koddan kesin olarak doğrulanamadı. | Bkz. bölüm 7.6. |
24.2 Genel Bakım Kuralları (kod içi yorumlardan çıkarılan proje kültürü)
- Yeni bir alan/uç nokta eklerken var olan isimlendirme sözleşmesine uyulmalı (
snake_casealan adları,section_*whitelist deseni,*_requirementmetin alan deseni). - Public tarafa asla mass-assignment ile yazma açılmamalı — her yeni public alan,
submitPublicProgress/setPublicSectionStatusiçinde açıkça whitelist'e eklenmelidir. steps[]'e eklenen her yeni adım derin kopya olmalı; var olan adımlar asla güncellenmemeli/silinmemeli (audit trail bütünlüğü).- Yeni bir secret/env değişkeni eklenirken
.env.example'a şablon (değersiz) olarak eklenmeli, koda gömülmemeli. docs:checkCI gate'i, yeni bir endpoint OpenAPI şemasına yansıtılmadan eklenirse pipeline'ı kırar — yeni route eklerkenbackend/src/docs/güncellenmelidir.- Yeni bir kalem/madde (
REQUIREMENT_ITEMSlistesine) eklenirken hem frontendconstants.tshem backendinfraRecord.service.js'teki bağımsız sabit listeler birlikte güncellenmelidir — bu ikisi kasıtlı olarak birbirinden bağımsız sabit kodlanmıştır (istemciden gelen ham değerlere güvenilmemesi için), bu yüzden tek taraflı güncelleme veri tutarsızlığına yol açar. - Var olan alanlar yeniden adlandırılmaz; yeni bir ihtiyaç doğduğunda mevcut alana ek/yeni bir alt-alan eklenir (bkz.
it.tsiçindeki "MEVCUT alanların HİÇBİRİ yeniden adlandırılmadı" yorumları) — bu, eski kayıtlarla geriye dönük uyumluluğu korumak için proje genelinde tutarlı biçimde izlenen bir kuraldır. - Yeni bir kapasite/gereksinim alt-nesnesi eklenirken var olan
{ device_type, cpu_core, ram_gb/ram_unit, disk_ssd_gb/disk_ssd_unit, operating_system }şekli tekrar kullanılır, ikinci bir benzer şekil icat edilmez (bkz.provided_capacity/requested_capacity'nin birebir aynı şekli paylaşması).
Kaynaklar: yukarıdaki tüm bölümlerde atıfta bulunulan dosyalar; backend/src/repositories/infraRecord.repository.js, backend/src/services/bil.service.js, dashboard/src/routes/browserRouter.tsx, dashboard/src/services/itService.ts, dashboard/src/interfaces/models/it.ts.
Doküman sonu.