diff --git a/README.md b/README.md index fc800c5..37ccced 100644 --- a/README.md +++ b/README.md @@ -1,119 +1,151 @@ -# Шаблон репозитория для реализации проекта на курсе Route 256 +# Marketplace Microservices Platform - Поздравляем с зачислением на курс "Продвинутая разработка микросервисов на Go"! Надеемся, что процесс обучения будет -увлекательным, а полученные знания пригодятся в работе! +A **Go-based microservices marketplace platform** built step-by-step across modules. It showcases HTTP & gRPC APIs, databases, concurrency, messaging, and observability. - В рамках курса вам предстоит разработать проект– копию Озона в миниатюре. Не нужно пугаться, ведь на этом пути вас -будет сопровождать команда преподавателей и тьюторов. Работа над проектом будет разбита из 8 модулей, каждому из -которых, посвящены две лекции и одно практическое занятие. Действующие инженеры Озона поделятся своим опытом и обратят -внимание на важные аспекты, которые неизбежно возникают при разработке высоконагруженных распределенных систем. По -окончании каждого модуля будет предложено реализовать ту или иную часть из курсового проекта, имеющую непосредственное -отношение к теме модуля. - -Желаем успехов в прохождении курса! +## Services -# Работа над курсовым проектом +- **Cart** — user shopping cart (HTTP). +- **LOMS** — Logistics & Order Management (gRPC + HTTP gateway): orders, stock, reservation. +- **Comments** — item comments (HTTP). +- **Notifier** — Kafka consumer that processes order events. -## Инициализация проекта +Infra: PostgreSQL, Kafka, Docker Compose, Prometheus, Grafana, OpenTelemetry. -Для работы над курсовым проектом необходимо выполнить инициализацию репозитория: +--- -1. Открыть репозиторий https://gitlab.ozon.dev/go/classroom-18/students/homework-draft (вы уже в нем); -2. Создать копию данного репозитория https://gitlab.ozon.dev/go/classroom-18/students/homework-draft (форк проекта в свой - приватный репозиторий (см. рис. 1)); -3. Разорвать связь с шаблонным репозиторием, для этого в GitLab необходимо выполнить: Settings › Advanced › Remove - fork relationship (см. рис. 2 и 3); -4. Добавить тьютора в Members проекта. Для этого: Project information › Members › Invite member, пригласить своего - тьютора с правами Maintainer (см. рис. 4, 5 и 6). +## Features by Module - -Обрати внимание! -Если не разорвать связь с проектом, можно случайно отправить изменения в общий проект с шаблоном курсового проекта! - +1. **Go Basics (Cart)** + - HTTP API: add/delete/clear/list cart. + - Logging middleware, request validation, client retries. + - In-memory repository. -![Рис. 1. Форк проекта](./docs/readme/img/fork-project.png) -Рис. 1. Создаем копию проекта +2. **Testing in Go** + - Unit tests for use cases & repository (minimock). + - Coverage target ≥ 60%. + - Benchmarks + e2e tests (selected handlers). -![Рис. 2. Продвинутые настройки](./docs/readme/img/advanced-settings.png) -Рис. 2. Переходим в продвинутые настройки репозитория +3. **Inter-service Communication (LOMS)** + - gRPC API: `OrderCreate`, `OrderInfo`, `OrderPay`, `OrderCancel`, `StocksInfo`. + - Cart → LOMS via gRPC (checkout & stock checks). + - proto-gen-validate interceptor, HTTP gateway, Swagger UI. -![Рис. 3. Разрыв связи](./docs/readme/img/unlink-fork.png) -Рис. 3. Разрываем связь в шаблонным проектом +4. **Databases** + - LOMS uses PostgreSQL with migrations. + - Transactional order creation. + - SQLC for type-safe queries. -![Рис. 4. Настройки участников проекта](./docs/readme/img/project-members.png) -Рис. 4. Настройки участников проекта +5. **Concurrency** + - Parallel product lookups with a custom `errgroup`. + - Client-side RPS limiting (10 RPS), context cancellation. + - Mutex-protected in-memory stores. -![Рис. 5. Добавить новых участников](./docs/readme/img/invite-member.png) -Рис. 5. Добавить новых участников +6. **Messaging & Outbox** *(extended)* + - Kafka outbox for order domain events (see `loms/internal/infra/messaging/kafka_outbox`). + - Notifier consumes and processes events (`notifier/internal/infra/messaging/kafka`). -![Рис. 6. Добавление тьютора с ролью Maintainer](./docs/readme/img/make-tutor-a-maintainer.png) -Рис. 6. Добавление тьютора с ролью Maintainer +7. **Observability** *(extended)* + - OpenTelemetry tracing, Prometheus metrics, Grafana dashboards. + - gRPC/HTTP middleware for logging/metrics/tracing. +8. **Production-Ready Enhancements** *(extended)* + - Dockerized services & Makefile automation. + - Graceful shutdowns, race/leak checks. + - CI-friendly lint/tests/migrations. + - End-to-end integration tests. -## Выполнение домашнего задания: +--- -1. В своём форке проекта необходимо создать ветку от master под выполняемое задание. Ветку **необходимо (MUST)** назвать - hw-N, где N– номер модуля, к которому относится выполняемое задание; -2. Выполнить задание; -3. Создать мерж-реквест ветки с решением в master в своём форке проекта; -4. Уведомить тьютора об отправке решения на проверку и поделиться ссылкой на мерж-реквест в Telegram; -5. После проверки задания тьютором он может оставить комментарии к решению. Если требующие исправления замечания - отсутствуют, тьютор засчитывает решение, оставляя отметку (approve) на мерж-реквесте. По итогам проверки тьютор - проставляет оценку за работу в таблице прогресса; -6. Необходимо устранить все обязательные замечания и добиться успешного прохождения проверки тьютором; -7. После того как решение зачтено тьютором, и работа над ним со стороны студента завершена, решение необходимо вмержить - в ветку master. +## Tech Stack -## Формат названий на курсе Go на примере домашнего задания №1 (HW1): +Go 1.23 • HTTP • gRPC + gRPC-Gateway • Swagger • PostgreSQL • SQLC • Kafka • OpenTelemetry • Prometheus • Grafana • Docker & Docker Compose • minimock -| Формат наименования | Пример | -|--------------------|------------------------------| -| Для ветки | hw-1 | -| Для коммита | [hw-1] Свободный комментарий | -| Для мерж-реквеста | [hw-1] Свободный комментарий | +--- -## Прохождение автоматизированных проверок - - На текущем потоке мы в пилотном режиме запускаем систему автоматизированной проверки решений. Это не означает, что -тьюторы будут проверять решения менее тщательно, напротив– мы хотим освободить тьюторов от рутинных проверок и -помочь им фокусироваться на проверке других важных аспектов реализации. Это требует от вас внимательнее относится -к именованию веток, потому что для запуска проверок необходимо чтобы ветки удовлетворяли указанному шаблону `hw-N`. - - Поскольку это пилотный запуск тестирующей системы, возможно возникновение проблем в ее работе, в том числе ложно -негативных срабатываний, **успешное прохождения решением всех автоматизированных проверок не является обязательным**. -Тем не менее постарайтесь, чтобы ваше решение проходило столько проверок, на сколько это возможно. Уделите внимание -проверкам кода (линтеру golangci-lint). Все это поможет избежать лишних замечаний в мерж-реквестах, которые непременно -оставит тьютор, и позволит сдать задание быстрее и за меньшее количество проверок. - - Блюдите культуру и гигиену работы с git, постарайтесь не пушить бессодержательные коммиты в систему контроля версий. -**Количество коммитов не оценивается**. Большое количество коммитов вызывает запуск автоматизированных проверок, а -ввиду ограниченности ресурсов это может создать очередь в их прохождении. Более того, большое количество коммитов в -репозитории, где одновременно работает много разработчиков (как обычно и бывает на настоящем крупном проекте), может -затруднить слияние и разрешение конфликтов, сложнее понять состояние репозитория и ориентироваться в истории. Хорошей -практикой считается выполнение объединения коммитов в один (squash) перед созданием мерж-реквеста и аналогичное -объединение коммитов с исправлениями в один перед повторной отправкой тьютору на повторную. Таким образом количество -коммитов в ветке будет соответствовать количеству итераций проверки. Мы не считаем количество коммитов и не оцениваем -работу по этому признаку. Сказанное выше является рекомендацией, но не требованием. - -## Чтение файла конфигурации -В вашем решинии каждый из сервисов должен (MUST) использовать переменную окружения `CONFIG_FILE` в которой указан ПУТЬ -до файла конфигурации. - -[Пример](cart/configs/values_ci.yaml) такого файла для сервиса `cart`, который используется в CI/CD пайплайне -(НЕ МОДИФИЦИРОВАТЬ). - -Файлы конфигурации для локального запуска так-же [находятся в репозитории](cart/configs/values_local.yaml). - -## Troubleshooting -1. Чтобы запустить product-service локально требуется выполнить команду +## Project Structure (high-level) ``` -docker login gitlab-registry.ozon.dev +/cart # HTTP cart service, clients to LOMS & product-service, tests +/loms # gRPC LOMS service (orders, stocks), DB layer (sqlc), gateway, swagger +/comments # Comments service (HTTP, Postgres repository) +/notifier # Kafka consumer (order events) +/prometheus # Prometheus config +/grafana_data # Local Grafana storage +/docker-compose.yaml +/Makefile # build/run/test targets ``` - логин и пароль такие-же, как для доступа к https://gitlab.ozon.dev/ -2. Если при прохождении джобы с тестами вы получаете ошибку +(See service-specific folders for `configs`, `db/migrations`, and `Makefile` targets.) + +--- + +## Run Locally + +```bash +make run-all ``` -ERROR: Job failed: failed to pull image "gitlab-registry.ozon.dev/go/...." with specified policies [always]: Error response from daemon: pull access denied for gitlab-registry.ozon.dev/go/...., repository does not exist or may require 'docker login': denied: requested access to the resource is denied -``` -напишите об этом тьютору, чтобы он сделал необходимые настройки. После подтверждения от тьютора, что работы проведены - просто перезапустите пайплайн + +Starts services (`cart`, `loms`, `comments`, `notifier`) plus dependencies (PostgreSQL, Kafka), applies migrations, and exposes UIs. + +**Default ports** +- Cart HTTP: `http://localhost:8080` +- LOMS gRPC-Gateway & Swagger: `http://localhost:8081` +- Product service (mock): `http://localhost:8082/docs` +- Prometheus: `http://localhost:9090` +- Grafana: `http://localhost:3000` + +> Auth to product-service via `X-API-KEY: testToken`. + +--- + +## Key APIs + +### Cart (HTTP) +- `POST /user/{user_id}/cart/{sku}` — add item (validates via product-service; checks stock via LOMS). +- `DELETE /user/{user_id}/cart/{sku}` — remove item. +- `DELETE /user/{user_id}/cart` — clear cart. +- `GET /user/{user_id}/cart` — list cart (sorted by SKU). +- `POST /checkout/{user_id}` — create order in LOMS from cart. + +### LOMS (gRPC + HTTP Gateway) +- `OrderCreate`, `OrderInfo`, `OrderPay`, `OrderCancel` +- `StocksInfo` — available to buy (total − reserved) + +Swagger (when enabled): +- LOMS: `http://localhost:8081/docs` +- Product mock: `http://localhost:8082/docs` + +--- + +## Happy Path (Example Flow) + +1. `POST /user/{user_id}/cart/{sku}` — Add item to cart (checks product exists and stock is sufficient). +2. `GET /user/{user_id}/cart` — Verify cart contents. +3. `POST /checkout/{user_id}` — Create an order in LOMS. +4. `POST /order/pay` (LOMS) — Pay the order with body `{ "orderId": }`. +5. Optionally, `POST /order/cancel` (LOMS) before payment to cancel the order. + +--- + +## Development + +**Makefile highlights** +- `make run-all` — build & run full stack +- `make test` — unit tests (minimock) +- `make lint` — lint (incl. cyclomatic/cognitive complexity) +- `make cover` — coverage report +- `make gen` — proto & SQLC codegen + +**Testing** +- Unit tests for use cases & repositories +- e2e tests for selected handlers +- Benchmarks for in-memory storage +- Race detector & goroutine leak checks (where applicable) + +--- + +## Observability + +- Tracing via OpenTelemetry (`internal/infra/tracing`) +- Metrics via Prometheus (`/prometheus/prometheus.yml`) +- Dashboards in Grafana (`/grafana_data`)