Real loyiha arxitekturasi — papkalar tuzilishi, best practices

~25 daq · Next.js · Ilg'or mavzular

Muammodan boshlaylik

Loyiha bir yil oldin boshlangan. Hozir:

  • app/ ichida sahifalar, komponentlar, util lar, API chaqiruvlari aralash
  • Bir xil Prisma so'rovi 8 ta faylda nusxalangan — biriga ruxsat tekshiruvi qo'shildi, qolganlariga yo'q
  • components/ da 140 ta fayl; Button.tsx, Button2.tsx, NewButton.tsx
  • Hamma joyda 'use client' — chunki "shunday ishlaydi"
  • Yangi dasturchi bir haftada ham "qayerga nima yozish kerak"ligini tushunmaydi

Hayotiy o'xshatma

Yaxshi tashkil etilgan oshxona. Har narsaning joyi bor: pichoqlar — bir tortmada, ziravorlar — javonda, xom go'sht va tayyor taom — alohida. Yangi oshpaz birinchi kuniyoq nima qayerdaligini topadi. Tartibsiz oshxonada eng yaxshi oshpaz ham sekin ishlaydi va xato qiladi (xom va tayyor narsa aralashib ketadi — bizda: server va client kodi).


Tavsiya etilgan tuzilma

src/
├── app/                          # faqat routing: sahifalar, layout lar, route lar
│   ├── (marketing)/              # route group — ochiq sahifalar (25-dars)
│   │   ├── page.tsx
│   │   └── layout.tsx
│   ├── (dokon)/
│   │   ├── katalog/
│   │   │   ├── page.tsx
│   │   │   ├── loading.tsx
│   │   │   └── _components/      # faqat shu sahifaga xos (_ — route emas)
│   │   └── mahsulot/[id]/
│   ├── (auth)/login/
│   ├── dashboard/
│   ├── api/
│   │   ├── auth/[...nextauth]/route.ts
│   │   └── webhooks/
│   ├── layout.tsx
│   ├── not-found.tsx
│   └── global-error.tsx
│
├── features/                     # biznes funksiyalar
│   ├── savat/
│   │   ├── components/           # SavatTugmasi.tsx, SavatRoyxati.tsx
│   │   ├── actions.ts            # 'use server' — Server Action lar
│   │   ├── queries.ts            # server-only — ma'lumot olish
│   │   ├── schemas.ts            # Zod
│   │   └── types.ts
│   ├── mahsulotlar/
│   └── buyurtmalar/
│
├── components/
│   ├── ui/                       # shadcn: button, dialog... (52-dars)
│   └── layout/                   # Header, Footer
│
├── lib/
│   ├── prisma.ts                 # singleton (45-dars)
│   ├── dal.ts                    # talabQil, adminTalabQil (43-dars)
│   ├── env.ts                    # Zod bilan env (65-dars)
│   └── utils.ts                  # cn()
│
├── auth.ts, auth.config.ts       # Auth.js (38, 42-darslar)
├── middleware.ts
└── instrumentation.ts            # OpenTelemetry (74-dars)

Asosiy tamoyillar

1. app/ — faqat routing

// app/(dokon)/katalog/page.tsx — yupqa: ma'lumot olish va yig'ish
import { getMahsulotlar } from '@/features/mahsulotlar/queries'
import { MahsulotlarRoyxati } from '@/features/mahsulotlar/components/MahsulotlarRoyxati'
import { Filtrlar } from '@/features/mahsulotlar/components/Filtrlar'

export default async function Katalog({ searchParams }: { searchParams: Promise<Record<string, string>> }) {
  const filtr = await searchParams
  const { royxat, jami } = await getMahsulotlar(filtr)

  return (
    <>
      <Filtrlar />
      <MahsulotlarRoyxati mahsulotlar={royxat} jami={jami} />
    </>
  )
}

Sahifa biznes mantiqni bilmaydi — u feature lardan qismlarni yig'adi.

2. Feature bo'yicha guruhlash

Savat bilan bog'liq hamma narsa — features/savat/ da: komponentlar, Server Action lar, so'rovlar, sxemalar. O'zgartirish — bitta papkada; o'chirish — bitta papkani o'chirish.

3. Server va client chegarasi aniq

// features/mahsulotlar/queries.ts
import 'server-only'
import { cache } from 'react'
import { prisma } from '@/lib/prisma'

export const getMahsulot = cache(async (id: string) =>
  prisma.mahsulot.findUnique({ where: { id, faol: true }, select: mahsulotDTO })
)
// features/savat/actions.ts
'use server'
import { talabQil } from '@/lib/dal'
// har bir action: auth → Zod → baza → revalidate
  • queries.ts — server-only, faqat o'qish, DTO (faqat ochiq maydonlar)
  • actions.ts — 'use server', har biri o'z ichida ruxsatni tekshiradi
  • 'use client' — faqat interaktiv barg komponentlarda

4. Server Component — standart

Sahifa (server)
├── Sarlavha (server)
├── MahsulotMa'lumoti (server)
│   └── SavatgaTugma (client)      ← faqat shu interaktiv
└── Sharhlar (server, Suspense ichida)
    └── SharhForma (client)

