first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:41:46 +03:00
commit b6e74bd024
56 changed files with 16114 additions and 0 deletions

12
belgeler/README.md Normal file
View File

@@ -0,0 +1,12 @@
# goaresv3 — Proje Belgeleri
Bu klasör, projenin teknik belgelerini içerir.
| Dosya | Konu |
|---|---|
| [proje-yapisi.md](proje-yapisi.md) | Klasör ve dosya ağacı, her birinin rolü |
| [auth.md](auth.md) | Kimlik doğrulama sistemi (Register / Login / JWT) |
| [api-referans.md](api-referans.md) | Tüm endpoint'ler, istek/yanıt örnekleri |
| [veritabani.md](veritabani.md) | GORM modelleri ve veritabanı şeması |
| [ortam-degiskenleri.md](ortam-degiskenleri.md) | `.env` değişkenleri ve açıklamaları |
| [testler.md](testler.md) | Otomatik test kapsamı ve çalıştırma rehberi |

267
belgeler/api-referans.md Normal file
View File

@@ -0,0 +1,267 @@
# API Referansı
Base URL: `http://localhost:8080`
---
## Public Endpoint'ler
_Token gerektirmez._
---
### `POST /api/v1/auth/register`
Yeni kullanıcı oluşturur ve doğrulama maili gönderir.
**İstek gövdesi**
```json
{
"username": "ali",
"email": "ali@ornek.com",
"password": "gizli1234",
"confirm_password": "gizli1234"
}
```
| Alan | Tip | Kural |
|---|---|---|
| `username` | string | Zorunlu, 350 karakter |
| `email` | string | Zorunlu, geçerli e-posta |
| `password` | string | Zorunlu, min 8 karakter |
| `confirm_password` | string | Zorunlu, `password` ile aynı olmalı |
**Yanıtlar**
| Durum | Açıklama | Gövde örneği |
|---|---|---|
| `201 Created` | Kayıt başarılı, doğrulama maili gönderildi | `{ "message": "user created. please verify your email", "user_id": 1 }` |
| `400 Bad Request` | Doğrulama hatası | `{ "error": "Key: 'RegisterRequest.Email' Error:..." }` |
| `400 Bad Request` | Şifreler eşleşmiyor | `{ "error": "password and confirm_password do not match" }` |
| `409 Conflict` | E-posta zaten kayıtlı | `{ "error": "email already in use" }` |
| `500 Internal Server Error` | Doğrulama maili gönderilemedi | `{ "error": "failed to send verification email" }` |
---
### `GET /api/v1/auth/verify-email`
Kullanıcı email doğrulama linkindeki token ile hesabı aktive eder.
**Query parametreleri**
| Alan | Tip | Kural |
|---|---|---|
| `token` | string | Zorunlu |
**Yanıtlar**
| Durum | Açıklama | Gövde örneği |
|---|---|---|
| `200 OK` | Email doğrulandı | `{ "message": "email verified successfully" }` |
| `400 Bad Request` | Token eksik/geçersiz | `{ "error": "invalid or expired verification token" }` |
| `500 Internal Server Error` | Sunucu hatası | `{ "error": "could not verify email" }` |
---
### `POST /api/v1/auth/login`
E-posta ve şifre ile giriş yapar; token çifti döner.
**İstek gövdesi**
```json
{
"email": "ali@ornek.com",
"password": "gizli1234"
}
```
**Yanıtlar**
| Durum | Açıklama | Gövde örneği |
|---|---|---|
| `200 OK` | Giriş başarılı | Aşağıya bakın |
| `400 Bad Request` | Eksik alan | `{ "error": "..." }` |
| `401 Unauthorized` | Yanlış bilgi | `{ "error": "invalid email or password" }` |
| `403 Forbidden` | Email doğrulanmamış | `{ "error": "email is not verified" }` |
```json
// 200 OK
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer"
}
```
---
### `POST /api/v1/auth/refresh`
Süresi dolmuş access token'ı yeniler.
**İstek gövdesi**
```json
{ "refresh_token": "eyJ..." }
```
**Yanıtlar**
| Durum | Açıklama | Gövde örneği |
|---|---|---|
| `200 OK` | Yenileme başarılı | `{ "access_token": "eyJ...", "token_type": "Bearer" }` |
| `400 Bad Request` | Eksik alan | `{ "error": "..." }` |
| `401 Unauthorized` | Token geçersiz/süresi dolmuş | `{ "error": "invalid or expired refresh token" }` |
| `403 Forbidden` | Email doğrulanmamış | `{ "error": "email is not verified" }` |
---
## Korumalı Endpoint'ler
_`Authorization: Bearer <access_token>` başlığı zorunludur._
---
### `GET /api/v1/me`
Oturum açmış kullanıcının kimlik bilgilerini döner.
**İstek başlığı**
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**Yanıtlar**
| Durum | Açıklama | Gövde örneği |
|---|---|---|
| `200 OK` | Başarılı | `{ "user_id": 1, "email": "ali@ornek.com", "username": "ali" }` |
| `401 Unauthorized` | Başlık eksik veya token geçersiz | `{ "error": "authorization header missing or malformed" }` |
---
## Admin Yetkisi Gerektiren Endpoint'ler
Bu endpointler için kullanıcı hem giriş yapmış olmalı hem de `is_admin=true` olmalıdır.
### Settings
- `PUT /api/v1/settings`
- `POST /api/v1/settings/heroes`
- `PUT /api/v1/settings/heroes/{id}`
- `DELETE /api/v1/settings/heroes/{id}`
- `POST /api/v1/settings/cors/whitelist`
- `PUT /api/v1/settings/cors/whitelist/{id}`
- `DELETE /api/v1/settings/cors/whitelist/{id}`
- `POST /api/v1/settings/cors/blacklist`
- `PUT /api/v1/settings/cors/blacklist/{id}`
- `DELETE /api/v1/settings/cors/blacklist/{id}`
- `POST /api/v1/settings/rate-limits`
- `PUT /api/v1/settings/rate-limits/{id}`
- `DELETE /api/v1/settings/rate-limits/{id}`
### Shop
- `POST /api/v1/shop/categories`
- `PUT /api/v1/shop/categories/{id}`
- `DELETE /api/v1/shop/categories/{id}`
- `POST /api/v1/shop/tags`
- `PUT /api/v1/shop/tags/{id}`
- `DELETE /api/v1/shop/tags/{id}`
- `POST /api/v1/shop/products`
- `PUT /api/v1/shop/products/{id}`
- `DELETE /api/v1/shop/products/{id}`
### Blog
- `POST /api/v1/blog/categories`
- `PUT /api/v1/blog/categories/{id}`
- `DELETE /api/v1/blog/categories/{id}`
- `POST /api/v1/blog/tags`
- `PUT /api/v1/blog/tags/{id}`
- `DELETE /api/v1/blog/tags/{id}`
- `POST /api/v1/blog/posts`
- `PUT /api/v1/blog/posts/{id}`
- `DELETE /api/v1/blog/posts/{id}`
---
## Auth Gerekli (Okuma / Kullanıcı İşlemleri)
### Settings (read)
- `GET /api/v1/settings`
- `GET /api/v1/settings/heroes`
- `GET /api/v1/settings/cors/whitelist`
- `GET /api/v1/settings/cors/blacklist`
- `GET /api/v1/settings/rate-limits`
### Shop
- `GET /api/v1/shop/categories`
- `GET /api/v1/shop/tags`
- `GET /api/v1/shop/products`
- `GET /api/v1/shop/products/{id}`
- `GET /api/v1/shop/cart`
- `POST /api/v1/shop/cart/items`
- `PUT /api/v1/shop/cart/items/{itemId}`
- `DELETE /api/v1/shop/cart/items/{itemId}`
### Blog
- `GET /api/v1/blog/categories`
- `GET /api/v1/blog/tags`
- `GET /api/v1/blog/posts`
- `GET /api/v1/blog/posts/{id}`
---
## Runtime Güvenlik Davranışı
- **CORS blacklist**: origin varsa doğrudan blok (`403`).
- **CORS whitelist**: origin whitelist'te ise rate-limit muaf.
- **Whitelist/blacklist dışı**: CORS geçer, rate-limit uygulanır.
- **Rate limit kural sırası**:
1. Endpoint adı (`api/v1/auth/login` gibi)
2. Fallback `api`
> En güncel endpoint listesi ve request/response şemaları için Swagger UI kullanın.
---
## Hata Formatı
Tüm hata yanıtları aynı yapıdadır:
```json
{ "error": "açıklayıcı hata mesajı" }
```
---
## curl Örnekleri
```bash
# Kayıt
curl -X POST http://localhost:8080/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"ali","email":"ali@ornek.com","password":"gizli1234","confirm_password":"gizli1234"}'
# Email doğrulama
curl "http://localhost:8080/api/v1/auth/verify-email?token=<verification_token>"
# Giriş
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"ali@ornek.com","password":"gizli1234"}'
# Korumalı endpoint
curl http://localhost:8080/api/v1/me \
-H "Authorization: Bearer <access_token>"
# Token yenile
curl -X POST http://localhost:8080/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token":"<refresh_token>"}'
```
---
## Swagger
- UI: `http://localhost:8080/swagger/index.html`
- OpenAPI dosyaları: `docs/swagger.json`, `docs/swagger.yaml`

