All checks were successful
ci/woodpecker/push/deploy Pipeline was successful
7.3 KiB
7.3 KiB
GoodBrick Site
Сайт производителя фасадной плитки GoodBrick с каталогом продукции.
Stack
- Frontend: Next.js 16 + shadcn/ui + Tailwind CSS 4 (TypeScript)
- Backend: .NET 9 Web API (C#)
- Database: PostgreSQL 16
- Proxy: Caddy 2 (auto-SSL)
- CI/CD: Woodpecker CI (Gitea OAuth)
- Git: Gitea (self-hosted)
Project Structure
GBSite/
├── frontend/ # Next.js app
│ ├── src/app/ # App Router pages
│ ├── src/lib/ # Utilities
│ ├── Dockerfile # Multi-stage: node:20-alpine
│ └── package.json
├── backend/ # .NET 9 Web API
│ ├── src/GBSite.Api/ # Main API project
│ │ ├── Controllers/
│ │ └── Program.cs
│ ├── GBSite.Api.sln
│ └── Dockerfile # Multi-stage: dotnet sdk → aspnet runtime
├── deploy/
│ ├── docker-compose.prod.yml
│ ├── docker-compose.dev.yml
│ └── docker-compose.local.yml # Local backend (Docker mode)
├── scripts/
│ ├── local-tunnel.ps1 # SSH tunnel to dev DB
│ ├── local-backend-docker.ps1 # Start Docker backend
│ ├── local-backend-dotnet.ps1 # Start native backend
│ └── local-frontend.ps1 # Start frontend dev server
├── .woodpecker/
│ └── deploy.yml # CI/CD pipeline
└── CLAUDE.md # This file
Environments
| Env | Frontend URL | API URL | DB |
|---|---|---|---|
| Prod | https://new.goodbrick.com.ua | https://new.goodbrick.com.ua/api/* | prod_db |
| Dev | https://dev.goodbrick.com.ua | https://dev.goodbrick.com.ua/api/* | dev_db |
| Local | http://localhost:3000 | http://localhost:5000/api/* | dev_db (via SSH tunnel) |
Docker Containers (Server)
| Container | Internal Port | Host Port | Network |
|---|---|---|---|
| gb-prod-frontend | 3000 | 127.0.0.1:3100 | app-network |
| gb-prod-backend | 5000 | 127.0.0.1:5100 | app-network |
| gb-dev-frontend | 3000 | 127.0.0.1:3200 | app-network |
| gb-dev-backend | 5000 | 127.0.0.1:5200 | app-network |
Routing (Caddy)
Path-based routing — один домен для фронта и API:
domain.com/*→ frontend container (port 3000)domain.com/api/*→ backend container (port 5000)
Backend получает запросы с prefix /api/ (Caddy использует handle, не handle_path).
Local Development
Quick Start (3 терминала)
Terminal 1 — SSH Tunnel (всегда нужен):
.\scripts\local-tunnel.ps1
Terminal 2 — Backend (выбрать один):
# Работа с фронтом — бэкенд в Docker:
.\scripts\local-backend-docker.ps1
# Работа с бэком — dotnet run с hot-reload:
.\scripts\local-backend-dotnet.ps1
Terminal 3 — Frontend:
.\scripts\local-frontend.ps1
Как это работает
- SSH Tunnel:
localhost:5433→ сервер31.131.18.254:5432(dev_db) - Backend: слушает на
localhost:5000, подключается к БД через туннель - Frontend:
npm run devна:3000, Next.js rewrites проксируют/api/*→localhost:5000 - Переключение режимов: Ctrl+C в терминале с бэком, запустить другой скрипт. Фронт перезапускать не нужно.
Конфигурация
backend/src/GBSite.Api/appsettings.Local.json— connection string к dev_db (gitignored).NET User Secrets— R2 credentials и другие секреты (хранятся вне репо)- Управление:
dotnet user-secrets set "R2:AccountId" "value"(из папкиbackend/src/GBSite.Api) - Просмотр:
dotnet user-secrets list - User secrets имеют приоритет выше appsettings*.json
- Управление:
frontend/.env.local—LOCAL_API_URLиINTERNAL_API_URLдля локального проксированияdeploy/docker-compose.local.yml— Docker backend сhost.docker.internal:5433
URLs
- Frontend: http://localhost:3000
- Backend API: http://localhost:5000/api/health
- DB: localhost:5433 (через SSH tunnel к dev_db)
Development (manual)
Frontend
cd frontend && npm install && npm run dev
Backend
cd backend && dotnet run --project src/GBSite.Api
Build locally
cd frontend && npm run build
cd backend && dotnet build
API Conventions
- All API routes start with
/api/ - Controllers use attribute routing:
[Route("api/[controller]")] - Health check:
GET /api/health— returns{ status, database, environment } - Health ping:
GET /api/health/ping— returns{ status: "pong" } - Upload:
POST /api/upload— multipart form, fields:file(required),path(optional folder prefix)
Frontend Conventions
- App Router (not Pages Router)
src/app/— pages and API routessrc/lib/— shared utilitiessrc/components/— React components (create when needed)- shadcn/ui components via
npx shadcn@latest add <component> - Server-side calls to backend use
INTERNAL_API_URLenv var - Client-side calls use relative paths (
/api/...) — Caddy proxies them on server, Next.js rewrites locally
Git & CI/CD
- Repo: https://git.goodbrick.com.ua/admin/gb-site
- Branches:
main→ prod deploy,dev→ dev deploy - CI: Woodpecker auto-deploys on push (SSH to server, git pull, docker compose build & up)
- Commit style: conventional, short descriptions in English
Server
- Host: 31.131.18.254
- SSH:
ssh deploy@31.131.18.254(key-based) - App location:
/srv/apps/gb-site(main),/srv/apps/gb-site-dev(dev worktree) - Caddy config:
/srv/proxy/Caddyfile - All services docs: see SERVER.md
Database
PostgreSQL доступен только внутри Docker network (container name: postgres).
Connection string format:
Host=postgres;Port=5432;Database={db};Username={user};Password={pass}
Configured via env var ConnectionStrings__Default in docker-compose files.
Locally via appsettings.Local.json with SSH tunnel (localhost:5433).
CDN & Image Storage
- Storage: Cloudflare R2 (S3-compatible)
- CDN domain: https://cdn.goodbrick.com.ua
- Bucket: goodbrick
- Frontend:
NEXT_PUBLIC_CDN_URLenv var,cdnUrl()helper insrc/lib/cdn.ts - Backend:
R2__*env vars (server), .NET User Secrets (local),R2StorageServicefor uploads - Upload endpoint:
POST /api/upload— multipart/form-data, max 10MB, images only (jpeg/png/webp/avif)
Folder Convention
products/<slug>/main.jpg— product photoscatalog/<slug>/cover.jpg— collection coverssite/<name>.jpg— site-wide images (hero, about, etc.)
Key Rules
- Never commit
.envfiles or secrets — on server: docker-compose env vars, locally: .NET User Secrets - Frontend standalone output (
output: "standalone"in next.config.ts) — required for Docker - Backend listens on port 5000 (
ASPNETCORE_URLS=http://+:5000) - All containers must be in
app-network(external Docker network) appsettings.Local.jsonis gitignored — local dev overrides only