'use client' ni daraxtning iloji boricha pastiga qo'ying — brauzerga kam JavaScript, tezroq sahifa (54-dars).


Ma'lumot oqimi

O'qish:  page.tsx ──▶ features/*/queries.ts (server-only, cache, DTO) ──▶ Prisma
Yozish:  Client forma ──▶ features/*/actions.ts ('use server')
                            ├── talabQil() — auth va ruxsat
                            ├── Zod — validatsiya
                            ├── Prisma — yozish
                            └── revalidateTag / revalidatePath
Tashqi:  mobil ilova, webhook ──▶ app/api/*/route.ts ──▶ o'sha queries va actions mantiqi

API endpoint lar faqat tashqi mijozlar uchun (31-dars). O'z sahifalaringiz — to'g'ridan-to'g'ri queries va actions.


Xavfsizlik — ro'yxat

  • Har bir Server Action va Route Handler — auth() + ruxsat (42-dars)
  • Update/delete — where da egasi (47-dars)
  • Barcha kirish — Zod bilan validatsiya
  • server-only — baza va maxfiy kalitlar bilan ishlaydigan fayllarda
  • DTO — client ga faqat kerakli maydonlar (46-dars)
  • NEXT_PUBLIC_ da maxfiy narsa yo'q (65-dars)
  • Xavfsizlik header lari, CSP (71-dars)
  • Login va SMS ga rate limit (34-dars)
  • Webhook lar — imzo tekshiruvi (35-dars)
  • Bog'liqliklar yangilangan (Dependabot)

Performance — ro'yxat

  • Server Component — standart, client — faqat kerak joyda
  • Promise.all — parallel so'rovlar; Suspense — sekin qismlar
  • Kesh strategiyasi aniq: statik / ISR / dinamik (59-dars)
  • next/image — sizes, LCP rasmga priority (57-dars)
  • next/font, next/script — lazyOnload (58-dars)
  • Og'ir client komponentlar — dynamic (56-dars)
  • Core Web Vitals kuzatiladi (54-dars)

Sifat — ro'yxat

  • TypeScript strict, ESLint, Prettier
  • Unit (Vitest) + muhim oqimlar uchun E2E (Playwright)
  • CI: lint → tsc → test → build; branch protection (69-dars)
  • error.tsx, not-found.tsx, loading.tsx — muhim segmentlarda
  • Monitoring: xatolar (Sentry), trace lar (74-dars)

[!TIP] Bu tuzilma — boshlang'ich nuqta, qonun emas. Kichik loyihada features/ siz, app/ + components/ + lib/ yetarli bo'lishi mumkin. Tuzilmani loyiha o'sishi bilan rivojlantiring: "bu faylni qayerga qo'yishni bilmayman" yoki "bir xil kod uchinchi marta nusxalandi" — qayta tuzish vaqti kelganining belgilari.

[!INFO] Muhimi — izchillik. Jamoa qaysi tuzilmani tanlasa ham, uni hamma bir xil qo'llashi kerak. Qoidalarni README yoki CONTRIBUTING.md da yozib qo'ying va ESLint bilan (masalan, features lar bir-biriga to'g'ridan-to'g'ri kirmasligi) avtomatik tekshiring.


Tez-tez uchraydigan xatolar

1. Hamma narsa app/ ichida

Komponentlar, util lar va sahifalar aralash — routing tuzilmasi o'qib bo'lmaydigan bo'ladi. app/ — routing; qolgani — features/, components/, lib/.

2. Ma'lumot olish komponentlarda tarqoq

Bir xil so'rov 8 joyda — ruxsat tekshiruvi birida bor, birida yo'q. Bitta queries.ts.

3. Root layout da 'use client'

Butun ilova client komponentga aylanadi — Server Component larning barcha afzalliklari yo'qoladi.


Xulosa

app/ — faqat routing: yupqa sahifalar, route group lar, _components
features/ — biznes funksiyalar: components, actions ('use server'), queries (server-only), schemas
components/ui — umumiy UI; lib/ — prisma, dal, env, utils
Server Component — standart; 'use client' — faqat barg komponentlarda
O'qish — queries (cache, DTO); yozish — actions (auth → Zod → DB → revalidate)
API — faqat tashqi mijozlar uchun
Xavfsizlik, performance va sifat ro'yxatlari; izchillik

Kurs yakunlandi

Tabriklaymiz — Next.js kursini tugatdingiz! Siz App Router va Server Component lardan boshlab rendering strategiyalari, ma'lumot olish, routing, API, autentifikatsiya, ma'lumotlar bazasi, stilizatsiya, performance, testlash, deployment va real loyiha arxitekturasigacha bo'lgan yo'lni bosib o'tdingiz.

Keyingi qadamlar:

  • O'z loyihangizni yarating — masalan, shu kursdagi do'kon — va Vercel yoki o'z serveringizga deploy qiling
  • TypeScript kursi — turlarni chuqurroq o'rganish
  • PostgreSQL kursi — ma'lumotlar bazasini mukammal bilish