201
belgeler/auth.md Normal file
View File

@@ -0,0 +1,201 @@
# Kimlik Doğrulama Sistemi
## Genel Bakış
Proje email + şifre tabanlı kimlik doğrulama kullanır. Başarılı girişte iki token döner:
| Token | Ömür | Kullanım |
|---|---|---|
| `access_token` | 15 dakika | Her korumalı isteğe `Authorization: Bearer` başlığı |
| `refresh_token` | 7 gün | Süresi dolan access token'ı yenilemek için |
Ek kural: Email doğrulaması tamamlanmadan login ve refresh işlemleri engellenir.
Algoritma: **HS256** (HMAC-SHA256)
---
## Akış Diyagramı
```
┌─────────┐ POST /api/v1/auth/register ┌─────────┐
│ Client │ ────────────────────────────────────► │ Server │
│ │ ◄──── 201 { user_id } + verify mail │ │
└─────────┘ └─────────┘
┌─────────┐ GET /api/v1/auth/verify-email ┌─────────┐
│ Client │ ── token linki ile ──────────────────► │ Server │
│ │ ◄──── 200 email verified ──────────── │ │
└─────────┘ └─────────┘
┌─────────┐ POST /api/v1/auth/login ┌─────────┐
│ Client │ ── { email, password } ──────────────► │ Server │
│ │ ◄── 200 { access_token, │ │
│ │ refresh_token } ───────────── └─────────┘
└─────────┘
┌─────────┐ GET /api/v1/me ┌─────────┐
│ Client │ ── Authorization: Bearer <access> ───► │ Server │
│ │ ◄── 200 { user_id, email, username } │ (auth │
└─────────┘ │ middleware)
└─────────┘
┌─────────┐ POST /api/v1/auth/refresh ┌─────────┐
│ Client │ ── { refresh_token } ────────────────► │ Server │
│ │ ◄── 200 { access_token } ───────────── └─────────┘
└─────────┘
```
---
## Kayıt (`Register`)
**Dosya:** `app/accounts/controllers/user.go``Register()`
1. JSON body doğrulanır (`username` min 3, `email` geçerli format, `password` min 8 karakter, `confirm_password` min 8 karakter).
2. `password` ve `confirm_password` eşleşmesi kontrol edilir.
3. Şifre `bcrypt.DefaultCost` ile hash'lenir.
4. `User` kaydı veritabanına yazılır.
5. Rastgele bir email doğrulama token'ı üretilir ve kullanıcıya yazılır.
6. Kullanıcıya doğrulama maili gönderilir.
7. `email` alanı unique index'li; duplicate durumunda `409 Conflict` döner.
Not: Mail gönderimi başarısız olursa oluşturulan kullanıcı kaydı geri silinir.
```json
// İstek
{
"username": "ali",
"email": "ali@ornek.com",
"password": "gizli1234",
"confirm_password": "gizli1234"
}
// Başarılı yanıt 201
{ "message": "user created. please verify your email", "user_id": 1 }
```
## Email Doğrulama (`VerifyEmail`)
**Dosya:** `app/accounts/controllers/user.go``VerifyEmail()`
1. Query string içinden `token` alınır.
2. Token ile kullanıcı bulunur.
3. `email_verified=true`, `email_verified_at=now`, `email_verify_token=""` olarak güncellenir.
```json
// Başarılı yanıt 200
{ "message": "email verified successfully" }
```
---
## Giriş (`Login`)
**Dosya:** `app/accounts/controllers/user.go``Login()`
1. Email ile kullanıcı aranır.
2. `email_verified` kontrol edilir; doğrulanmamış hesaplara `403` dönülür.
3. `bcrypt.CompareHashAndPassword` ile şifre doğrulanır.
4. Her iki adımda da hata mesajı aynı tutulur — kullanıcı numaralandırma saldırısına karşı.
5. Başarıda access + refresh token döner.
```json
// İstek
{ "email": "ali@ornek.com", "password": "gizli1234" }
// Başarılı yanıt 200
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "Bearer"
}
```
---
## Token Yenileme (`RefreshToken`)
**Dosya:** `app/accounts/controllers/user.go``RefreshToken()`
1. Body'den `refresh_token` alınır.
2. `JWT_REFRESH_SECRET` ile doğrulanır.
3. Kullanıcının `email_verified` durumu kontrol edilir; doğrulanmamışsa `403` döner.
4. Claims'ten `user_id`, `email`, `username` alanları kullanılarak yeni access token üretilir.
5. Refresh token yenilenmez (sliding window değil, sabit pencere).
```json
// İstek
{ "refresh_token": "eyJ..." }
// Başarılı yanıt 200
{ "access_token": "eyJ...", "token_type": "Bearer" }
```
---
## Google Login (OAuth 2.0)
**Dosya:** `app/accounts/controllers/user.go``GoogleLogin()` ve `GoogleCallback()`
Akış:
1. `GET /api/v1/auth/google/login`
2. Sunucu CSRF için `state` üretir, cookie'ye yazar ve `auth_url` döner.
3. Client kullanıcıyı `auth_url` adresine yönlendirir.
4. Google kullanıcıyı callback'e döndürür: `GET /api/v1/auth/google/callback?state=...&code=...`
5. Sunucu `state` doğrular, `code` ile Google'dan token alır.
6. Google `userinfo` verisi çekilir.
7. Kullanıcı email'e göre bulunur/oluşturulur, `SocialAccount(provider=google)` kaydı bağlanır.
8. Google ile gelen kullanıcı email'i doğrulanmış kabul edilir (`email_verified=true`).
9. Yerel `access_token` + `refresh_token` üretilip döndürülür.
Yeni endpointler:
- `GET /api/v1/auth/google/login`
- `GET /api/v1/auth/google/callback`
---
## GitHub Login (OAuth 2.0)
**Dosya:** `app/accounts/controllers/user.go``GitHubLogin()` ve `GitHubCallback()`
Akış:
1. `GET /api/v1/auth/github/login`
2. Sunucu CSRF için `state` üretir, cookie'ye yazar ve `auth_url` döner.
3. Client kullanıcıyı `auth_url` adresine yönlendirir.
4. GitHub callback'e döndürür: `GET /api/v1/auth/github/callback?state=...&code=...`
5. Sunucu `state` doğrular, `code` ile GitHub'dan token alır.
6. GitHub profil/email bilgisi çekilir.
7. Kullanıcı email'e göre bulunur/oluşturulur, `SocialAccount(provider=github)` kaydı bağlanır.
8. GitHub ile gelen kullanıcı email'i doğrulanmış kabul edilir (`email_verified=true`).
9. Yerel `access_token` + `refresh_token` üretilip döndürülür.
Yeni endpointler:
- `GET /api/v1/auth/github/login`
- `GET /api/v1/auth/github/callback`
---
## Güvenlik Notları
- Şifreler veritabanında **asla düz metin** tutulmaz; bcrypt hash'i saklanır.
- `Password` alanı modelde `json:"-"` ile işaretlidir — API yanıtlarında görünmez.
- Access ve refresh token farklı secret'larla imzalanır (`JWT_SECRET` / `JWT_REFRESH_SECRET`).
- Production'da her iki secret'ın en az 32 karakter uzunluğunda, rastgele olması gerekir.
- HTTPS zorunludur; token'lar aktarım sırasında şifrelenmez.
- Register adımında şifre uyumsuzluğu için `400 Bad Request` dönülür: `password and confirm_password do not match`.
---
## Swagger
- Swagger UI: `/swagger/index.html`
- Doküman üretme komutu:
```bash
$(go env GOPATH)/bin/swag init -g main.go
```

