nodebb-plugin-pdf-secure 1.2.26 → 1.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PRD.md ADDED
@@ -0,0 +1,776 @@
1
+ # PRD: IEU Forum Çok Katmanlı Premium Abonelik Sistemi
2
+
3
+ ## 1. Bağlam (Context)
4
+
5
+ ### Mevcut Durum
6
+
7
+ `/Users/enesuysal/myapps/ieu-forum-premium/` dizininde çalışan tek katmanlı (99.90₺/ay) bir premium abonelik sistemi mevcut. Sistem Express.js + EJS + MongoDB + PayTR + NodeBB entegrasyonu kullanıyor. Tek bir "premium" NodeBB grubu ve basit bir admin paneli var.
8
+
9
+ ### Amaç
10
+
11
+ Sistemi 3 kademeli abonelik planına (Lite, Premium, VIP), aylık + yıllık ödeme seçeneklerine, plan yükseltme mekanizmasına, ve gelişmiş admin paneline dönüştürmek.
12
+
13
+ ---
14
+
15
+ ## 2. Abonelik Planları
16
+
17
+ ### 2.1 Plan Tanımları
18
+
19
+ | Plan | Aylık | Yıllık (8 ay bedava) | NodeBB Grubu | Seviye |
20
+ | ------------------------ | ----- | -------------------- | ------------ | ------ |
21
+ | **Lite** | 119₺ | 476₺ | `lite` | 1 |
22
+ | **Premium** (En Popüler) | 139₺ | 556₺ | `premium` | 2 |
23
+ | **VIP** (Elit) | 159₺ | 636₺ | `vip` | 3 |
24
+
25
+ ### 2.2 Plan Özellikleri
26
+
27
+ **Lite (Seviye 1)**
28
+
29
+ - Tüm çalışma sorularına sınırsız erişim
30
+ - En güncel ders notları arşivi
31
+
32
+ **Premium (Seviye 2) — Lite + ekstralar**
33
+
34
+ - Gelişmiş PDF önizleme ve araçları
35
+ - Akıllı CV Oluşturucu
36
+ - Hedef odaklı GPA Hesaplayıcı
37
+ - Sıfır Reklam (reklamsız arayüz)
38
+ - Niki Wallet: %30 indirimli kahve hediye
39
+ - Sosyal Analitik: Profil ve konu görüntüleyenleri görme
40
+
41
+ **VIP (Seviye 3) — Premium + ekstralar**
42
+
43
+ - Prestij: Profilde özel VIP Badge
44
+ - Öncülük: Yeni özelliklere erken erişim
45
+
46
+ ### 2.3 Ödeme Periyotları
47
+
48
+ - **Aylık**: Standart fiyat, 30 günlük süre
49
+ - **Yıllık**: 8 ay bedava (4 aylık ödemeyle 12 ay kullanım), 365 günlük süre
50
+
51
+ ---
52
+
53
+ ## 3. İş Kuralları
54
+
55
+ ### 3.1 Plan Yükseltme (Upgrade)
56
+
57
+ - Kullanıcı sadece **üst plana** geçebilir (Lite → Premium, Lite → VIP, Premium → VIP)
58
+ - **Prorated fark ücreti**: Kalan günlerin fiyat farkı hesaplanır
59
+ - Formül: `fark = (yeniPlanFiyat - eskiPlanFiyat) / toplamGün * kalanGün`
60
+ - Örnek: Lite'tan Premium'a, 15 gün kala: `(139-119)/30*15 = 10₺`
61
+ - Yükseltme sonrası bitiş tarihi değişmez, sadece plan seviyesi ve grup değişir
62
+ - Yıllık abonelikte de aynı prorated mantık geçerli
63
+
64
+ ### 3.2 Downgrade
65
+
66
+ - **Desteklenmiyor**. Kullanıcı alt plana geçemez
67
+ - Alt plan isteyen kullanıcı mevcut aboneliği iptal edip süre bittikten sonra yeni plan satın almalı
68
+
69
+ ### 3.3 Abonelik Süresi Dolduğunda
70
+
71
+ - Mevcut cron job (10dk) kontrol eder
72
+ - Kullanıcı ilgili NodeBB grubundan çıkarılır
73
+ - Subscription status "expired" olarak işaretlenir
74
+
75
+ ### 3.4 Yenileme
76
+
77
+ - **Otomatik yenileme varsayılan olarak açık** gelir (checkbox tikli)
78
+ - Kullanıcı istemezse satın alma sırasında tiki kaldırarak kapatabilir
79
+ - Otomatik yenileme tercihi subscription kaydında `autoRenew: true/false` olarak saklanır
80
+ - Abonelik süresi dolmadan önce (ör. 1 gün kala) cron job otomatik yenileme yapılacak abonelikleri tespit eder
81
+ - Otomatik yenileme açık olan kullanıcılar için aynı plan + period ile yeni ödeme talebi oluşturulur (PayTR tekrarlayan ödeme veya kayıtlı kart ile)
82
+ - Otomatik yenileme kapalıysa: kullanıcı manuel olarak tekrar ödeme yaparak süre uzatır
83
+ - Aynı plan ile uzatma: mevcut bitiş tarihine süre eklenir
84
+
85
+ ### 3.5 Kullanıcı Abonelik İptali — NodeBB Grup Sinyali
86
+
87
+ NodeBB tarafında **herhangi bir plugin yazılmaz**. Bunun yerine NodeBB'nin yerleşik grup sistemi, kullanıcı ile ödeme servisi arasında güvenli bir iletişim kanalı olarak kullanılır.
88
+
89
+ #### Mekanizma
90
+
91
+ - NodeBB'de `iptal-talep` adında **açık (open)** bir grup oluşturulur
92
+ - Kullanıcı aboneliğini iptal etmek istediğinde bu gruba katılır (NodeBB'nin kendi arayüzü üzerinden, ek plugin gerekmez)
93
+ - Ödeme servisi bu grubu **5 dakikada bir** cron job ile kontrol eder
94
+ - Gruptaki kullanıcılar tespit edilir → otomatik yenileme kapatılır (`autoRenew: false`)
95
+ - İşlem tamamlandıktan sonra kullanıcı `iptal-talep` grubundan çıkarılır (API ile)
96
+
97
+ #### İptal Akışı
98
+
99
+ ```
100
+ 1. Kullanıcı NodeBB'de "iptal-talep" grubuna katılır
101
+ (Profil → Gruplar → "iptal-talep" → Katıl)
102
+ 2. Ödeme servisi cron job çalışır (her 5 dk)
103
+ 3. NodeBB API: GET /api/v3/groups/iptal-talep/members → üye listesi
104
+ 4. Her üye için:
105
+ a. Aktif abonelik var mı? → Evet ise:
106
+ - autoRenew = false olarak güncelle
107
+ - Subscription kaydına cancelRequestedAt = now ekle
108
+ b. Kullanıcıyı "iptal-talep" grubundan çıkar (API: DELETE /groups/iptal-talep/membership/{uid})
109
+ 5. Abonelik mevcut dönem sonuna kadar aktif kalır
110
+ 6. Dönem dolduğunda mevcut cron job (10 dk) normal şekilde plan grubundan çıkarır ve expired işaretler
111
+ ```
112
+
113
+ #### Neden Bu Yaklaşım Güvenli?
114
+
115
+ - Kullanıcı sadece **kendi oturumundan** NodeBB grubuna katılabilir (NodeBB'nin kendi auth sistemi)
116
+ - Ödeme servisi ile NodeBB arasında kullanıcı kimlik doğrulaması gerekmez
117
+ - Başka birinin aboneliğini iptal etmek imkansız — NodeBB'de bir gruba başkası adına katılamazsınız
118
+ - Cross-service auth, HMAC, OTP gibi mekanizmalara ihtiyaç yok
119
+
120
+ #### Kullanıcıya Bilgilendirme
121
+
122
+ - `iptal-talep` grubunun açıklama metninde şu yazılır:
123
+ > "Bu gruba katılarak aboneliğinizin otomatik yenilenmesini iptal etmiş olursunuz. Mevcut abonelik süreniz sonuna kadar erişiminiz devam edecektir. İptal talebiniz en geç 5 dakika içinde işleme alınacaktır."
124
+ - İptal işlendikten sonra ödeme servisi kullanıcıya NodeBB özel mesajı (PM) gönderebilir:
125
+ > "Otomatik yenileme iptal edildi. Aboneliğiniz {bitiş tarihi} tarihine kadar aktif kalacaktır."
126
+
127
+ #### Kullanıcı Fikir Değiştirirse
128
+
129
+ - İptal sadece otomatik yenilemeyi kapatır, mevcut dönem erişimi devam eder
130
+ - Kullanıcı forumdan yeniden `/pay/checkout?uid={uid}` üzerinden aynı planı satın alarak devam edebilir
131
+ - Veya admin panelden otomatik yenileme tekrar açılabilir
132
+
133
+ ### 3.6 NodeBB Grup Yönetimi
134
+
135
+ - Her plan için ayrı NodeBB grubu: `lite`, `premium`, `vip`
136
+ - İptal talep grubu: `iptal-talep` (açık grup, kullanıcılar serbestçe katılabilir)
137
+ - Kullanıcı **sadece** aktif planının grubunda olur
138
+ - Plan yükseltmede: eski gruptan çıkar, yeni gruba ekle
139
+ - Süre dolduğunda: gruptan çıkar
140
+
141
+ ### 3.7 Admin Paneli — Tam Yetki
142
+
143
+ Admin paneli NodeBB foruma bağlıdır ve admin aşağıdaki tüm işlemleri yapabilir:
144
+
145
+ #### Kullanıcı Doğrulama
146
+
147
+ - Admin, UID veya kullanıcı adı girerek işlem yapar
148
+ - Girilen bilgi NodeBB API üzerinden doğrulanır; kullanıcı bulunamazsa hata gösterilir
149
+ - Doğrulanan kullanıcının profil bilgileri (avatar, username, email, kayıt tarihi) gösterilir
150
+
151
+ #### Manuel Plan Atama
152
+
153
+ - Admin herhangi bir kullanıcıya herhangi bir plan (Lite / Premium / VIP) atayabilir
154
+ - Manuel atama PayTR ödemesi gerektirmez
155
+ - Süre admin tarafından belirlenir (1 ay / 3 ay / 6 ay / 12 ay / özel tarih, varsayılan: 30 gün)
156
+ - Period admin tarafından seçilir (aylık / yıllık)
157
+ - Atama sonrası NodeBB'de ilgili gruba eklenir (eski grup varsa çıkarılır)
158
+ - Subscription kaydı `source: "admin"` ve `adminAssignedBy` ile oluşturulur
159
+
160
+ #### Manuel Plan Değiştirme (Upgrade & Downgrade)
161
+
162
+ - Admin, kullanıcının mevcut planını **herhangi bir plana** değiştirebilir (hem yükseltme hem düşürme)
163
+ - Downgrade dahil — normal kullanıcılar yapamaz ama admin yapabilir
164
+ - Plan değiştirildiğinde: eski NodeBB grubundan çıkarılır, yeni gruba eklenir
165
+ - Bitiş tarihi korunur (admin isterse bitiş tarihini de değiştirebilir)
166
+ - `previousPlan` kaydedilir, `source: "admin"` olarak işaretlenir
167
+
168
+ #### Abonelik İptali
169
+
170
+ - Admin, aktif bir aboneliği anında iptal edebilir
171
+ - İptal sonrası: kullanıcı NodeBB grubundan çıkarılır, status "cancelled" olarak işaretlenir
172
+ - İptal nedeni opsiyonel olarak kaydedilebilir (`cancelReason`)
173
+
174
+ #### Süre Düzenleme
175
+
176
+ - Admin, mevcut aboneliğin bitiş tarihini ileri veya geri alabilir
177
+ - Süre uzatma veya kısaltma serbesttir
178
+
179
+ #### Kullanıcı Detay Sayfası
180
+
181
+ - Tek kullanıcıya ait tüm abonelik geçmişi (aktif + geçmiş) listelenir
182
+ - Mevcut plan, period, başlangıç/bitiş tarihi, kaynak (ödeme/admin/upgrade), otomatik yenileme durumu
183
+ - Üzerinden doğrudan plan değiştirme, iptal, süre düzenleme işlemleri yapılabilir
184
+ - NodeBB'deki grup üyeliği durumu gösterilir
185
+
186
+ ---
187
+
188
+ ## 4. Teknik Tasarım
189
+
190
+ ### 4.1 Veritabanı Modeli Değişiklikleri
191
+
192
+ **Subscription Model** (`src/models/subscription.model.js`) — güncellenecek alanlar:
193
+
194
+ ```javascript
195
+ {
196
+ // Mevcut alanlar (korunacak)
197
+ uid, username, status, startedAt, expiresAt, premiumRevokedAt,
198
+ billingInfo, paytrMerchantOid, paytrRaw,
199
+
200
+ // YENİ ALANLAR
201
+ plan: {
202
+ type: String,
203
+ enum: ["lite", "premium", "vip"],
204
+ required: true,
205
+ index: true
206
+ },
207
+ period: {
208
+ type: String,
209
+ enum: ["monthly", "yearly"],
210
+ default: "monthly"
211
+ },
212
+ amount: {
213
+ type: Number, // kuruş cinsinden ödenen tutar
214
+ required: true
215
+ },
216
+ source: {
217
+ type: String,
218
+ enum: ["payment", "admin", "upgrade"],
219
+ default: "payment"
220
+ },
221
+ previousPlan: {
222
+ type: String,
223
+ enum: ["lite", "premium", "vip", null],
224
+ default: null
225
+ },
226
+ autoRenew: {
227
+ type: Boolean,
228
+ default: true // varsayılan olarak açık
229
+ },
230
+ adminAssignedBy: {
231
+ type: String, // admin username (null if not admin-assigned)
232
+ default: null
233
+ },
234
+ cancelReason: {
235
+ type: String, // admin tarafından iptal edildiğinde sebep (opsiyonel)
236
+ default: null
237
+ }
238
+ }
239
+ ```
240
+
241
+ **Yeni Model: Plan Config** (`src/models/plan.model.js`) — plan tanımları için (opsiyonel, config dosyasında da tutulabilir):
242
+
243
+ Plan tanımları `src/config/plans.js` config dosyasında tutulacak (veritabanında değil):
244
+
245
+ ```javascript
246
+ const PLANS = {
247
+ lite: {
248
+ name: "Lite",
249
+ slug: "lite",
250
+ level: 1,
251
+ monthlyPrice: 11900, // kuruş
252
+ yearlyPrice: 47600, // kuruş (8 ay bedava)
253
+ nodebbGroup: "lite",
254
+ features: ["Tüm çalışma sorularına sınırsız erişim", "En güncel ders notları arşivi"],
255
+ },
256
+ premium: {
257
+ name: "Premium",
258
+ slug: "premium",
259
+ level: 2,
260
+ monthlyPrice: 13900,
261
+ yearlyPrice: 55600,
262
+ nodebbGroup: "premium",
263
+ badge: "En Popüler",
264
+ features: ["Lite planındaki her şey", "Gelişmiş PDF önizleme ve araçları", "Akıllı CV Oluşturucu", "Hedef odaklı GPA Hesaplayıcı", "Sıfır Reklam", "Niki Wallet: %30 indirimli kahve hediye", "Sosyal Analitik"],
265
+ },
266
+ vip: {
267
+ name: "VIP",
268
+ slug: "vip",
269
+ level: 3,
270
+ monthlyPrice: 15900,
271
+ yearlyPrice: 63600,
272
+ nodebbGroup: "vip",
273
+ badge: "Elit Deneyim",
274
+ features: ["Premium'daki her şey", "Prestij: Profilde özel VIP Badge", "Öncülük: Yeni özelliklere erken erişim"],
275
+ },
276
+ };
277
+ ```
278
+
279
+ ### 4.2 Değiştirilecek Dosyalar
280
+
281
+ | Dosya | Değişiklik |
282
+ | --------------------------------------- | ------------------------------------------------------------------------------- |
283
+ | `src/models/subscription.model.js` | plan, period, amount, source, previousPlan, adminAssignedBy alanları eklenir |
284
+ | `src/config/plans.js` | **YENİ** — Plan tanımları ve fiyatlandırma |
285
+ | `src/config/env.js` | Yeni NodeBB grup env değişkenleri (veya plans.js'den okunur) |
286
+ | `src/services/paytr.service.js` | Dinamik fiyat ve ürün adı desteği (plan + period parametreleri) |
287
+ | `src/services/nodebb.service.js` | Çoklu grup desteği: addToGroup(uid, groupName), removeFromGroup(uid, groupName) |
288
+ | `src/services/subscription.service.js` | createOrExtend → plan-aware, upgrade hesaplaması, admin atama |
289
+ | `src/services/admin.service.js` | Plan bazlı istatistikler, manuel atama servisi, gelir hesabı güncelleme |
290
+ | `src/controllers/payment.controller.js` | Plan seçimi ve period akışı, upgrade flow |
291
+ | `src/controllers/admin.controller.js` | Manuel plan atama endpoint'i, gelişmiş dashboard |
292
+ | `src/routes/payment.routes.js` | Yeni route'lar (plan seçim, upgrade) |
293
+ | `src/routes/admin.routes.js` | Manuel atama route'ları |
294
+ | `src/jobs/subscriptionWatcher.job.js` | Plan-aware grup çıkarma |
295
+ | `src/views/home.ejs` | 3 kart plan seçim UI, aylık/yıllık toggle |
296
+ | `src/views/billing-form.ejs` | Plan ve period bilgisi taşıma |
297
+ | `src/views/payment.ejs` | Seçilen plan bilgisi gösterme |
298
+ | `src/views/result.ejs` | Plan adı gösterme |
299
+ | `src/jobs/cancelRequestWatcher.job.js` | **YENİ** — İptal talep grubu kontrol cron job (5 dk) |
300
+ | `src/views/admin/dashboard.ejs` | Plan bazlı istatistikler, gelişmiş grafikler |
301
+ | `src/views/admin/subscribers.ejs` | Plan filtresi, manuel atama butonu |
302
+ | `src/views/admin/assign.ejs` | **YENİ** — Admin kullanıcı arama + manuel plan atama formu |
303
+ | `src/views/admin/subscriber-detail.ejs` | **YENİ** — Tek kullanıcı detay sayfası (plan değiştir, iptal, süre düzenle) |
304
+ | `.env.example` | Yeni env değişkenleri |
305
+
306
+ ### 4.3 API Endpoint'leri
307
+
308
+ #### Mevcut Route'lar (Güncelleme)
309
+
310
+ - `GET /pay/checkout?uid={uid}` → Plan seçim sayfası (3 kart + aylık/yıllık toggle)
311
+ - `GET /pay/checkout/billing?uid={uid}&plan={slug}&period={monthly|yearly}` → Fatura formu
312
+ - `POST /pay/checkout/billing` → Form işleme (plan + period eklenir)
313
+ - `GET /pay/checkout/start?uid={uid}&plan={slug}&period={monthly|yearly}&...` → PayTR başlat
314
+ - `POST /pay/checkout/callback` → PayTR callback (plan bilgisi merchantOid'den parse)
315
+ - `GET /pay/checkout/result` → Sonuç sayfası
316
+
317
+ #### Yeni Route'lar
318
+
319
+ - `GET /pay/checkout/upgrade?uid={uid}&plan={slug}` → Upgrade sayfası (fark ücreti göster)
320
+ - `POST /pay/checkout/upgrade` → Upgrade işlemi başlat → PayTR'ye yönlendir
321
+
322
+ #### Admin Route'ları (Güncelleme + Yeni)
323
+
324
+ - `GET /pay/admin` → Gelişmiş dashboard (plan bazlı breakdown)
325
+ - `GET /pay/admin/subscribers` → Plan filtresiyle liste
326
+ - `GET /pay/admin/subscriber/:uid` → **YENİ** Tek kullanıcı detay sayfası (abonelik geçmişi + işlemler)
327
+ - `GET /pay/admin/assign` → **YENİ** Manuel plan atama formu (UID/username ile kullanıcı arama)
328
+ - `POST /pay/admin/assign` → **YENİ** Manuel plan atama işlemi
329
+ - `POST /pay/admin/change-plan` → **YENİ** Plan değiştirme (upgrade/downgrade)
330
+ - `POST /pay/admin/cancel` → **YENİ** Abonelik iptal etme
331
+ - `POST /pay/admin/extend` → **YENİ** Süre düzenleme (uzatma/kısaltma)
332
+ - `GET /pay/admin/lookup?q={uid|username}` → **YENİ** NodeBB kullanıcı arama (AJAX)
333
+
334
+ ### 4.4 Ödeme Akışı (Güncel)
335
+
336
+ ```
337
+ 1. Kullanıcı → /pay/checkout?uid=123
338
+ 2. Plan seçim sayfası gösterilir (3 kart + aylık/yıllık toggle)
339
+ - Aktif aboneliği varsa: mevcut plan gösterilir + sadece üst planlar seçilebilir (upgrade)
340
+ - Aktif aboneliği yoksa: tüm planlar seçilebilir
341
+ 3. Kullanıcı plan + period seçer → "Satın Al" butonuna tıklar
342
+ 4. Billing form → Plan ve period bilgisi hidden field'larda taşınır
343
+ 5. PayTR'ye gönderilir:
344
+ - merchantOid formatı: {uid}x{planSlug}x{period}x{timestamp}
345
+ - Tutar: plans.js'den ilgili fiyat
346
+ - Basket: Plan adı + period
347
+ 6. PayTR callback gelir → merchantOid parse edilir → plan + period çıkarılır
348
+ 7. NodeBB'de ilgili gruba eklenir (eski grup varsa önce çıkarılır)
349
+ 8. Subscription kaydı oluşturulur (plan, period, amount bilgileriyle)
350
+ ```
351
+
352
+ ### 4.5 Upgrade Akışı
353
+
354
+ ```
355
+ 1. Kullanıcı → /pay/checkout?uid=123 (aktif aboneliği var)
356
+ 2. Mevcut planı gösterilir, üst planların "Yükselt" butonu aktif
357
+ 3. "Yükselt" → /pay/checkout/upgrade?uid=123&plan=premium
358
+ 4. Prorated fark ücreti hesaplanıp gösterilir:
359
+ - kalanGün = (expiresAt - now) / (1000*60*60*24)
360
+ - eskiGünlükFiyat = eskiPlan.fiyat / toplamGün
361
+ - yeniGünlükFiyat = yeniPlan.fiyat / toplamGün
362
+ - fark = (yeniGünlükFiyat - eskiGünlükFiyat) * kalanGün
363
+ - Minimum fark: 1₺ (100 kuruş)
364
+ 5. Kullanıcı onaylar → Billing form → PayTR (fark ücreti kadar)
365
+ 6. Callback → Eski gruptan çıkar, yeni gruba ekle
366
+ 7. Subscription güncelle: plan değişir, expiresAt aynı kalır, previousPlan kaydedilir
367
+ ```
368
+
369
+ ### 4.6 Admin Paneli Güncellemeleri
370
+
371
+ #### Dashboard İstatistikleri
372
+
373
+ - **Toplam Gelir**: Plan ve period bazlı breakdown
374
+ - **Aktif Aboneler**: Plan bazlı dağılım (pasta grafik veya bar)
375
+ - **Plan Dağılımı**: Lite vs Premium vs VIP oranları
376
+ - **Aylık vs Yıllık**: Period dağılımı
377
+ - **Bu Ay Gelir**: Plan bazlı
378
+ - **Son Abonelikler**: Plan bilgisiyle birlikte
379
+ - **Aylık Gelir Grafiği**: Plan bazlı stacked bar chart
380
+
381
+ #### Kullanıcı Arama & Atama Sayfası (`assign.ejs`)
382
+
383
+ - UID veya kullanıcı adı giriş alanı
384
+ - "Ara" butonuna basıldığında NodeBB API'den kullanıcı doğrulanır (AJAX ile `/pay/admin/lookup`)
385
+ - Kullanıcı bulunamazsa hata mesajı gösterilir
386
+ - Bulunursa: avatar, username, email, kayıt tarihi ve mevcut abonelik durumu gösterilir
387
+ - Plan seçimi (Lite / Premium / VIP)
388
+ - Period seçimi (Aylık / Yıllık)
389
+ - Süre seçimi (1 ay / 3 ay / 6 ay / 12 ay / özel tarih)
390
+ - "Ata" butonuna basıldığında:
391
+ - Subscription kaydı oluşturulur (source: "admin", adminAssignedBy kaydedilir)
392
+ - NodeBB grubuna eklenir (eski grup varsa çıkarılır)
393
+
394
+ #### Kullanıcı Detay Sayfası (`subscriber-detail.ejs`)
395
+
396
+ - NodeBB'den çekilen profil bilgileri (avatar, username, email, uid)
397
+ - Mevcut aktif abonelik bilgisi (plan, period, başlangıç/bitiş, kaynak, otomatik yenileme)
398
+ - NodeBB grup üyeliği durumu
399
+ - **İşlem butonları:**
400
+ - **Plan Değiştir**: Dropdown ile yeni plan seç → onayda upgrade veya downgrade yapılır
401
+ - **Süre Düzenle**: Bitiş tarihini değiştir (date picker)
402
+ - **Aboneliği İptal Et**: Onay modal → iptal nedeni (opsiyonel) → iptal işlemi
403
+ - Geçmiş abonelik kayıtları tablosu (tüm subscription history)
404
+
405
+ #### Abone Listesi (`subscribers.ejs`)
406
+
407
+ - Mevcut filtreler + plan filtresi (Lite / Premium / VIP)
408
+ - Period filtresi (Aylık / Yıllık)
409
+ - Source filtresi (Ödeme / Admin / Upgrade)
410
+ - Her satırda plan badge'i gösterilir
411
+ - Her satırda kullanıcı detay sayfasına link
412
+ - Hızlı işlem butonları (iptal, plan değiştir)
413
+
414
+ ---
415
+
416
+ ## 5. NodeBB Entegrasyonu (Plugin Yok)
417
+
418
+ NodeBB tarafında **herhangi bir plugin yazılmaz**. Tüm iletişim NodeBB'nin yerleşik grup sistemi ve API'si üzerinden sağlanır.
419
+
420
+ ### 5.1 Güvenlik Modeli
421
+
422
+ | İşlem | Güvenlik Riski | Çözüm |
423
+ | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------ |
424
+ | **Plan satın alma** (`/pay/checkout?uid={uid}`) | Düşük — saldırgan başkasının uid'sini girse bile kendi parasıyla başkasına abonelik alır (hediye gibi) | Mevcut akış yeterli |
425
+ | **Plan yükseltme** (`/pay/checkout/upgrade?uid={uid}`) | Düşük — aynı mantık, saldırgan kendi kartıyla ödeme yapar | Mevcut akış yeterli |
426
+ | **Abonelik iptali** | Yüksek — başkasının aboneliğini iptal etme riski | NodeBB grup sinyali ile çözüldü (bkz. 3.5) |
427
+
428
+ Sonuç: Ödeme gerektiren işlemlerde cross-service auth gerekmez (PayTR güvenliği yeterli). İptal gibi hassas işlemler NodeBB'nin kendi auth'u içinde kalır.
429
+
430
+ ### 5.2 NodeBB Tarafında Yapılacaklar (Admin Panelden, Kod Yazmadan)
431
+
432
+ #### 1. Grupları Oluştur
433
+
434
+ NodeBB Admin Panel → Groups → Create:
435
+
436
+ | Grup Adı | Tür | Amaç |
437
+ | ------------- | -------------- | ------------------------------------------------- |
438
+ | `lite` | Gizli (Hidden) | Lite plan üyeleri |
439
+ | `premium` | Gizli (Hidden) | Premium plan üyeleri |
440
+ | `vip` | Gizli (Hidden) | VIP plan üyeleri |
441
+ | `iptal-talep` | Açık (Open) | Kullanıcıların katılarak iptal sinyali göndermesi |
442
+
443
+ - Plan grupları (`lite`, `premium`, `vip`) → **Hidden** ve sadece API ile yönetilir. Kullanıcılar kendileri katılamaz/çıkamaz.
444
+ - `iptal-talep` → **Open** grup. Kullanıcılar serbestçe katılabilir.
445
+
446
+ #### 2. `iptal-talep` Grubunun Açıklama Metni
447
+
448
+ Grup açıklamasına şu yazılır (NodeBB Admin → Groups → iptal-talep → Description):
449
+
450
+ > **Abonelik İptal Talebi**
451
+ >
452
+ > Bu gruba katılarak aboneliğinizin otomatik yenilenmesini iptal etmiş olursunuz.
453
+ > Mevcut abonelik süreniz sonuna kadar erişiminiz devam edecektir.
454
+ > Talebiniz en geç 5 dakika içinde işleme alınacaktır.
455
+ > İşlem tamamlandığında bu gruptan otomatik olarak çıkarılacaksınız.
456
+
457
+ #### 3. Navigasyon Linkleri
458
+
459
+ NodeBB Admin Panel → Navigation:
460
+
461
+ - **"Planını Yükselt"** → `https://pay.ieu.app/pay/checkout?uid={uid}` (NodeBB template değişkeni ile uid otomatik eklenir)
462
+ - **"Aboneliği İptal Et"** → `/groups/iptal-talep` (forum içi link, kullanıcı "Katıl" butonuna basar)
463
+
464
+ ### 5.3 Ödeme Servisi Tarafında — İptal Talep Cron Job
465
+
466
+ Mevcut `subscriptionWatcher.job.js` genişletilir veya ayrı bir job eklenir:
467
+
468
+ **İptal Talep Kontrolü (her 5 dakika):**
469
+
470
+ ```
471
+ 1. NodeBB API: GET /api/v3/groups/iptal-talep/members → üye listesi çek
472
+ 2. Her üye (uid) için:
473
+ a. MongoDB'de aktif abonelik ara (uid, status: "active")
474
+ b. Aktif abonelik varsa:
475
+ - autoRenew = false
476
+ - cancelRequestedAt = new Date()
477
+ - source bilgisine "user-cancel" notu
478
+ c. NodeBB API: DELETE /api/v3/groups/iptal-talep/membership/{uid} → gruptan çıkar
479
+ d. (Opsiyonel) NodeBB API: POST /api/v3/chats → kullanıcıya PM gönder:
480
+ "Otomatik yenileme iptal edildi. Aboneliğiniz {bitiş tarihi} tarihine kadar aktif kalacaktır."
481
+ 3. Aktif aboneliği olmayan kullanıcı gruba katılmışsa → sadece gruptan çıkar, başka işlem yapma
482
+ ```
483
+
484
+ ### 5.4 Akış Diyagramları
485
+
486
+ #### Kullanıcı Aboneliğini İptal Eder
487
+
488
+ ```
489
+ Kullanıcı (forum.ieu.app) NodeBB Ödeme Servisi (cron job)
490
+ │ │ │
491
+ │ Gruplar → "iptal-talep" → Katıl │ │
492
+ │───────────────────────────────────────►│ │
493
+ │ │ │
494
+ │ "Gruba katıldınız" ✓ │ │
495
+ │◄───────────────────────────────────────│ │
496
+ │ │ │
497
+ │ (5 dk sonra cron job çalışır) │
498
+ │ │ │
499
+ │ │ GET /groups/iptal-talep/ │
500
+ │ │ members │
501
+ │ │◄─────────────────────────────│
502
+ │ │ │
503
+ │ │ [{uid: 123}, ...] │
504
+ │ │─────────────────────────────►│
505
+ │ │ │
506
+ │ │ autoRenew = false
507
+ │ │ cancelRequestedAt = now
508
+ │ │ │
509
+ │ │ DELETE /groups/iptal-talep/ │
510
+ │ │ membership/123 │
511
+ │ │◄─────────────────────────────│
512
+ │ │ │
513
+ │ (opsiyonel) PM: "İptal edildi, │ │
514
+ │ aboneliğiniz {tarih}'e kadar aktif" │ │
515
+ │◄───────────────────────────────────────│◄─────────────────────────────│
516
+ ```
517
+
518
+ #### Kullanıcı Plan Satın Alır
519
+
520
+ ```
521
+ Kullanıcı (forum.ieu.app) Ödeme Servisi (pay.ieu.app)
522
+ │ │
523
+ │ "Planını Yükselt" tıklar │
524
+ │ → /pay/checkout?uid=123 │
525
+ │─────────────────────────────────────────────────────────────►│
526
+ │ │
527
+ │ Plan seçim sayfası (3 kart + aylık/yıllık) │
528
+ │◄─────────────────────────────────────────────────────────────│
529
+ │ │
530
+ │ Plan seçer → billing form → PayTR ödeme │
531
+ │─────────────────────────────────────────────────────────────►│
532
+ │ │
533
+ │ PayTR callback → NodeBB grubuna ekle
534
+ │ → Subscription oluştur │
535
+ │ │
536
+ │ result?status=success │
537
+ │◄─────────────────────────────────────────────────────────────│
538
+ ```
539
+
540
+ ---
541
+
542
+ ## 6. Frontend Tasarım
543
+
544
+ ### 6.1 Plan Seçim Sayfası (home.ejs)
545
+
546
+ - 3 kart yan yana (mobilde alt alta)
547
+ - Aylık/Yıllık toggle switch (üstte)
548
+ - Yıllık seçildiğinde: "8 ay bedava!" badge, aylık eşdeğer fiyat gösterimi
549
+ - Premium kartı: "En Popüler" badge, hafif vurgu (border/shadow)
550
+ - VIP kartı: "Elit Deneyim" badge
551
+ - Her kartta: Özellik listesi + fiyat + "Satın Al" butonu
552
+ - Aktif aboneliği olan kullanıcı: mevcut plan vurgulanır, alt planlar disabled, üst planlarda "Yükselt" butonu
553
+
554
+ ### 6.2 Upgrade Sayfası
555
+
556
+ - Mevcut plan vs yeni plan karşılaştırması
557
+ - Prorated fark ücreti hesabı gösterimi
558
+ - Kalan gün bilgisi
559
+ - Onay butonu → billing form'a yönlendir
560
+
561
+ ---
562
+
563
+ ## 7. Yasal Uyumluluk ve Bilgilendirmeler
564
+
565
+ Ödeme içeren bir abonelik sistemi olduğundan, Türkiye mevzuatına tam uyum sağlanmalıdır.
566
+
567
+ ### 7.1 Uyulması Gereken Mevzuat
568
+
569
+ | Mevzuat | Kapsam |
570
+ | ---------------------------------------------------------------- | ------------------------------------------------------------------- |
571
+ | **6502 sayılı Tüketicinin Korunması Hakkında Kanun** | Tüketici hakları, cayma hakkı, haksız şartlar |
572
+ | **Mesafeli Sözleşmeler Yönetmeliği** | Ön bilgilendirme, sözleşme, cayma hakkı, dijital içerik istisnaları |
573
+ | **6698 sayılı KVKK** | Kişisel verilerin korunması, aydınlatma yükümlülüğü, açık rıza |
574
+ | **6563 sayılı Elektronik Ticaretin Düzenlenmesi Hakkında Kanun** | Hizmet sağlayıcı bilgileri, ticari iletişim, sipariş onayı |
575
+ | **5651 sayılı İnternet Kanunu** | İçerik sağlayıcı sorumlulukları |
576
+ | **Abonelik Sözleşmeleri Yönetmeliği** | Otomatik yenileme bilgilendirme, abonelik iptali |
577
+
578
+ ### 7.2 Satın Alma Öncesi Bilgilendirmeler
579
+
580
+ Kullanıcı ödeme yapmadan önce aşağıdaki bilgilendirmeler **açıkça** sunulmalı ve onay alınmalıdır:
581
+
582
+ #### Ön Bilgilendirme Formu (Zorunlu)
583
+
584
+ Plan seçim sayfasında veya billing formunda kullanıcıya gösterilecek:
585
+
586
+ - Hizmet sağlayıcı bilgileri (unvan, adres, iletişim)
587
+ - Seçilen planın adı, kapsamı ve özellikleri
588
+ - Toplam fiyat (KDV dahil, kuruş cinsinden net tutar)
589
+ - Ödeme yöntemi ve koşulları
590
+ - Abonelik süresi (aylık: 30 gün, yıllık: 365 gün)
591
+ - Otomatik yenileme durumu ve koşulları
592
+ - Cayma hakkı bilgilendirmesi (dijital içerik istisnası dahil)
593
+ - Şikayet ve itiraz mekanizmaları
594
+
595
+ #### Onay Checkbox'ları (Satın alma butonundan önce)
596
+
597
+ Kullanıcının tüm checkbox'ları işaretlemesi zorunludur:
598
+
599
+ 1. **Sözleşme onayı** (mevcut, güncellenmeli):
600
+
601
+ > "Mesafeli Satış Sözleşmesi'ni, Kullanım Koşulları'nı, Gizlilik Politikası'nı ve KVKK Aydınlatma Metni'ni okudum, anladım ve kabul ediyorum."
602
+
603
+ 2. **Dijital içerik cayma hakkı feragati** (mevcut, güncellenmeli):
604
+
605
+ > "Dijital içerik hizmetinin derhal ifasına başlanmasını talep ettiğimi ve bu sebeple 14 günlük cayma hakkımdan feragat ettiğimi onaylıyorum."
606
+
607
+ 3. **Otomatik yenileme bilgilendirmesi** (YENİ — varsayılan tikli):
608
+
609
+ > "Abonelik sürem dolduğunda, aynı plan ve ödeme tutarı ile otomatik olarak yenileneceğini biliyorum. Otomatik yenilemeyi istediğim zaman iptal edebileceğimi anlıyorum."
610
+
611
+ 4. **Ön bilgilendirme formu onayı** (YENİ):
612
+ > "Ön Bilgilendirme Formu'nu okudum ve satın alma öncesi gerekli tüm bilgileri aldım."
613
+
614
+ ### 7.3 Otomatik Yenileme — Yasal Gereklilikler
615
+
616
+ Abonelik Sözleşmeleri Yönetmeliği gereği:
617
+
618
+ - **Satış anında**: Otomatik yenileme tercihi açıkça gösterilmeli, fiyat ve yenilenme tarihi belirtilmeli
619
+ - **Yenileme öncesi bildirim**: Abonelik sona ermeden **en az 3 gün önce** kullanıcıya e-posta ile bildirim gönderilmeli:
620
+ - Yenilenecek plan adı
621
+ - Yenileme tutarı
622
+ - Yenileme tarihi
623
+ - İptal etme linki / talimatları
624
+ - **Kolay iptal**: Kullanıcı otomatik yenilemeyi kolayca kapatabilmeli (forum profili veya ödeme sayfası üzerinden)
625
+ - **İptal onayı**: Otomatik yenileme kapatıldığında kullanıcıya onay bildirimi gönderilmeli
626
+
627
+ ### 7.4 Cayma Hakkı ve İade Politikası
628
+
629
+ 6502 sayılı Kanun ve Mesafeli Sözleşmeler Yönetmeliği kapsamında:
630
+
631
+ - **Genel kural**: Mesafeli satışlarda tüketici 14 gün içinde cayma hakkına sahiptir
632
+ - **Dijital içerik istisnası**: Elektronik ortamda anında ifa edilen dijital içeriklerde, tüketicinin önceden açık onayı ve cayma hakkından feragat beyanı alınmışsa cayma hakkı uygulanmaz
633
+ - **Bu sistemde**: Kullanıcı satın alma öncesinde dijital içerik feragat checkbox'ını onayladığı için cayma hakkı bulunmaz
634
+ - **İade**: İade politikası sayfasında (`legal-refund.ejs`) bu durum açıkça belirtilmelidir
635
+ - **Admin iptali**: Admin tarafından yapılan iptallerde iade kararı admin'in insiyatifindedir
636
+
637
+ ### 7.5 Güncellenecek Yasal Sayfalar
638
+
639
+ Mevcut yasal sayfalar çok katmanlı plan yapısına göre güncellenmelidir:
640
+
641
+ | Sayfa | Güncellenecek İçerik |
642
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
643
+ | `legal-distance.ejs` | Plan isimleri (Lite/Premium/VIP), fiyat tablosu, otomatik yenileme maddeleri, yıllık abonelik koşulları, upgrade/downgrade kuralları |
644
+ | `legal-terms.ejs` | Çoklu plan tanımları, plan yükseltme/düşürme koşulları, otomatik yenileme kuralları, admin iptal yetkisi |
645
+ | `legal-refund.ejs` | Plan bazlı iade kuralları, upgrade'de prorated hesaplama açıklaması, otomatik yenileme iptali prosedürü |
646
+ | `legal-privacy.ejs` | Otomatik yenileme için saklanan ödeme bilgileri, plan tercihi verisi |
647
+ | `legal-kvkk.ejs` | Ödeme bilgileri işleme amacı, otomatik yenileme kapsamında veri saklama süresi |
648
+
649
+ ### 7.6 Satın Alma Sonrası Bilgilendirmeler
650
+
651
+ #### Sipariş Onay E-postası / Ekranı
652
+
653
+ Ödeme başarılı olduğunda kullanıcıya gösterilecek ve (e-posta altyapısı varsa) gönderilecek bilgiler:
654
+
655
+ - Satın alınan plan adı ve özellikleri
656
+ - Ödenen tutar (KDV dahil)
657
+ - Abonelik başlangıç ve bitiş tarihi
658
+ - Otomatik yenileme durumu (açık/kapalı)
659
+ - Bir sonraki yenileme tarihi ve tutarı (otomatik yenileme açıksa)
660
+ - İptal ve iletişim bilgileri
661
+
662
+ #### Result Sayfası (`result.ejs`)
663
+
664
+ Başarılı ödeme sonrası gösterilecek ek bilgiler:
665
+
666
+ - Seçilen plan adı
667
+ - Abonelik bitiş tarihi
668
+ - Otomatik yenileme durumu
669
+ - Destek iletişim bilgileri
670
+
671
+ ### 7.7 Fiyat Gösterimi Kuralları
672
+
673
+ - Tüm fiyatlar **KDV dahil** olarak gösterilmelidir
674
+ - Para birimi açıkça belirtilmelidir (₺ / TL)
675
+ - Yıllık planda: toplam tutar + aylık eşdeğer fiyat + tasarruf miktarı gösterilmelidir
676
+ - Upgrade'de: fark ücreti hesaplaması kullanıcıya şeffaf şekilde gösterilmelidir (kalan gün, günlük fark, toplam fark)
677
+ - İndirimli fiyat gösteriminde eski fiyat ve indirim oranı belirtilmelidir
678
+
679
+ ### 7.8 Hizmet Sağlayıcı Bilgileri
680
+
681
+ Tüm sayfalarda (footer veya erişilebilir bir yerde) bulunması gereken bilgiler:
682
+
683
+ - Hizmet sağlayıcı unvanı
684
+ - İletişim e-posta adresi
685
+ - Website adresi
686
+ - Şikayet/destek kanalı
687
+
688
+ ---
689
+
690
+ ## 8. Environment Değişkenleri
691
+
692
+ ```env
693
+ # Mevcut değişkenler korunur, ek olarak:
694
+ NODEBB_LITE_GROUP=lite
695
+ NODEBB_PREMIUM_GROUP=premium
696
+ NODEBB_VIP_GROUP=vip
697
+ NODEBB_CANCEL_REQUEST_GROUP=iptal-talep
698
+ ```
699
+
700
+ > Not: Grup isimleri `src/config/plans.js` içinde tanımlı olacağından, env'den de okunabilir veya direkt config'te sabitlenebilir.
701
+
702
+ ---
703
+
704
+ ## 9. Migration / Geçiş Planı
705
+
706
+ Mevcut "premium" grubundaki kullanıcılar için geçiş:
707
+
708
+ 1. Mevcut tüm aktif aboneliklere `plan: "premium"` ve `period: "monthly"` atanır (geriye dönük uyumluluk)
709
+ 2. `amount: 9990` (mevcut fiyat 99.90₺) olarak set edilir
710
+ 3. NodeBB'de mevcut "premium" grubundaki kullanıcılar "premium" grubunda kalır (grup adı aynı)
711
+ 4. Migration script'i `src/scripts/migrate-plans.js` olarak yazılır
712
+
713
+ ---
714
+
715
+ ## 10. Uygulama Sırası
716
+
717
+ ### Faz 1: Altyapı
718
+
719
+ 1. `src/config/plans.js` oluştur — plan tanımları
720
+ 2. `subscription.model.js` güncelle — yeni alanlar
721
+ 3. Migration script yaz ve çalıştır
722
+
723
+ ### Faz 2: Servis Katmanı
724
+
725
+ 4. `nodebb.service.js` güncelle — çoklu grup desteği
726
+ 5. `paytr.service.js` güncelle — dinamik fiyat/ürün
727
+ 6. `subscription.service.js` güncelle — plan-aware CRUD + upgrade hesaplama
728
+
729
+ ### Faz 3: Ödeme Akışı
730
+
731
+ 7. `payment.controller.js` güncelle — plan seçimi + upgrade flow
732
+ 8. `payment.routes.js` güncelle — yeni route'lar
733
+ 9. Frontend: `home.ejs` (plan kartları), `billing-form.ejs`, `payment.ejs`, `result.ejs`
734
+
735
+ ### Faz 4: Admin Paneli
736
+
737
+ 10. `admin.service.js` güncelle — plan bazlı istatistikler + manuel atama
738
+ 11. `admin.controller.js` güncelle — yeni endpoint'ler
739
+ 12. `admin.routes.js` güncelle — yeni route'lar
740
+ 13. Frontend: `dashboard.ejs`, `subscribers.ejs`, `assign.ejs` (yeni)
741
+
742
+ ### Faz 5: Yasal Uyumluluk
743
+
744
+ 14. Yasal sayfalar güncelle — çoklu plan, otomatik yenileme, upgrade/downgrade kuralları
745
+ 15. Ön bilgilendirme formu ve onay checkbox'ları ekle
746
+ 16. Otomatik yenileme öncesi bildirim mekanizması (cron + e-posta)
747
+
748
+ ### Faz 6: Test & Doğrulama
749
+
750
+ 17. `.env.example` güncelle
751
+ 18. Tüm akışları test et (yeni abone, upgrade, admin atama, süre dolumu, yasal onaylar)
752
+
753
+ ---
754
+
755
+ ## 11. Doğrulama (Verification)
756
+
757
+ ### Test Senaryoları
758
+
759
+ 1. **Yeni Abonelik**: Her 3 plan x 2 period = 6 senaryo test
760
+ 2. **Upgrade**: Lite→Premium, Lite→VIP, Premium→VIP = 3 senaryo
761
+ 3. **Admin Atama**: Her plan için manuel atama testi
762
+ 4. **Süre Dolumu**: Cron job'un doğru grubu kaldırdığını doğrula
763
+ 5. **NodeBB Grup**: Upgrade'de eski gruptan çıkıp yeni gruba girdiğini doğrula
764
+ 6. **PayTR Callback**: merchantOid parse'ın doğru çalıştığını doğrula
765
+ 7. **Prorated Hesaplama**: Fark ücretinin doğru hesaplandığını doğrula
766
+ 8. **Dashboard**: Plan bazlı istatistiklerin doğru gösterildiğini doğrula
767
+ 9. **Yasal Onaylar**: Checkbox'lar işaretlenmeden ödeme butonunun aktif olmadığını doğrula
768
+ 10. **Otomatik Yenileme Bildirimi**: Süre dolmadan 3 gün önce bildirim cron job'ının çalıştığını doğrula
769
+ 11. **Yasal Sayfalar**: Tüm yasal sayfalarda plan isimleri, fiyatlar ve otomatik yenileme bilgilerinin güncel olduğunu doğrula
770
+
771
+ ### Test Yöntemi
772
+
773
+ - PayTR test mode ile ödeme akışı testi
774
+ - MongoDB'de kayıt doğrulama
775
+ - NodeBB API'den grup üyeliği doğrulama
776
+ - Admin panel üzerinden manuel kontrol