# 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 (всегда нужен):** ```powershell .\scripts\local-tunnel.ps1 ``` **Terminal 2 — Backend (выбрать один):** ```powershell # Работа с фронтом — бэкенд в Docker: .\scripts\local-backend-docker.ps1 # Работа с бэком — dotnet run с hot-reload: .\scripts\local-backend-dotnet.ps1 ``` **Terminal 3 — Frontend:** ```powershell .\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) - `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 ```bash cd frontend && npm install && npm run dev ``` ### Backend ```bash cd backend && dotnet run --project src/GBSite.Api ``` ### Build locally ```bash 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 routes - `src/lib/` — shared utilities - `src/components/` — React components (create when needed) - shadcn/ui components via `npx shadcn@latest add ` - Server-side calls to backend use `INTERNAL_API_URL` env 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_URL` env var, `cdnUrl()` helper in `src/lib/cdn.ts` - **Backend:** `R2__*` env vars, `R2StorageService` for uploads - **Upload endpoint:** `POST /api/upload` — multipart/form-data, max 10MB, images only (jpeg/png/webp/avif) ### Folder Convention - `products//main.jpg` — product photos - `catalog//cover.jpg` — collection covers - `site/.jpg` — site-wide images (hero, about, etc.) ## Key Rules - Never commit `.env` files or secrets — credentials are in docker-compose env vars on server - 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.json` is gitignored — local dev overrides only