View File

@@ -0,0 +1,151 @@
# Ortam Değişkenleri
Proje kök dizinindeki `.env` dosyasından veya sistem ortam değişkenlerinden okunur.
`.env` yoksa sistem değişkenleri kullanılır (ör. Docker, CI ortamları).
---
## Veritabanı
| Değişken | Varsayılan | Açıklama |
|---|---|---|
| `DB_HOST` | `localhost` | MySQL sunucu adresi |
| `DB_PORT` | `3306` | MySQL port |
| `DB_USER` | `root` | Veritabanı kullanıcı adı |
| `DB_PASSWORD` | _(boş)_ | Veritabanı şifresi |
| `DB_NAME` | `goaresv3` | Veritabanı adı |
---
## JWT
| Değişken | Açıklama |
|---|---|
| `JWT_SECRET` | Access token imzalama anahtarı (min 32 karakter önerilir) |
| `JWT_REFRESH_SECRET` | Refresh token imzalama anahtarı (min 32 karakter önerilir) |
> **Uyarı:** Her iki secret production ortamda farklı, uzun ve rastgele olmalıdır.
> Örnek üretim komutu:
> ```bash
> openssl rand -hex 32
> ```
---
## Uygulama
| Değişken | Varsayılan | Açıklama |
|---|---|---|
| `PORT` | `8080` | HTTP sunucu portu |
| `APP_BASE_URL` | `http://localhost:8080` | Email doğrulama linki oluşturmak için temel adres |
---
## Google OAuth
| Değişken | Varsayılan | Açıklama |
|---|---|---|
| `SOCIAL_AUTH_GOOGLE_OAUTH2_KEY` | - | Google OAuth istemci ID |
| `SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET` | - | Google OAuth istemci secret |
| `SOCIAL_AUTH_GOOGLE_REDIRECT_URL` | - | Google callback URL (ör: `http://localhost:8080/api/v1/auth/google/callback`) |
| `SOCIAL_AUTH_GOOGLE_SCOPES` | `openid,email,profile` | İsteğe bağlı scope listesi (virgülle ayrılmış) |
---
## GitHub OAuth
| Değişken | Varsayılan | Açıklama |
|---|---|---|
| `SOCIAL_AUTH_GITHUB_KEY` | - | GitHub OAuth istemci ID |
| `SOCIAL_AUTH_GITHUB_SECRET` | - | GitHub OAuth istemci secret |
| `SOCIAL_AUTH_GITHUB_REDIRECT_URL` | - | GitHub callback URL (ör: `http://localhost:8080/api/v1/auth/github/callback`) |
| `SOCIAL_AUTH_GITHUB_SCOPES` | `read:user,user:email` | İsteğe bağlı scope listesi (virgülle ayrılmış) |
---
## CORS Bootstrap
> Bu değerler sadece **ilk açılış seed** için kullanılır.
> DB'de kayıt varsa üzerine yazılmaz.
| Değişken | Varsayılan | Açıklama |
|---|---|---|
| `CORS_BOOTSTRAP_WHITELIST_ORIGINS` | _(boş)_ | Virgülle ayrılmış origin listesi (ör: `http://localhost:3000,https://admin.ornek.com`) |
| `CORS_BOOTSTRAP_BLACKLIST_ORIGINS` | _(boş)_ | Virgülle ayrılmış engelli origin listesi |
---
## Rate Limit Bootstrap
> Bu değerler sadece **ilk açılış seed** için kullanılır.
> `rate_limit_settings` tablosunda aynı `name` varsa değiştirilmez.
| Değişken | Varsayılan | Açıklama |
|---|---|---|
| `RL_BOOTSTRAP_LOGIN_MAX_REQUESTS` | `10` | `api/v1/auth/login` için maksimum istek |
| `RL_BOOTSTRAP_LOGIN_WINDOW_SECONDS` | `60` | Login penceresi (sn) |
| `RL_BOOTSTRAP_REGISTER_MAX_REQUESTS` | `5` | `api/v1/auth/register` için maksimum istek |
| `RL_BOOTSTRAP_REGISTER_WINDOW_SECONDS` | `60` | Register penceresi (sn) |
| `RL_BOOTSTRAP_API_MAX_REQUESTS` | `120` | Diğer endpointler için fallback `api` limiti |
| `RL_BOOTSTRAP_API_WINDOW_SECONDS` | `60` | Genel fallback pencere (sn) |
---
## Email
| Değişken | Varsayılan | Açıklama |
|---|---|---|
| `EMAIL_HOST` | - | SMTP sunucu adresi |
| `EMAIL_PORT` | - | SMTP port |
| `EMAIL_HOST_USER` | _(boş olabilir)_ | SMTP kullanıcı adı |
| `EMAIL_HOST_PASSWORD` | _(boş olabilir)_ | SMTP şifresi |
| `EMAIL_USE_TLS` | `false` | STARTTLS kullanılsın mı |
| `EMAIL_USE_SSL` | `false` | SMTPS (SSL/TLS) doğrudan bağlantı kullanılsın mı |
| `EMAIL_FROM` | - | Gönderici email adresi |
---
## Örnek `.env`
```dotenv
DB_HOST=localhost
DB_PORT=3307
DB_USER=root
DB_PASSWORD=sifrem
DB_NAME=goaresv3
JWT_SECRET=uretilen-guclu-secret-1
JWT_REFRESH_SECRET=uretilen-guclu-secret-2
PORT=8080
APP_BASE_URL=http://localhost:8080
EMAIL_HOST=10.80.80.70
EMAIL_PORT=1025
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
EMAIL_USE_TLS=false
EMAIL_USE_SSL=false
EMAIL_FROM=noreply@gauth.local
CORS_BOOTSTRAP_WHITELIST_ORIGINS=http://localhost:3000,http://localhost:5173
CORS_BOOTSTRAP_BLACKLIST_ORIGINS=
RL_BOOTSTRAP_LOGIN_MAX_REQUESTS=10
RL_BOOTSTRAP_LOGIN_WINDOW_SECONDS=60
RL_BOOTSTRAP_REGISTER_MAX_REQUESTS=5
RL_BOOTSTRAP_REGISTER_WINDOW_SECONDS=60
RL_BOOTSTRAP_API_MAX_REQUESTS=120
RL_BOOTSTRAP_API_WINDOW_SECONDS=60
```
---
## Güvenlik
- `.env` dosyasını **asla** Git'e commit etmeyin.
- `.gitignore` dosyanıza ekleyin:
```
.env
```
- Staging/production ortamlarda değişkenleri CI/CD secret yöneticisi (GitHub Secrets, Vault) ile iletin.

