🛠️ 1. API (бэкенд внутри Next.js)
📌 Вариант с pages/
(Pages Router)
Создаёшь файлы в pages/api/
.
Например pages/api/users.js
:
// pages/api/users.js
export default function handler(req, res) {
if (req.method === "GET") {
res.status(200).json([{ id: 1, name: "John" }]);
} else if (req.method === "POST") {
const user = req.body;
res.status(201).json({ message: "User created", user });
}
}
Доступно по адресу:
👉 /api/users
📌 Вариант с app/
(App Router, Next 13+)
Здесь API создаётся через app/api/*/route.js
:
// app/api/users/route.js
export async function GET() {
return Response.json([{ id: 1, name: "Alice" }]);
}
export async function POST(req) {
const data = await req.json();
return Response.json({ message: "User created", user: data });
}
👉 будет доступно на /api/users
.
🛠️ 2. Подключение базы данных
Next не ограничивает — можно воткнуть что угодно:
- Prisma (SQL/NoSQL, удобный ORM)
- Mongoose (если MongoDB)
- Прямой
pg
драйвер (Postgres) - Supabase, Firebase и т.д.
Пример с Prisma и Postgres (app/api/users/route.js
):
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export async function GET() {
const users = await prisma.user.findMany();
return Response.json(users);
}
export async function POST(req) {
const data = await req.json();
const newUser = await prisma.user.create({ data });
return Response.json(newUser);
}
🛠️ 3. Админка
Тут есть несколько вариантов:
🔹 Собственная админка внутри Next
Просто сделай app/admin/page.js
или pages/admin.js
, и защищай её авторизацией (например, через NextAuth.js):
// app/admin/page.js
"use client";
import { useSession } from "next-auth/react";
export default function AdminPage() {
const { data: session } = useSession();
if (!session) return <p>Access denied</p>;
return <h1>Welcome to Admin Panel, {session.user.name}</h1>;
}
🔹 Подключение готовых решений
- React Admin — можно встроить прямо в Next.
- KeystoneJS или Strapi — как headless CMS + админка (ставятся отдельно, Next просто потребляет API).
- Sanity — CMS с админкой.
🛠️ 4. Авторизация и безопасность
- NextAuth.js → самое популярное решение для OAuth, JWT, сессий.
- Если нужна кастомная auth → можно самому хранить токены/сессии в базе и проверять их в
middleware.js
.
Подключение админки
📂 1. Модули (утилиты, хелперы, сервисы)
Все твои функции (например, utils.js
, api.js
, auth.js
) лучше складывать в папку lib/
или utils/
в корне проекта.
Пример структуры:
my-next-app/
├─ app/ (или pages/)
├─ components/
├─ lib/ <-- утилиты и модули
│ ├─ api.js
│ ├─ auth.js
│ └─ helpers.js
├─ public/
└─ ...
👉 Так принято в Next, и это даёт чистоту в импортах:
import { fetchData } from "@/lib/api";
📂 2. Layout’ы (общие и частичные)
В Pages Router (pages/
)
Глобальный layout → pages/_app.js
.
Частичные (например, DashboardLayout
) лучше хранить в components/layouts/
.
// components/layouts/DashboardLayout.js
export default function DashboardLayout({ children }) {
return (
<div className="dashboard">
<aside>Sidebar</aside>
<main>{children}</main>
</div>
);
}
Использование:
// pages/dashboard.js
import DashboardLayout from "@/components/layouts/DashboardLayout";
export default function DashboardPage() {
return (
<DashboardLayout>
<h1>Dashboard</h1>
</DashboardLayout>
);
}
В App Router (app/
)
Layout встроен в сам роут:
app/
├─ layout.js <-- глобальный layout
├─ dashboard/
│ ├─ layout.js <-- layout только для dashboard
│ └─ page.js
└─ about/
└─ page.js
Пример:
// app/dashboard/layout.js
export default function DashboardLayout({ children }) {
return (
<div className="dashboard">
<aside>Sidebar</aside>
<main>{children}</main>
</div>
);
}
👉 Всё, что внутри /dashboard/*
будет обёрнуто этим layout’ом.
📂 3. JSON (данные, конфиги)
Тут варианты зависят от того, для чего JSON:
-
Статичные данные (например, список товаров) → клади в
public/data/
илиlib/data/
.import products from "@/lib/data/products.json";
Если в
public/
, можно грузить через fetch:const res = await fetch("/data/products.json"); const products = await res.json();
-
Конфиги (например, настройки приложения) →
config/
илиlib/config/
. -
Данные, как API → можно положить JSON в
public/
и отдавать через/data/file.json
.
📂 Итоговая структура (пример)
my-next-app/
├─ app/ (или pages/) # страницы
├─ components/ # UI-компоненты
│ └─ layouts/ # layout’ы
├─ lib/ # утилиты, модули
│ ├─ api.js
│ ├─ helpers.js
│ └─ data/
│ └─ products.json
├─ public/ # статические файлы (картинки, json для fetch)
├─ config/ # конфиги приложения
├─ styles/ # CSS/SCSS/Tailwind
└─ ...
Структура
📂 Структура проекта в Next
app/
├─ layout.js # глобальный layout (NavBar, Footer, <head>)
├─ page.js # /
├─ about/
│ └─ page.js # /about
├─ beats/
│ └─ page.js # /beats
├─ discography/
│ └─ page.js # /discography
├─ albums/
│ └─ page.js # /albums
├─ video/
│ └─ page.js # /video
├─ contact/
│ └─ page.js # /contact
components/
├─ NavBar.js
├─ Footer.js
layouts/
├─ DefaultLayout.js
└─ HomeLayout.js
📝 Глобальный layout (app/layout.js
)
Это твой заменитель App.js
:
// app/layout.js
import "./globals.css";
import NavBar from "@/components/NavBar";
import Footer from "@/components/Footer";
export const metadata = {
title: "Music Artist | Musician. Producer. Beatmaker",
description: "Music artist website built with Next.js",
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<NavBar />
{children}
<Footer />
</body>
</html>
);
}
👉 Здесь уже не нужен useEffect
для document.title
— у Next есть встроенное metadata
.
📝 Главная страница с HomeLayout
// app/page.js
import HomeLayout from "@/layouts/HomeLayout";
import Home from "@/pages/Home";
export default function Page() {
return (
<HomeLayout>
<Home />
</HomeLayout>
);
}
📝 Другие страницы с DefaultLayout
Например /about
:
// app/about/page.js
import DefaultLayout from "@/layouts/DefaultLayout";
import About from "@/pages/About";
export default function Page() {
return (
<DefaultLayout>
<About />
</DefaultLayout>
);
}
Точно так же делаешь для /beats
, /discography
, /albums
, /video
, /contact
.
TS и global.css
✅ Почему так?
TypeScript по умолчанию не знает, что делать с .css
/ .scss
/ .svg
/ .png
и т.п. — он умеет проверять только TS/JS.
Решение: нужно подсказать компилятору, что эти импорты валидны.
🔹 Решение
Создай в корне проекта файл global.d.ts
(или declarations.d.ts
) и добавь туда:
// global.d.ts
declare module "*.css";
declare module "*.scss";
declare module "*.sass";
🔹 Проверка tsconfig.json
Убедись, что твой tsconfig.json
видит этот файл. Обычно Next добавляет **/*.d.ts
автоматически, но если нет — добавь:
{
"compilerOptions": {
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts"],
"exclude": ["node_modules"]
}
🔹 Файл globals.css
Убедись, что у тебя реально есть файл:
/app/globals.css
или
/src/app/globals.css
👉 Если он лежит в src/app/
, то импорт должен быть import "../globals.css";
из layout.tsx
.
🔹 Быстрый фикс (если не хочешь возиться с типами)
Можно добавить "skipLibCheck": true
в tsconfig.json
(часто включено по умолчанию у Next). Это отключает проверку типов у импортов .css
.
Админка
🔹 Вариант 1. Встроенная админка в Next
Ты просто делаешь отдельный роут /admin
внутри app/
или pages/
, и это будет админка.
Структура:
app/
├─ admin/
│ ├─ layout.tsx # общий layout для админки
│ └─ page.tsx # главная страница админки
Пример:
// app/admin/layout.tsx
"use client";
import { useSession } from "next-auth/react"; // если будешь использовать авторизацию
import type { ReactNode } from "react";
export default function AdminLayout({ children }: { children: ReactNode }) {
const { data: session } = useSession();
if (!session) return <p>Access denied</p>; // защита
return (
<div className="admin-layout">
<aside>Sidebar (меню админки)</aside>
<main>{children}</main>
</div>
);
}
// app/admin/page.tsx
export default function AdminPage() {
return <h1>Админка — Dashboard</h1>;
}
👉 У тебя будет полноценная защищённая зона /admin
.
🔹 Вариант 2. Админка через headless CMS
Если тебе нужно редактировать контент (тексты, картинки, товары и т.д.), а не код руками:
- Strapi — поднимешь бэкенд с админкой и API (GraphQL/REST).
- Sanity — встроенная админка в браузере + API.
- KeystoneJS — Node.js CMS с красивой админкой.
Тогда Next просто тянет данные по API:
const res = await fetch("http://localhost:1337/api/posts");
const posts = await res.json();
🔹 Вариант 3. React Admin (готовая библиотека)
React Admin можно встроить внутрь /admin
роутера. Он даёт таблицы, CRUD, фильтры.
Пример:
// app/admin/page.tsx
"use client";
import { Admin, Resource, ListGuesser } from "react-admin";
import simpleRestProvider from "ra-data-simple-rest";
export default function AdminPage() {
return (
<Admin dataProvider={simpleRestProvider("/api")}>
<Resource name="users" list={ListGuesser} />
<Resource name="posts" list={ListGuesser} />
</Admin>
);
}
🔐 Важное: защита админки
- NextAuth.js — лучшее решение для авторизации (Google, GitHub, JWT, Email).
- Можно добавить
middleware.ts
, чтобы перенаправлять неавторизованных:
// middleware.ts
import { getToken } from "next-auth/jwt";
import { NextResponse } from "next/server";
export async function middleware(req: Request) {
const token = await getToken({ req });
const url = new URL(req.url);
if (url.pathname.startsWith("/admin") && !token) {
return NextResponse.redirect(new URL("/api/auth/signin", req.url));
}
return NextResponse.next();
}
Backend
🔹 Где писать бэкенд в Next.js?
1. App Router (новый, app/
)
API создаётся в папке app/api/*/route.ts
.
Каждый route.ts
= endpoint.
Пример:
app/
├─ api/
│ ├─ users/
│ │ └─ route.ts
│ └─ posts/
│ └─ route.ts
// app/api/users/route.ts
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json([{ id: 1, name: "Alice" }]);
}
export async function POST(req: Request) {
const body = await req.json();
return NextResponse.json({ message: "User created", user: body });
}
👉 Теперь у тебя есть API по адресу /api/users
.
2. Pages Router (старый, pages/
)
Если у тебя pages/
, то API делается в pages/api/*
.
// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from "next";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") {
res.status(200).json([{ id: 1, name: "Bob" }]);
} else if (req.method === "POST") {
res.status(201).json({ message: "User created" });
}
}
🔹 Можно ли работать с БД?
Да, без проблем:
- Prisma (Postgres, MySQL, SQLite, MongoDB)
- Mongoose (MongoDB)
- node-postgres (
pg
) - Drizzle ORM (лёгкий ORM, очень модный сейчас)
Пример (Prisma):
// app/api/users/route.ts
import { PrismaClient } from "@prisma/client";
import { NextResponse } from "next/server";
const prisma = new PrismaClient();
export async function GET() {
const users = await prisma.user.findMany();
return NextResponse.json(users);
}
export async function POST(req: Request) {
const data = await req.json();
const newUser = await prisma.user.create({ data });
return NextResponse.json(newUser);
}
🔹 Плюсы подхода «бэкенд в том же репо»
✅ Один кодовый репозиторий — легче поддерживать. ✅ Нет CORS — фронт и бэк в одном домене. ✅ Быстрое прототипирование (API готов сразу). ✅ Можно деплоить на Vercel / Netlify без отдельного сервера.
🔹 Минусы
⚠️ Если бэкенд очень тяжёлый (огромное API, очереди, WebSocket-ы), может быть лучше вынести его в отдельный сервис. ⚠️ Лимиты serverless (например, у Vercel есть ограничения на время выполнения функций).
БД
🔹 Вариант 1. Мок-данные прямо в коде
Ты уже так делал — lorem ipsum
, 12345
, массивы.
const users = [
{ id: 1, name: "Alice", email: "alice@test.com" },
{ id: 2, name: "Bob", email: "bob@test.com" },
];
✅ Быстро ✅ Ничего не ломается ❌ Нет ощущения “реальной БД” ❌ Придётся руками править данные
🔹 Вариант 2. Фейковая БД (SQLite/Postgres) через ORM
Можно подключить Prisma и завести SQLite-файл (db.sqlite
) прямо в проекте.
Пример:
- Установил Prisma:
npm install prisma @prisma/client
npx prisma init --datasource-provider sqlite
prisma/schema.prisma
:
model User {
id Int @id @default(autoincrement())
name String
email String @unique
}
- Прогнал миграцию:
npx prisma migrate dev --name init
- Теперь можешь использовать в API:
// app/api/users/route.ts
import { PrismaClient } from "@prisma/client";
import { NextResponse } from "next/server";
const prisma = new PrismaClient();
export async function GET() {
const users = await prisma.user.findMany();
return NextResponse.json(users);
}
✅ Реалистично (запросы, CRUD, типы) ✅ Полезно для прокачки навыков ❌ Чуть дольше настраивать, чем мок-данные
🔹 Вариант 3. Фейковый API без БД
Можно подключить JSON Server.
Ты заводишь db.json
→ и он поднимает фейковый REST API.
{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}
Запуск:
npx json-server --watch db.json --port 4000
Теперь в Next можно делать:
const res = await fetch("http://localhost:4000/users");
const users = await res.json();
✅ Очень просто ✅ Похоже на “реальный” бэкенд ❌ Отдельный процесс, лишний для MVP
Магазин
🔹 Архитектура магазина в Next.js
1. Структура страниц
app/
├─ shop/ → список товаров
│ ├─ page.tsx
│ └─ [id]/page.tsx → страница товара
├─ cart/page.tsx → корзина
└─ checkout/page.tsx → оформление заказа
2. Данные о товарах
Варианты:
- 🟢 На старте: JSON / мок-данные (типа
products.json
). - 🟢 Для практики: SQLite + Prisma (
Product
модель). - 🟡 В будущем: подключить headless-CMS (Strapi, Sanity) или вынести в API.
Пример модели Prisma:
model Product {
id Int @id @default(autoincrement())
name String
description String
price Float
imageUrl String
createdAt DateTime @default(now())
}
3. API для магазина
app/api/products/route.ts → список товаров
app/api/cart/route.ts → корзина
app/api/orders/route.ts → заказы
Пример app/api/products/route.ts
:
import { NextResponse } from "next/server";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export async function GET() {
const products = await prisma.product.findMany();
return NextResponse.json(products);
}
4. UI (React + TSX)
/shop
→ карточки товаров (с фото, ценой, кнопкой “в корзину”)./cart
→ список добавленных товаров./checkout
→ форма для оплаты.
🔹 Оплата (главный момент)
У тебя 3 пути:
🟢 Stripe (самый популярный)
- Платежи по карте, Apple Pay, Google Pay.
- Есть Next.js SDK (
@stripe/stripe-js
). - Для цифровых товаров (музыка, пресеты) идеально.
Пример (очень упрощённый):
// app/api/checkout/route.ts
import { NextResponse } from "next/server";
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const { items } = await req.json();
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
line_items: items,
mode: "payment",
success_url: "http://localhost:3000/success",
cancel_url: "http://localhost:3000/cancel",
});
return NextResponse.json({ url: session.url });
}
🟡 PayPal
- Простой вариант для фрилансеров/артистов.
- Есть кнопки оплаты → вставляешь в checkout.
🟠 Web3 (позже)
- Подключение Metamask, USDC/ETH платежей.
- Для твоей идеи с децентрализацией это 🔮, но лучше оставить на потом.
🔹 Минимальный flow магазина
/shop
→ список товаров./cart
→ клиентский стейт (useState, Redux или Zustand)./checkout
→ создаём Stripe-сессию, редирект на оплату./success
→ пользователь возвращается после оплаты, создаём заказ в базе.