1) Teknik Mimari#
1.1 Frontend#
Framework: Next.js App Router (next@16.1.1)
Durum/Sorgu: TanStack Query
API doğrulama: Zod contract katmanı (api/contracts/*.ts)
Çok dil: next-intl + locale prefix (/tr, /en, /es, /de)
englishcamplanding/package.json
englishcamplanding/app/[locale]/layout.tsx
englishcamplanding/i18n/routing.ts
englishcamplanding/api/services/*.ts
1.2 Backend#
Framework: NestJS (@nestjs/common@11)
Veri katmanı: Mongoose (MongoDB)
Auth: JWT + refresh token + blacklist
API docs: Swagger (/api/docs, /swagger/json)
Dosya depolama: Cloudflare R2 (S3 client)
englishcampbackend/package.json
englishcampbackend/src/main.ts
englishcampbackend/src/database/database.module.ts
englishcampbackend/src/storage/storage.service.ts
1.3 Global API davranışı#
Tüm controller dönüşleri global interceptor ile standart response formatına sarılır.{
"isSuccess": true,
"statusCode": 200,
"data": {},
"errors": [],
"timestamp": "2026-02-13T10:00:00.000Z"
}
englishcampbackend/src/common/interceptors/response.interceptor.ts
englishcampbackend/src/common/dto/app-base-response.ts
2) Env Değişkenleri (Tam Liste)#
2.1 Backend (englishcampbackend)#
| Değişken | Zorunlu | Varsayılan/Fallback | Kullanım | Kanıt |
|---|
PORT | Hayır | 3000 | API dinleme portu | englishcampbackend/src/main.ts |
NODE_ENV | Hayır | Yok | Exception mesaj seviyesi (prod/dev) | englishcampbackend/src/app/exception-filters/translation-validation-exception-filter.ts |
MONGODB_URI | Evet (prod) | mongodb://localhost:27017/englishcamp | Mongo bağlantısı | englishcampbackend/src/config/mongodb.config.ts |
JWT_SECRET | Evet (prod) | your-secret-key-change-in-production | JWT imzalama | englishcampbackend/src/config/jwt.config.ts |
JWT_EXPIRATION | Hayır | 150d | Access token TTL | englishcampbackend/src/config/jwt.config.ts |
JWT_REFRESH_EXPIRATION | Hayır | 150d | Refresh token TTL | englishcampbackend/src/config/jwt.config.ts |
MAIL_HOST | Evet (mail için) | Yok | SMTP host | englishcampbackend/src/config/mail.config.ts |
MAIL_PORT | Hayır | 587 | SMTP port | englishcampbackend/src/config/mail.config.ts |
MAIL_USER | Evet (mail için) | Yok | SMTP user | englishcampbackend/src/config/mail.config.ts |
MAIL_PASS | Evet (mail için) | Yok | SMTP pass | englishcampbackend/src/config/mail.config.ts |
MAIL_FROM_NAME | Evet (mail için) | Yok | Gönderen adı | englishcampbackend/src/config/mail.config.ts |
MAIL_FROM_EMAIL | Evet (mail için) | Yok | Gönderen e-posta | englishcampbackend/src/config/mail.config.ts |
FRONTEND_BASE_URL | Hayır | '' | Materyal atama maili link base URL | englishcampbackend/src/config/mail.config.ts, englishcampbackend/src/education-materials/use-cases/assign-education-material-to-users.use-case.ts |
R2_ACCESS_KEY_ID | Evet (upload için) | Yok | R2 kimlik | englishcampbackend/src/config/r2.config.ts |
R2_SECRET_ACCESS_KEY | Evet (upload için) | Yok | R2 secret | englishcampbackend/src/config/r2.config.ts |
R2_BUCKET | Evet (upload için) | Yok | Bucket adı | englishcampbackend/src/config/r2.config.ts |
R2_ENDPOINT | Evet (upload için) | Yok | R2 endpoint | englishcampbackend/src/config/r2.config.ts |
R2_BUCKET_CUSTOM_DOMAIN | Hayır | Yok | Public URL üretimi | englishcampbackend/src/config/r2.config.ts, englishcampbackend/src/storage/storage.service.ts |
R2_ACCOUNT_ID | Hayır | Yok | R2 hesap id | englishcampbackend/src/config/r2.config.ts |
2.2 Frontend (englishcamplanding)#
| Değişken | Zorunlu | Varsayılan/Fallback | Kullanım | Kanıt |
|---|
NEXT_PUBLIC_API_URL | Hayır (local fallback var) | http://localhost:3000 | Axios base URL | englishcamplanding/api/http/axios.ts |
NEXT_PUBLIC_SITE_URL | Hayır | https://englishcamplanding.vercel.app | SEO/canonical/sitemap/robots | englishcamplanding/lib/seo.ts, englishcamplanding/app/sitemap.ts, englishcamplanding/app/robots.ts |
NEXT_PUBLIC_UMAMI_WEBSITE_ID | Hayır | Kod içi default UUID | Umami analytics | englishcamplanding/components/analytics/analytics-loader.tsx |
NEXT_PUBLIC_GA_MEASUREMENT_ID | Hayır | Yok (GA kapalı) | Google Analytics script | englishcamplanding/components/analytics/google-analytics.tsx |
API_URL | TBD | TBD | Kodda referans bulunamadı | Arama: englishcamplanding içinde rg "\bAPI_URL\b" |
3) API Endpointleri (Tam Özet)#
3.1 App#
| Method | Path | Auth | Request | Response data |
|---|
GET | / | Public | - | string ("Hello World!") |
3.2 Auth (/auth)#
| Method | Path | Auth | Request DTO | Response data |
|---|
POST | /auth/refresh | Public | RefreshTokenDto | AuthResponseDto |
POST | /auth/logout | JWT | RefreshTokenDto (opsiyonel body) | LogoutResponseDto |
POST | /auth/otp/request | Public | RequestOtpUnifiedDto | OtpResponseDto |
POST | /auth/otp/verify | Public | VerifyOtpUnifiedDto | AuthResponseDto + registrationComplete |
POST | /auth/complete-registration | JWT | CompleteRegistrationDto | { message, user } |
GET | /auth/registration-status | JWT | - | RegistrationStatusResponseDto |
3.3 Users / Profile#
| Method | Path | Auth | Request DTO/Query | Response data |
|---|
GET | /me | JWT | - | UserProfileResponseDto |
PATCH | /me/profile | JWT | UpdateMeProfileDto | UserProfileResponseDto |
GET | /optional | Optional JWT | - | { authenticated: boolean } |
GET | /users | AdminGuard | GetAllUsersQueryDto | UserListResponseDto |
GET | /users/:id | AdminGuard | Path param | User detail object |
PATCH | /admin/users/:id/profile | AdminGuard | AdminUpdateUserProfileDto | UserProfileResponseDto |
PATCH | /admin/users/:id/email | AdminGuard | AdminUpdateUserEmailDto | UserProfileResponseDto |
PATCH | /users/:id/role | SuperAdminGuard | UpdateUserRoleDto | Updated user object |
DELETE | /users/:id | JWT | Path param | void |
3.4 Courses (/courses)#
| Method | Path | Auth | Request DTO | Response data |
|---|
POST | /courses | AdminGuard | CreateCourseDto + image + pdfs[] (multipart) | CourseResponseDto |
POST | /courses/:id/duplicate | AdminGuard | Path param | CourseResponseDto |
GET | /courses | Public | GetAllCoursesQueryDto | CourseListResponseDto |
GET | /courses/:id | Public | Path param | CourseResponseDto |
PATCH | /courses/:id | AdminGuard | UpdateCourseDto + file alanları (multipart) | CourseResponseDto |
DELETE | /courses/:id | AdminGuard | Path param | CourseResponseDto |
3.5 Proficiency Tests (/proficiency-tests)#
| Method | Path | Auth | Request DTO/Query | Response data |
|---|
POST | /proficiency-tests | AdminGuard | CreateProficiencyTestDto + coverImage (multipart) | Proficiency test dokümanı |
POST | /proficiency-tests/:id/duplicate | AdminGuard | Path param | Proficiency test dokümanı |
PATCH | /proficiency-tests/:id | AdminGuard | UpdateProficiencyTestDto + coverImage (multipart) | Proficiency test dokümanı |
GET | /proficiency-tests | Public | GetProficiencyTestsQueryDto | Proficiency test listesi |
GET | /proficiency-tests/target-languages | Public | - | TargetLanguage[] |
GET | /proficiency-tests/admin/results/:id | AdminGuard | Path param | Sonuç detay (populate) |
DELETE | /proficiency-tests/admin/results/:id | AdminGuard | Path param | { success: boolean } |
GET | /proficiency-tests/admin/results | AdminGuard | page, limit | { list, pagination } |
GET | /proficiency-tests/admin/results/user/:userId | AdminGuard | Path param | Kullanıcı sonuç listesi |
GET | /proficiency-tests/results/me | JWT | - | Kullanıcının sonuç listesi |
GET | /proficiency-tests/results/:resultId | JWT | Path param | Sonuç detay |
GET | /proficiency-tests/:id/status | JWT | Path param | { completed, result? } |
GET | /proficiency-tests/:id | Public | Path param | Test detay |
DELETE | /proficiency-tests/:id | AdminGuard | Path param | boolean |
POST | /proficiency-tests/:id/submit | JWT | SubmitTestDto | UserTestResult |
3.6 Education Materials (/education-materials)#
| Method | Path | Auth | Request DTO | Response data |
|---|
POST | /education-materials | JWT + AdminGuard | CreateEducationMaterialDto + files[] (multipart) | EducationMaterialResponseDto |
GET | /education-materials | JWT + AdminGuard | GetEducationMaterialsQueryDto | EducationMaterialResponseDto[] |
POST | /education-materials/:id/assign | JWT + AdminGuard | AssignEducationMaterialDto | AssignEducationMaterialSummaryDto |
GET | /education-materials/my-materials | JWT | - | AssignedEducationMaterialResponseDto[] |
GET | /education-materials/admin/users/:userId/materials | JWT + AdminGuard | Path param | AdminUserAssignedMaterialsResponseDto |
GET | /education-materials/:id | Public | Path param | EducationMaterialResponseDto |
PATCH | /education-materials/:id | JWT + AdminGuard | UpdateEducationMaterialDto + files[] (multipart) | EducationMaterialResponseDto |
DELETE | /education-materials/:id | JWT + AdminGuard | Path param | { success: boolean } |
| Method | Path | Auth | Request | Response data |
|---|
POST | /contact | Public | Partial<Contact> | ContactDocument |
GET | /contact/admin | JWT + AdminGuard | page, limit | { items, total } |
POST | /contact/admin/:id/reply | JWT + AdminGuard | { message: string } | ContactDocument |
DELETE | /contact/admin/:id | JWT + AdminGuard | Path param | void |
PATCH | /contact/admin/:id/status | JWT + AdminGuard | { status: ContactStatus } | ContactDocument |
3.8 Settings / Admin Dashboard / Storage#
| Method | Path | Auth | Request DTO | Response data |
|---|
GET | /settings/:key | Public | Path param | { value: string } |
PUT | /settings | JWT + AdminGuard | UpsertSettingDto | SettingDocument |
GET | /admin/dashboard | JWT + AdminGuard | GetAdminDashboardQueryDto | AdminDashboardStatsResponse |
POST | /storage/upload | Public | multipart (file, folder) | { success: true, data: { key, url } } |
4) DTO Bazlı Örnek Request/Response#
Not: Aşağıdaki response örneklerinde global BaseResponseDto wrapper kullanılmıştır.
4.1 OTP isteği#
{
"email": "user@example.com",
"language": "tr"
}
{
"isSuccess": true,
"statusCode": 200,
"data": {
"message": "Verification code has been sent to your email address",
"email": "user@example.com"
},
"errors": [],
"timestamp": "2026-02-13T10:00:00.000Z"
}
4.2 OTP doğrulama#
{
"email": "user@example.com",
"code": "123456"
}
{
"isSuccess": true,
"statusCode": 200,
"data": {
"accessToken": "<jwt>",
"refreshToken": "<jwt>",
"user": {
"id": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"role": "user",
"isRegistrationComplete": false
},
"registrationComplete": false
},
"errors": [],
"timestamp": "2026-02-13T10:00:00.000Z"
}
4.3 Kayıt tamamlama#
{
"name": "John Doe",
"age": 25,
"gender": "female",
"city": "Istanbul",
"country": "Turkey",
"countryCode": "TR",
"phoneNumber": "+905551234567"
}
{
"isSuccess": true,
"statusCode": 200,
"data": {
"message": "Registration completed",
"user": {
"_id": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"name": "John Doe",
"isRegistrationComplete": true,
"age": 25,
"gender": "female",
"city": "Istanbul",
"country": "Turkey",
"countryCode": "TR",
"phoneNumber": "+905551234567"
}
},
"errors": [],
"timestamp": "2026-02-13T10:00:00.000Z"
}
4.4 Kendi profilini güncelleme#
{
"age": 29,
"phone": "+905559999999",
"gender": "other",
"city": "Ankara",
"country": "Turkey"
}
{
"isSuccess": true,
"statusCode": 200,
"data": {
"user": {
"id": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"age": 29,
"gender": "other",
"city": "Ankara",
"country": "Turkey",
"phoneNumber": "+905559999999"
}
},
"errors": [],
"timestamp": "2026-02-13T10:00:00.000Z"
}
4.5 Kurs oluşturma (multipart)#
4.6 Proficiency test submit#
{
"answers": [
{ "questionIndex": 0, "selectedOptionIndex": 1 },
{ "questionIndex": 1, "selectedOptionIndex": 0 }
]
}
{
"isSuccess": true,
"statusCode": 201,
"data": {
"_id": "67abf0e7d4d26f5d9b246e99",
"userId": "507f1f77bcf86cd799439011",
"testId": "65abc123def4567890ab1234",
"totalScore": 60,
"level": "B1",
"answers": [
{ "questionId": "0", "selectedOptionId": "1", "isCorrect": true },
{ "questionId": "1", "selectedOptionId": "0", "isCorrect": false }
],
"message": "Intermediate level",
"completedAt": "2026-02-13T10:00:00.000Z"
},
"errors": [],
"timestamp": "2026-02-13T10:00:00.000Z"
}
4.7 Materyal atama#
{
"userIds": [
"507f1f77bcf86cd799439011",
"507f1f77bcf86cd799439012"
]
}
{
"isSuccess": true,
"statusCode": 200,
"data": {
"materialId": "65abc123def4567890ab1234",
"requestedUserCount": 2,
"assignedUserCount": 2,
"skippedUserCount": 0,
"assignedUserIds": ["507f1f77bcf86cd799439011", "507f1f77bcf86cd799439012"],
"skippedUserIds": [],
"emailFailedUserIds": []
},
"errors": [],
"timestamp": "2026-02-13T10:00:00.000Z"
}
5) Veri Modeli#
5.1 Mermaid ER#
5.2 Koleksiyon Bazlı Özet#
| Koleksiyon/Sınıf | Amaç | Dosya |
|---|
User | Kimlik, rol, profil alanları | englishcampbackend/src/users/schemas/user.schema.ts |
Otp | OTP doğrulama kodu/TTL | englishcampbackend/src/users/schemas/otp.schema.ts |
RefreshToken | Refresh token saklama | englishcampbackend/src/users/schemas/refresh-token.schema.ts |
BlacklistedToken | Logout sonrası access token blacklist | englishcampbackend/src/users/schemas/blacklisted-token.schema.ts |
Course | Kurs içeriği | englishcampbackend/src/courses/schemas/course.schema.ts |
ProficiencyTest | Sınav soruları/level aralıkları | englishcampbackend/src/proficiency-tests/schemas/proficiency-test.schema.ts |
UserTestResult | Kullanıcı sınav sonucu | englishcampbackend/src/proficiency-tests/schemas/user-test-result.schema.ts |
EducationMaterial | PDF/video materyal | englishcampbackend/src/education-materials/schemas/education-material.schema.ts |
UserEducationMaterialAssignment | User-material ilişki tablosu | englishcampbackend/src/education-materials/schemas/user-education-material-assignment.schema.ts |
Contact | İletişim talepleri | englishcampbackend/src/common/schemas/contact.schema.ts |
Setting | Key-value ayar | englishcampbackend/src/settings/schemas/setting.schema.ts |
6) Rol Matrisi (Endpoint Seviyesi)#
| Endpoint Grubu | Public | User | Admin | Superadmin |
|---|
/auth/otp/*, /auth/refresh | Evet | Evet | Evet | Evet |
/auth/logout, /me, /me/profile, /auth/complete-registration, /auth/registration-status | Hayır | Evet | Evet | Evet |
/users ve /admin/users/* | Hayır | Hayır | Evet | Evet |
/users/:id/role | Hayır | Hayır | Hayır | Evet |
/courses create/update/delete/duplicate | Hayır | Hayır | Evet | Evet |
/proficiency-tests create/update/delete/admin-results | Hayır | Hayır | Evet | Evet |
/proficiency-tests/:id/submit, /proficiency-tests/results/*, /:id/status | Hayır | Evet | Evet | Evet |
/education-materials admin CRUD/assign | Hayır | Hayır | Evet | Evet |
/education-materials/my-materials | Hayır | Evet | Evet | Evet |
/contact/admin/*, /admin/dashboard, /settings PUT | Hayır | Hayır | Evet | Evet |
7) Rate Limiting#
| Kural | Limit | Pencere | Kapsam | Kanıt |
|---|
DEFAULT | 120 | 1 dakika | Tüm endpointler (override edilmediyse) | englishcampbackend/src/common/constants/rate-limit.constants.ts, englishcampbackend/src/app/app.module.ts |
AUTH_REFRESH | 30 | 1 dakika | POST /auth/refresh | englishcampbackend/src/common/constants/rate-limit.constants.ts, englishcampbackend/src/auth/auth.controller.ts |
AUTH_OTP_REQUEST | 5 | 5 dakika | POST /auth/otp/request | englishcampbackend/src/common/constants/rate-limit.constants.ts, englishcampbackend/src/auth/auth.controller.ts |
AUTH_OTP_VERIFY | 12 | 5 dakika | POST /auth/otp/verify | englishcampbackend/src/common/constants/rate-limit.constants.ts, englishcampbackend/src/auth/auth.controller.ts |
CONTACT_CREATE | 6 | 1 saat | POST /contact | englishcampbackend/src/common/constants/rate-limit.constants.ts, englishcampbackend/src/common/controllers/contact.controller.ts |
STORAGE_UPLOAD | 20 | 10 dakika | POST /storage/upload | englishcampbackend/src/common/constants/rate-limit.constants.ts, englishcampbackend/src/storage/storage.controller.ts |
Rate-limit tracker x-forwarded-for öncelikli, yoksa req.ip kullanır.Kanıt: englishcampbackend/src/app/app.module.ts
Modified at 2026-02-14 10:36:56