56
belgeler/proje-yapisi.md Normal file
View File

@@ -0,0 +1,56 @@
# Proje Yapısı
```
goaresv3/
├── main.go
├── .env
├── app/
│ ├── accounts/
│ │ ├── controllers/user.go
│ │ └── models/accounts.go
│ ├── settings/
│ │ ├── controllers/settings.go
│ │ └── models/{setting,hero,cors}.go
│ ├── shop/
│ │ ├── controllers/shop.go
│ │ └── models/{product,cart}.go
│ └── blog/
│ ├── controllers/blog.go
│ └── models/blog.go
├── config/database.go
├── pkg/
│ ├── jwt/jwt.go
│ ├── mailer/mailer.go
│ ├── middleware/{auth,cors_dynamic,rate_limit_dynamic}.go
│ └── swaggerui/initializer.go
├── router/router.go
├── docs/{docs.go,swagger.json,swagger.yaml}
└── belgeler/
```
## Uygulama Akışı
1. `.env` yüklenir (`godotenv`).
2. `config.ConnectDB()` ile MySQL bağlantısıılır.
3. `config.RunAutoMigrate()` tüm modüllerin şemalarını uygular.
4. `config.SeedSecurityDefaults()` CORS/RateLimit başlangıç kayıtlarını (yoksa) ekler.
5. Gin başlatılır, global middlewareler çalışır:
- `DynamicCORS()`
- `DynamicRateLimit()`
6. `router.Setup(r)` ile endpointler yüklenir.
## Yetki Modeli
- `AuthRequired()`:
- Access token doğrular
- Context'e `user_id`, `email`, `username` yazar
- `AdminRequired()`:
- `users.is_admin` alanını kontrol eder
- `POST/PUT/DELETE/PATCH` gibi mutating endpointlerde kullanılır
## Route Grupları
- Public: `/api/v1/auth/*`
- Auth zorunlu (read + user işlemleri): `/api/v1/*`
- Admin zorunlu (mutating yönetim işlemleri): `/api/v1/*` altında admin grubu
- Swagger UI: `/swagger/*any`

