Kinematik dark-galereya portfolio-sayti. Fotograf Sardor uchun tez, xavfsiz va o'zi boshqariladigan platforma — fotolarni ko'rsatish, buyurtma qabul qilish va qo'llab-quvvatlash uchun.
Next.js 15 · React 19 · TypeScript strict · Prisma · PostgreSQL · Tailwind v4
- Xususiyatlar
- Tez ishga tushirish (Docker)
- Serverga deploy — GitHub'dan bir buyruqda
- Lokal ishlab chiqish
- Environment o'zgaruvchilari
- Fayl saqlash — Local vs Cloudflare R2
- Arxitektura
- Skriptlar
- Xavfsizlik
- Litsenziya
- Kinematik masonry galereya — CSS emas, JS bilan tuzilgan; FLIP animatsiyasi, featured 2-ustun span.
- Har tashrifda tasodifiy tartib (admin panel'idan yoqib/o'chirib qo'yish mumkin).
- Lightbox — bir kontent ochilganda intercepting route (URL o'zgaradi, orqaga qaytish tabiiy).
- Buyurtma tizimi — kod bilan qidirish (
SB-1042) yoki maxfiy token orqali holatni ko'rish. - Kvitansiya OCR — Payme/Click chekini avtomatik o'qish,
Contentnarxi bilan solishtirish. - Donate sahifasi — Telegram-uslub izohlar, ixtiyoriy summa, "muallif" nomidan javob berish.
- Filtrlar — janr (bir kontent bir nechta janrda bo'lishi mumkin), joylashuv, yil.
- Blurhash — rasm yuklanguncha yumshoq placeholder.
- Yuklash — resumable chunked upload, individual metadata (janr, joy, sana, narx per fayl), rasm/video preview cardda.
- Kontent boshqaruvi — inline tahrirlash, bulk operatsiyalar (o'chirish, chop etish, janrga o'zgartirish).
- Buyurtmalar — kvitansiya ko'rish, OCR natijasi, tasdiqlash/rad etish, imzolangan URL bilan yuklab olish.
- Statistika — ko'rishlar, unique tashrifchilar, konversiya, top kontent, qurilma taqsimoti, manba (referrer).
- Sozlamalar — sayt sarlavhalari, taksonomiya, hero, to'lov kartalar, xavfsizlik chegaralari.
- Real-time yangilanish — SSE (Server-Sent Events) orqali barcha admin sahifalari va donate izohlari.
- Audit log — muhim harakatlar (login, credential o'zgarishi, o'chirishlar).
Eng oson yo'l — hech nima o'rnatmasdan. Kerak: Docker va Docker Compose.
git clone https://github.com/drowgone/shotbysardor.git
cd shotbysardor
cp .env.example .env
# .env ni tahrirlang: SESSION_SECRET, ADMIN_INITIAL_PASSWORD, POSTGRES_PASSWORD
docker compose up -d --buildBo'ldi. Ilova avtomatik ravishda:
- PostgreSQL konteynerini ishga tushiradi
- Next.js image'ni build qiladi (ffmpeg + sharp bilan)
prisma migrate deploy— barcha migratsiyalarni qo'llaydiprisma db seed— sozlamalar, boshlang'ich janrlar/joylashuvlar, admin parolini ekadi- Serverni port
3000da ochadi
Sayt: http://localhost:3000
Admin: http://localhost:3000/admin (parol — .env dagi ADMIN_INITIAL_PASSWORD)
Log ko'rish:
docker compose logs -f appTo'xtatish:
docker compose downMa'lumot va storage saqlanadi (volume'lar), qayta up qilsangiz shu holatida davom etadi.
Ubuntu/Debian VPS uchun to'liq deploy stsenariysi:
1) Bir marta — server tayyorlash:
# Docker o'rnatish
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
# Loyihani klonlash
git clone https://github.com/drowgone/shotbysardor.git
cd shotbysardor
cp .env.example .env2) .env ni tahrirlang — production qiymatlar bilan:
SESSION_SECRET="<openssl rand -hex 32 bilan generatsiya>"
ADMIN_INITIAL_PASSWORD="<kuchli parol>"
POSTGRES_PASSWORD="<kuchli parol>"
NEXT_PUBLIC_SITE_URL="https://shotbysardor.uz"
STORAGE_DRIVER="r2" # yoki "local"
# R2 kalitlari (agar r2 bo'lsa)3) Ishga tushirish:
docker compose up -d --build4) Kelgusidagi yangilanishlar — bir buyruq:
git pull && docker compose up -d --buildEndi loyiha :3000 portida ishlaydi. Oldiga nginx yoki Caddy qo'yib TLS bilan proksi qiling:
Nginx namuna konfiguratsiya
server {
listen 443 ssl http2;
server_name shotbysardor.uz;
ssl_certificate /etc/letsencrypt/live/shotbysardor.uz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shotbysardor.uz/privkey.pem;
client_max_body_size 2100M; # Video yuklash uchun
proxy_read_timeout 600s;
proxy_send_timeout 600s;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Caddy namuna (avtomatik TLS)
shotbysardor.uz {
reverse_proxy 127.0.0.1:3000 {
header_up X-Forwarded-For {remote_host}
}
request_body {
max_size 2100MB
}
}Docker'siz, to'g'ridan-to'g'ri Node.js bilan:
Talablar:
- Node.js ≥ 20
- PostgreSQL 14+ (yoki
docker compose up -d dbbilan) ffmpeg(sudo apt install ffmpegyokibrew install ffmpeg)
Qadamlar:
git clone https://github.com/drowgone/shotbysardor.git
cd shotbysardor
cp .env.example .env
# Postgres — Docker orqali (yoki o'z instansiyangizni ishlating)
docker compose up -d db
npm install
npm run db:migrate # Migratsiyalar
npm run db:seed # Boshlang'ich ma'lumotlar
npm run dev.env.example fayldagi barcha o'zgaruvchilar izohlari bilan yozilgan.
| O'zgaruvchi | Kerakligi | Tavsif |
|---|---|---|
DATABASE_URL |
✅ | PostgreSQL ulanish satri |
POSTGRES_PASSWORD |
✅ | Docker Compose Postgres paroli |
SESSION_SECRET |
✅ | Iron-session imzosi (≥32 belgi) |
ADMIN_INITIAL_PASSWORD |
✅ | Birinchi login uchun admin parol |
NEXT_PUBLIC_SITE_URL |
✅ | Sayt to'liq URL (meta uchun) |
APP_PORT |
❌ | Tashqi port (default 3000) |
STORAGE_DRIVER |
✅ | local yoki r2 |
R2_ACCOUNT_ID |
R2 uchun | Cloudflare R2 akkaunt ID |
R2_ACCESS_KEY_ID |
R2 uchun | R2 API kaliti |
R2_SECRET_ACCESS_KEY |
R2 uchun | R2 API maxfiy kaliti |
R2_BUCKET_PRIVATE |
R2 uchun | Originallar uchun bucket |
R2_BUCKET_PUBLIC |
R2 uchun | Preview/thumb uchun bucket |
R2_PUBLIC_CDN_URL |
R2 uchun | Public CDN URL |
MAX_PHOTO_MB |
❌ | Foto chegara (default 60) |
MAX_VIDEO_MB |
❌ | Video chegara (default 2048) |
MAX_RECEIPT_MB |
❌ | Kvitansiya chegara (default 10) |
Local (default): Fayllar server diskida storage/ papkasida. Docker'da bu volume — konteyner o'chsa ham saqlanadi. Kichik loyihalar uchun ideal.
R2 (production'da tavsiya etiladi):
- Egress bepul (Cloudflare CDN)
- S3-mos API
- Signed URL — original fayllar faqat tasdiqlangan buyurtma uchun 60s TTL bilan chiqadi
O'tish uchun kodni o'zgartirish shart emas — .env dagi STORAGE_DRIVER ni r2 qiling va R2 kalitlarini qo'ying.
┌─────────────────────────────────────────────────────────────┐
│ Public shell (Next.js App Router — RSC + Client hybrid) │
├─────────────────────────────────────────────────────────────┤
│ / — Masonry galereya (shuffle + filter) │
│ /p/[slug] — Kontent (lightbox intercepting route) │
│ /donate — Qo'llab-quvvatlash + Telegram-izohlar │
│ /aloqa — Aloqa + buyurtma holati (kod orqali) │
│ /admin — Login + shell (protected) │
├─────────────────────────────────────────────────────────────┤
│ API routes (nodejs runtime, Prisma bilan) │
│ /api/contents · /api/orders · /api/live (SSE) │
│ /api/admin/... (CSRF + iron-session bilan himoyalangan) │
├─────────────────────────────────────────────────────────────┤
│ Prisma ORM → PostgreSQL (Content, Genre[], Order, ...) │
│ Storage layer → Local FS yoki Cloudflare R2 (S3) │
│ Media pipeline (sharp + ffmpeg + blurhash) │
└─────────────────────────────────────────────────────────────┘
Muhim qarorlar:
- Bir kontent — bir nechta janr:
Content ↔ Genreimplicit M2M (_ContentGenresjoin jadval). - Resumable upload: chunkli PATCH + finalize, server sessiyasi diskda saqlanadi — brauzer yopilsa qayta yopishib davom etadi.
- Original fayllar hech qachon public URL bilan chiqmaydi — faqat
APPROVEDbuyurtma va limit tugamagan bo'lsa. - Analitika denormalizatsiya qilingan:
Content.viewsCountretentiondan keyin ham saqlanadi. - Real-time: SSE (Server-Sent Events) — WebSocket emas, kam murakkablik.
- Bot filtratsiya:
/api/trackichida (Edge middleware'da Prisma ishlamaydi).
npm run dev # Dev server (hot reload)
npm run build # Production build (avval prisma generate)
npm run start # Production start
npm run lint # ESLint
npm run typecheck # TypeScript strict tekshiruv
npm run db:migrate # Yangi migratsiya yaratish (dev)
npm run db:push # Migratsiyasiz schema'ni push qilish
npm run db:seed # Sozlamalar/janrlar seed
npm run db:studio # Prisma Studio (DB GUI)- iron-session — HTTP-only, signed cookie'lar
- CSRF token — barcha admin
POST/PATCH/DELETE'da majburiy - Rate limit — IP va sessiya bo'yicha (izoh, like, buyurtma yaratish)
- argon2 — parol hash (parametrlar production-grade)
- Session versioning — parol o'zgarganda barcha eski sessiyalar bekor bo'ladi
- IP hash — hech qachon xom IP saqlanmaydi, faqat sha256 hash
- Image bomb himoyasi — sharp metadatasi dekompressiyagacha tekshiriladi
- SSRF himoyasi —
next/imagefaqat aniq R2 hostidan fetch qiladi (remotePatternscheklangan) - File type sniffing — MIME faqat magic bytes'dan aniqlanadi, extension'ga ishonilmaydi
- Payme/Click avtomatik to'lov tekshiruvi
- Email/SMS xabarnomalar
- Ko'p tillilik va light mavzu
- Original videoni to'liq sifatda onlayn ko'rish
Barcha fotografiyalar va videolar mualliflik huquqi Sardorga tegishli. Kod bazasi shaxsiy foydalanish uchun.
Made with ❤️ by drowgone