Demo classifieds marketplace inspired by popular C2C listing platforms. Multi-service infrastructure with Traefik, a Go API, and a frontend.
This project is not affiliated with Avito, OLX, or any other classifieds platform. All trademarks belong to their respective owners.
App under active development. There is no sensitive data, so feel free to change old migrations and drop the database at any time.
- Tech Stack
- Project Structure
- Architecture
- DDD: Ubiquitous Language
- Quick Start
- Services
- Database
- Development
- Production
- License
Backend
- Go 1.26, chi router, CQRS-lite architecture (read/write separation)
- PostgreSQL via pgx, goose migrations
- JWT auth (golang-jwt), request validation via validator
- WebSocket chat (coder/websocket)
- S3-compatible object storage via AWS SDK v2
- Transactional email via Resend, SMTP fallback
- YooKassa payments integration
- Swagger/OpenAPI docs via swaggo
- i18n:
ru+enthroughout the API and email templates
Frontend (admin panel)
- Alpine.js, Tailwind CSS, Vite
- FilePond for uploads, Tabulator for data tables
- E2E tests with Playwright
Infrastructure
- Traefik v3 reverse proxy, Docker Compose (dev/prod overrides)
- Dozzle (logs), Netdata (metrics), Mailpit (dev SMTP)
- GitHub Actions CI: format, lint, build, test, Swagger drift check
/
├── compose.yml # Base infrastructure (Traefik, Frontend, DB, etc)
├── compose.override.dev.yml # Dev overrides (local domains, hot-reload)
├── compose.override.prod.yml # Prod overrides (HTTPS, Let's Encrypt)
├── .env # Dev environment (auto-loaded)
├── Makefile # Commands
├── fe-admin/ # Admin panel frontend
└── api-go/ # Go API application
flowchart TB
client["Internet / Local Browser"]
traefik["Traefik - reverse proxy"]
client --> traefik
traefik --> feadmin["fe-admin - Nginx SPA"]
traefik --> api["api-go - Go HTTP API"]
traefik --> ops["Ops tools - Dozzle / Netdata"]
feadmin -- "HTTP /api/v1" --> api
api --> handlers["API handlers - auth, items, chat, upload, payments"]
handlers --> app["Application layer - services and queries"]
app --> pg["PostgreSQL - migrations, users, items, chat, payments"]
app --> storage["Object storage - item photos, avatars, chat attachments"]
app --> email["Email delivery - Mailpit in dev, Resend in prod"]
One term - one concept. The team uses the same names in speech, documentation, and code.
- Entities are named after their domain meaning, not their UI, retrieval method, or technical implementation.
- Giving different names to the same concept is forbidden.
- Related but distinct concepts are separated explicitly: for example, promotion payment, withdrawal, and balance are different terms.
A new term is recorded in the glossary first, then used in the code.
# setup /etc/hosts
# setup Dozzle creds
# setup HTTP_BASIC_AUTH_HASH in .env (htpasswd -nbB admin 'pass')
# Start dev
make dev- http://admin.avi.test # Admin panel (fe-admin)
- http://api.avi.test # API
- http://api.avi.test/swagger # API docs (Swagger UI)
- http://logs.avi.test # Dozzle (logs)
- http://metrics.avi.test # Netdata (metrics, basic auth)
- Traefik v3.6 - Reverse proxy
- API (Go) - Backend API
- Frontend NextJS
- Frontend Admin panel - SPA
- PostgreSQL
- Dozzle - Log viewer
- Netdata - Metrics monitoring
- Mailpit - Test SMTP
- Resend - Emails on prod
make dev # Start (dev mode)
make down # Stop
make logs # View logs
make sh # Shell into APImake prod # Switch to prod modeRequires:
.envwith prod real values- DNS configured for api.avi.app and avi.app
See Readme.md's in individual services for details.
Software source code and software components are licensed for non-commercial use only under the PolyForm Noncommercial License 1.0.0. Commercial use requires prior written permission from the copyright holder.
Any use, copying, distribution, modification, or incorporation of this project or its components must preserve the required attribution notices in NOTICE.
Documentation and non-code assets are licensed for non-commercial use with attribution under Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0), unless a file states otherwise.
Reference copy of the PolyForm license: https://raw.githubusercontent.com/polyformproject/polyform-licenses/1.0.0/PolyForm-Noncommercial-1.0.0.md