88
belgeler/testler.md Normal file
View File

@@ -0,0 +1,88 @@
# Test Rehberi
Bu dokuman projedeki otomatik test kapsamini ve calistirma adimlarini ozetler.
## Calistirma
Tum testleri calistirmak icin:
```bash
go test ./...
```
Kapsam (coverage) ile calistirmak icin:
```bash
go test -cover ./...
```
## Endpoint Test Matrisi
Asagidaki endpointler otomatik testlerle, hem basarili hem hata senaryolariyla kapsanir:
| Endpoint | Durum kodlari | Dosyalar |
|---|---|---|
| `POST /api/v1/auth/register` | `201`, `400`, `409`, `500` | [router/router_test.go](../router/router_test.go), [app/accounts/controllers/user_test.go](../app/accounts/controllers/user_test.go) |
| `GET /api/v1/auth/verify-email` | `200`, `400` | [router/router_test.go](../router/router_test.go), [app/accounts/controllers/user_test.go](../app/accounts/controllers/user_test.go) |
| `POST /api/v1/auth/login` | `200`, `400`, `401`, `403` | [router/router_test.go](../router/router_test.go), [app/accounts/controllers/user_test.go](../app/accounts/controllers/user_test.go) |
| `POST /api/v1/auth/refresh` | `200`, `400`, `401`, `403` | [router/router_test.go](../router/router_test.go), [app/accounts/controllers/user_test.go](../app/accounts/controllers/user_test.go) |
| `GET /api/v1/me` | `200`, `401` | [router/router_test.go](../router/router_test.go), [app/accounts/controllers/user_test.go](../app/accounts/controllers/user_test.go), [pkg/middleware/auth_test.go](../pkg/middleware/auth_test.go) |
| `GET /swagger/index.html` | `200` | [router/router_test.go](../router/router_test.go) |
| `POST /swagger/index.html` | `404` | [router/router_test.go](../router/router_test.go) |
| `GET /swagger/swagger-initializer.js` | `200` | [router/router_test.go](../router/router_test.go) |
## Endpoint Senaryo Detayi
### `POST /api/v1/auth/register`
- Basarili kayit ve mail gonderimi
- `password`/`confirm_password` uyusmazligi
- Duplicate email
- SMTP/config hatasinda register rollback
### `GET /api/v1/auth/verify-email`
- Basarili token ile aktivasyon
- Token eksik
- Token gecersiz
### `POST /api/v1/auth/login`
- Dogrulanmis hesapla basarili login
- Eksik/hatali request body
- Yanlis sifre veya bulunamayan email
- Dogrulanmamis email
### `POST /api/v1/auth/refresh`
- Gecerli refresh token ile yeni access token
- Eksik request body
- Bozuk/gecersiz JWT
- Token kullanicisi bulunamadi
- Dogrulanmamis email
### `GET /api/v1/me`
- Gecerli Bearer access token ile erisim
- Authorization header yok
- Raw token (Bearer olmadan) reddi
- Username context yoksa DB fallback
## Paket Bazli Testler
| Paket | Dosya | Kapsam |
|---|---|---|
| `pkg/jwt` | [pkg/jwt/jwt_test.go](../pkg/jwt/jwt_test.go) | Token uretim/dogrulama, yanlis secret davranisi |
| `pkg/middleware` | [pkg/middleware/auth_test.go](../pkg/middleware/auth_test.go), [pkg/middleware/dynamic_policies_test.go](../pkg/middleware/dynamic_policies_test.go) | Auth middleware + dynamic CORS/RateLimit davranisi |
| `pkg/mailer` | [pkg/mailer/mailer_test.go](../pkg/mailer/mailer_test.go) | SMTP config validasyonu ve fake SMTP ile gonderim |
| `app/accounts/controllers` | [app/accounts/controllers/user_test.go](../app/accounts/controllers/user_test.go) | Verify/Login/Refresh/Me handler seviyesinde davranis testleri |
## Dynamic Policy Testleri
`pkg/middleware/dynamic_policies_test.go` su senaryolari kapsar:
- Blacklist origin'in CORS tarafinda bloklanmasi
- Whitelist origin'in rate-limitten muaf olmasi
- Whitelist/blacklist disi origin'e rate-limit uygulanmasi
- `login` ve `register` endpointlerine ayri limit kurallarinin calismasi
## Notlar
- Endpoint entegrasyon testi icin test icinde gecici SQLite veritabani kullanilir.
- Register testinde email gonderimi icin test icinde fake SMTP sunucusu ayaga kaldirilir.
- Testler ortamdan bagimsiz calisacak sekilde gerekli env degerlerini test icinde set eder.

