Comment API iskeleti
Node.js + Express + Socket.io + Supabase + Redis tabanlı login/register API iskeleti. Güvenlik odaklı, host allowlist, rate limit, admin rol kilidi ve Redis oturum yönetimi içerir. Docker-compose ile Redis + API birlikte ayağa kalkar.
Dizın yapısı
src/
app.js // Express app
server.js // HTTP + Socket.io bootstrap
config/
env.js // .env yükleme ve parse
supabase.js // Supabase client
redis.js // Redis client
middleware/
authRequired.js
adminRequired.js
rateLimit.js
hostOnly.js
errorHandler.js
routes/
auth.routes.js
health.routes.js
controllers/
auth.controller.js
services/
auth.service.js
session.service.js
adminLock.service.js
utils/
crypto.js // bcrypt + JWT yardımcıları
response.js // standart JSON çıktı
Çalıştırma
- Bağımlılıklar:
npm installNot:
metascraperbağımlılığı özel git repo’dan gelir (git+https://gitea.wisecolt-panda.net/wisecolt/metascraper.git). Erişim için uygun token/SSH anahtarı olan bir ortamdanpm installçalıştırın. Docker build için base imajagiteklenmiştir; özel repo erişimi için gerekirseGIT_SSH_COMMANDveyaGITHUB_TOKENbenzeri auth ekleyin. - Ortam değişkenleri:
.env.exampledosyasını.envolarak kopyalayıp doldurun. - Geliştirme:
npm run dev - Üretim:
npm start
Docker
Yerelde (dev, hot-reload) Redis ile birlikte çalıştırmak için:
docker compose -f docker-compose.dev.yml up --build
# durdurmak için
docker compose -f docker-compose.dev.yml down
- API:
http://localhost:${PORT} - Redis:
redis://localhost:6379(container içinderedis://redis:6379)
Prod modunda Docker
.enviçindeNODE_ENV=productionve mümkünseCOOKIE_SECURE=true,TRUST_PROXY=loopback(veya proxy sayısı) olarak ayarlayın.- Çalıştırın:
docker compose up --build -d - Durdurun:
docker compose down
.env örneği
NODE_ENV=development
PORT=3000
TRUST_PROXY=loopback
SUPABASE_URL=https://YOUR-SUPABASE-PROJECT.supabase.co
SUPABASE_SERVICE_ROLE_KEY=YOUR_SUPABASE_SERVICE_ROLE_KEY
REDIS_URL=redis://redis:6379
JWT_SECRET=supersecretjwt
JWT_EXPIRES_IN=7d
COOKIE_NAME=sid
COOKIE_SECURE=false
ADMIN_EMAIL=admin@example.com
ADMIN_USERNAME=admin
ADMIN_NAME=Admin User
ADMIN_ROLE_LOCK=true
HOST_ONLY_ALLOWLIST=127.0.0.1,::1
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX=100
LOGIN_RATE_LIMIT_WINDOW_MS=60000
LOGIN_RATE_LIMIT_MAX=5
Endpointler
GET /health—{ ok: true, time }POST /auth/register— body{ email, name, username, password }POST /auth/login— body{ emailOrUsername, password }POST /auth/logout— cookie tabanlı JWT silerGET /auth/me— aktif kullanıcıyı döndürürPOST /auth/refresh— yeni JWT üretir (iskelet)POST /meta/scrape— body{ url }, destekli domainler:netflix.com,primevideo.com(yalnızcarole: user)- Başarılı sorgu Supabase
media_datatablosuna kaydedilir:media_id, media_name, year, type(movie/tv), thumbnail_url, info, genre, media_provider (netflix/primevideo)
- Başarılı sorgu Supabase
Postman örnekleri
Register
POST {{baseUrl}}/auth/register
Content-Type: application/json
Body:
{
"email": "user@example.com",
"name": "Test User",
"username": "testuser",
"password": "password123"
}
200:
{
"user": {
"id": "...",
"email": "user@example.com",
"name": "Test User",
"username": "testuser",
"roleEffective": "user"
}
}
Login
POST {{baseUrl}}/auth/login
Content-Type: application/json
Body:
{
"emailOrUsername": "testuser",
"password": "password123"
}
200:
{
"user": {
"id": "...",
"email": "user@example.com",
"name": "Test User",
"username": "testuser",
"roleEffective": "user"
}
}
JWT otomatik olarak Cookie: sid=<token> olarak set edilir.
Me
GET {{baseUrl}}/auth/me
Cookie: sid=<token>
200:
{
"user": {
"id": "...",
"email": "...",
"username": "...",
"roleEffective": "user"
}
}
Logout
POST {{baseUrl}}/auth/logout
Cookie: sid=<token>
200:
{ "message": "Çıkış yapıldı" }
Meta scrape (Netflix/Prime)
POST {{baseUrl}}/meta/scrape
Content-Type: application/json
Cookie: sid=<token> # roleEffective=user
Body:
{ "url": "https://www.netflix.com/tr/title/81507921" }
Prime örneği:
{ "url": "https://www.primevideo.com/-/tr/detail/0NHIN3TGAI9L7VZ45RS52RHUPL/ref=share_ios_movie" }
200 (örnek):
{
"provider": "netflix",
"type": "movie",
"media": {
"url": "https://www.netflix.com/title/82123114",
"id": "82123114",
"name": "ONE SHOT with Ed Sheeran",
"year": "2025",
"seasons": null,
"thumbnail": "...",
"info": "...",
"genre": "..."
},
"saved": {
"media_id": "82123114",
"media_name": "ONE SHOT with Ed Sheeran",
"year": "2025",
"type": "movie",
"thumbnail_url": "...",
"info": "...",
"genre": "...",
"media_provider": "netflix",
"created_at": "..."
}
}
Hata çıktıları tek tip:
{
"error": { "code": "ERROR_CODE", "message": "Açıklama", "details": [...] }
}
Supabase şeması (SQL)
create extension if not exists "pgcrypto";
create table if not exists public.users (
id uuid primary key default gen_random_uuid(),
email text unique not null,
name text not null,
username text unique not null,
password_hash text not null,
role text not null default 'user' check (role in ('user','admin')),
created_at timestamp with time zone default now()
);
create table if not exists public.media_data (
media_id varchar,
media_name text,
year numeric,
type text,
thumbnail_url varchar,
info text,
genre text,
media_provider text,
created_at timestamp with time zone default now()
);
Admin rol kilidi: Sadece
.enviçindekiADMIN_EMAILveADMIN_USERNAMEile birebir eşleşen kullanıcı API tarafındanadminkabul edilir. Supabase üzerinde rol elle değiştirilse bile etkisizdir.
Güvenlik notları
hostOnlymiddleware ve CORS sadece allowlist’teki host/ip erişimine izin verir.- Global rate limit + login özel rate limit aktiftir.
- JWT httpOnly cookie olarak set edilir; Redis içinde
session:{jti}anahtarıyla oturum metadata tutulur.
Socket.io
- Handshake sırasında cookie’deki JWT doğrulanır, Redis oturum kontrol edilir.
- Başarılı bağlantıda
welcomeeventi döner. - Örnek ping/pong:
- Client:
socket.emit('ping') - Server cevabı:
pongiçinde zaman damgası.
- Client:
Docker notları
docker-compose.ymliçindeapiservisiredisservisine bağımlıdır.- Geliştirme için kod klasörü container içine mount edilerek canlı yenileme (
npm run dev) sağlanır. - Sağlık kontrolü: container içinde
GET /healthçağrısı ile yapılır.
Yapılandırılabilir noktalar
- Rate limit penceresi ve max değerleri
.envile ayarlanır. HOST_ONLY_ALLOWLISTile izin verilen host/ip listesi yönetilir.ADMIN_ROLE_LOCKkapatılmadıkça tek admin.env’deki kullanıcıdır.
TODO / Genişletme fikirleri
- Refresh token için ayrı bir anahtar ve whitelist mekanizması.
- Audit logları (morgan loglarını dosyaya yazma).
- Supabase RPC veya policy’lerle ek güvenlik.
- Testler (Jest/Supertest) ve CI pipeline’ı.