159
belgeler/veritabani.md Normal file
View File

@@ -0,0 +1,159 @@
# Veritabanı
ORM: **GORM v1.31**
Sürücü: **MySQL (gorm.io/driver/mysql)**
Karakter seti: `utf8mb4`
---
## Tablolar
### `users`
`gorm.Model` gömülüdür → `id`, `created_at`, `updated_at`, `deleted_at` otomatik eklenir.
| Sütun | Tip | Kısıtlama | Açıklama |
|---|---|---|---|
| `id` | BIGINT UNSIGNED | PK, AUTO_INCREMENT | — |
| `username` | VARCHAR(255) | — | Kullanıcı adı |
| `email` | VARCHAR(255) | UNIQUE, NOT NULL | Giriş e-postası |
| `password` | VARCHAR(255) | — | bcrypt hash (JSON'da gizli) |
| `email_verified` | TINYINT(1) | DEFAULT 0 | E-posta doğrulandı mı |
| `email_verify_token` | VARCHAR(255) | INDEX | Doğrulama token'ı |
| `email_verified_at` | DATETIME | NULL | Doğrulama zamanı |
| `is_admin` | TINYINT(1) | DEFAULT 0 | Yönetici mi |
| `created_at` | DATETIME | — | — |
| `updated_at` | DATETIME | — | — |
| `deleted_at` | DATETIME | INDEX, NULL | Soft-delete |
---
### `social_accounts`
| Sütun | Tip | Kısıtlama | Açıklama |
|---|---|---|---|
| `id` | BIGINT UNSIGNED | PK | — |
| `user_id` | BIGINT UNSIGNED | NOT NULL, INDEX | `users.id` yabancı anahtar |
| `provider` | VARCHAR(255) | NOT NULL | `google`, `github` vb. |
| `provider_id` | VARCHAR(255) | NOT NULL | Sağlayıcıdan gelen ID |
| `email` | VARCHAR(255) | — | Sağlayıcı e-postası |
| `name` | VARCHAR(255) | — | Tam ad |
| `avatar_url` | VARCHAR(255) | — | Profil fotoğrafı URL |
| `created_at` | DATETIME | — | — |
| `updated_at` | DATETIME | — | — |
| `deleted_at` | DATETIME | NULL | Soft-delete |
---
### `profiles`
| Sütun | Tip | Kısıtlama | Açıklama |
|---|---|---|---|
| `id` | BIGINT UNSIGNED | PK | — |
| `user_id` | BIGINT UNSIGNED | NOT NULL, INDEX | `users.id` yabancı anahtar |
| `avatar_url` | VARCHAR(255) | — | Profil fotoğrafı |
| `first_name` | VARCHAR(255) | — | Ad |
| `last_name` | VARCHAR(255) | — | Soyad |
| `created_at` | DATETIME | — | — |
| `updated_at` | DATETIME | — | — |
| `deleted_at` | DATETIME | NULL | Soft-delete |
---
### `settings`
Site genel ayarları.
Örnek alanlar:
- `title`, `meta_title`, `meta_description`
- `phone`, `url`, `email`
- sosyal alanlar (`facebook`, `x`, `instagram`, ...)
- logo/medya alanları (`w_logo`, `b_logo`, `w_width`, ...)
- `is_active`
### `heroes`
Anasayfa hero/banner kayıtları:
- `color`, `title`, `text1/text2/text4/text5`
- `image`, `width`, `height`, `quality`, `format`
- `is_active`
### `cors_whitelists` / `cors_blacklists`
Dynamic CORS politika tabloları:
- whitelist: izinli origin
- blacklist: engelli origin (öncelikli blok)
### `rate_limit_settings`
DB tabanlı rate-limit kuralları:
- `name` (unique): ör. `api/v1/auth/login`, `api/v1/auth/register`, `api`
- `max_requests`, `window_seconds`, `is_active`
### Shop tabloları
- `product_categories`
- `product_tags`
- `products`
- join tabloları: `product_product_categories`, `product_product_tags`
- `product_category_views`
- `product_comments`
- `carts`
- `cart_items`
### Blog tabloları
- `categories`
- `tags`
- `posts`
- join tabloları: `post_categories`, `post_tags`
- `category_views`
- `comments`
---
## İlişkiler
```
users (1) ──────── (N) social_accounts
users (1) ──────── (N) profiles
```
---
## AutoMigrate
`config.ConnectDB()` her başlatmada çalışır ve eksik tabloları / sütunları ekler.
Mevcut sütunları silmez veya daraltmaz.
```go
db.AutoMigrate(
&accountModels.User{},
&accountModels.SocialAccount{},
&accountModels.Profile{},
&settingsModels.Setting{},
&settingsModels.Hero{},
&settingsModels.CorsWhitelist{},
&settingsModels.CorsBlacklist{},
&settingsModels.RateLimitSetting{},
&shopModels.ProductCategory{},
&shopModels.ProductTag{},
&shopModels.Product{},
&shopModels.ProductCategoryView{},
&shopModels.ProductComment{},
&shopModels.Cart{},
&shopModels.CartItem{},
&blogModels.Category{},
&blogModels.Tag{},
&blogModels.Post{},
&blogModels.CategoryView{},
&blogModels.Comment{},
)
```
---
## Notlar
- Tüm modellerde `gorm.Model` kullanıldığı için soft delete (`deleted_at`) aktiftir.
- CORS ve rate-limit için başlangıç seed kayıtları uygulama açılışında yalnızca **yoksa** oluşturulur.