Skip to content

ex0rcist/gophermart

Repository files navigation

Gophermart

Учебный проект в рамках курса GO-advanced Яндекс.Практикума. Состоит из:

  • сервиса расчета и аккумуляции бонусных баллов системы лояльности
  • blackbox-сервиса accrual

Разработка и тестирование

Для получения полного списка доступных команд выполните:

make help

Миграции

Сервер автоматически применит новые миграции при запуске.

Для работы с миграциями вручную можно установить утилиту golang-migrate:

go install -tags "postgres" github.com/golang-migrate/migrate/v4/cmd/migrate@latest

# добавление новой миграции:
migrate create -ext sql -dir ./internal/storage/migrations -seq имя_миграции

# применить миграции:
migrate -database ${DATABASE_DSN} -path ./internal/storage/migrations up

# откатить миграции:
migrate -database ${DATABASE_DSN} -path ./internal/storage/migrations down -all

Запуск сервера

Сервер отвечает за взаимодействие с пользователем (получение списка накоплений, запрос расходования накоплений и т.п.)

./cmd/gophermart/gophermart -d${DATABASE_DSN}

Опции командной строки

Имеют приоритет перед конфигурационным файлом. Для вывода списка доступных опций и их значений по умолчанию выполните команду:

./cmd/gophermart/gophermart --help
-r, --accrual-address string      address:port for accrual service (default "0.0.0.0:8181")
-d, --database string             PostgreSQL database DSN
-a, --gophermart-address string   address:port for HTTP API requests (default "0.0.0.0:8080")
-k, --secret string               a key to sign data; will be generated automatically if empty

Переменные окружения сервера

Имеют приоритет перед опциями командной строки.

# Адрес и порт для http-api:
export RUN_ADDRESS=0.0.0.0:8080

# Адрес и порт внешней системы начисления баллов:
export ACCRUAL_SYSTEM_ADDRESS=0.0.0.0:8080

# DSN для подключения к базе данных (postgres-only):
export DATABASE_URI=300

# Ключ для подписывания запросов, по умолчанию будет сгенерирован автоматически:
export APP_KEY=

Техническое задание

Накопительная система лояльности «Гофермарт»

Общие требования

Система представляет собой HTTP API со следующими требованиями к бизнес-логике:

  • регистрация, аутентификация и авторизация пользователей;
  • приём номеров заказов от зарегистрированных пользователей;
  • учёт и ведение списка переданных номеров заказов зарегистрированного пользователя;
  • учёт и ведение накопительного счёта зарегистрированного пользователя;
  • проверка принятых номеров заказов через систему расчёта баллов лояльности;
  • начисление за каждый подходящий номер заказа положенного вознаграждения на счёт лояльности пользователя.

Абстрактная схема взаимодействия с системой

  1. Пользователь регистрируется в системе лояльности «Гофермарт».
  2. Пользователь совершает покупку в интернет-магазине «Гофермарт».
  3. Заказ попадает в систему расчёта баллов лояльности.
  4. Пользователь передаёт номер совершённого заказа в систему лояльности.
  5. Система связывает номер заказа с пользователем и сверяет номер с системой расчёта баллов лояльности.
  6. При наличии положительного расчёта баллов лояльности производится начисление баллов лояльности на счёт пользователя.
  7. Пользователь списывает доступные баллы лояльности для частичной или полной оплаты последующих заказов в интернет-магазине «Гофермарт».

Примечания:

  • пункт 2 представлен как гипотетический и не реализован в данном проекте;
  • пункт 3 реализован в системе расчёта баллов лояльности и не реализован в данном проекте;

Система расчета баллов лояльности

Система расчета баллов лояльности является внешним сервисом в доверенном контуре. Он работает по принципу чёрного ящика и недоступен для инспекции внешними клиентами. Система рассчитывает положенные баллы лояльности за совершённый заказ по сложным алгоритмам, которые могут меняться в любой момент времени.

Внешнему потребителю доступна только информация о количестве положенных за конкретный заказ баллов лояльности. Причины наличия или отсутствия начислений внешнему потребителю неизвестны.

Протокол взаимодействия с сервисом базы будет предоставлен в конце.

Сводное HTTP API

Накопительная система лояльности «Гофермарт» должна предоставлять следующие HTTP-хендлеры:

  • POST /api/user/register — регистрация пользователя;
  • POST /api/user/login — аутентификация пользователя;
  • POST /api/user/orders — загрузка пользователем номера заказа для расчёта;
  • GET /api/user/orders — получение списка загруженных пользователем номеров заказов, статусов их обработки и информации о начислениях;
  • GET /api/user/balance — получение текущего баланса счёта баллов лояльности пользователя;
  • POST /api/user/balance/withdraw — запрос на списание баллов с накопительного счёта в счёт оплаты нового заказа;
  • GET /api/user/withdrawals — получение информации о выводе средств с накопительного счёта пользователем.

Регистрация пользователя

Хендлер: POST /api/user/register.

Регистрация производится по паре логин/пароль. Каждый логин должен быть уникальным.

Формат запроса:

POST /api/user/register HTTP/1.1
Content-Type: application/json
...

{
	"login": "<login>",
	"password": "<password>"
}

Возможные коды ответа:

  • 200 — пользователь успешно зарегистрирован и аутентифицирован;
  • 400 — неверный формат запроса;
  • 409 — логин уже занят;
  • 500 — внутренняя ошибка сервера.

Аутентификация пользователя

Хендлер: POST /api/user/login.

Аутентификация производится по паре логин/пароль.

Формат запроса:

POST /api/user/login HTTP/1.1
Content-Type: application/json
...

{
	"login": "<login>",
	"password": "<password>"
}

Возможные коды ответа:

  • 200 — пользователь успешно аутентифицирован;
  • 400 — неверный формат запроса;
  • 401 — неверная пара логин/пароль;
  • 500 — внутренняя ошибка сервера.

Загрузка номера заказа

Хендлер: POST /api/user/orders.

Хендлер доступен только аутентифицированным пользователям. Номером заказа является последовательность цифр произвольной длины. Номер заказа проверяется на корректность ввода с помощью алгоритма Луна

Формат запроса:

POST /api/user/orders HTTP/1.1
Content-Type: text/plain
...

12345678903

Возможные коды ответа:

  • 200 — номер заказа уже был загружен этим пользователем;
  • 202 — новый номер заказа принят в обработку;
  • 400 — неверный формат запроса;
  • 401 — пользователь не аутентифицирован;
  • 409 — номер заказа уже был загружен другим пользователем;
  • 422 — неверный формат номера заказа;
  • 500 — внутренняя ошибка сервера.

Получение списка загруженных номеров заказов

Хендлер: GET /api/user/orders.

Хендлер доступен только авторизованному пользователю. Номера заказа в выдаче должны быть отсортированы по времени загрузки от самых новых к самым старым. Формат даты — RFC3339.

Доступные статусы обработки расчётов:

  • NEW — заказ загружен в систему, но не попал в обработку;
  • PROCESSING — вознаграждение за заказ рассчитывается;
  • INVALID — система расчёта вознаграждений отказала в расчёте;
  • PROCESSED — данные по заказу проверены и информация о расчёте успешно получена.

Формат запроса:

GET /api/user/orders HTTP/1.1
Content-Length: 0

Возможные коды ответа:

  • 200 — успешная обработка запроса.

    Формат ответа:

    200 OK HTTP/1.1
    Content-Type: application/json
    ...
    
    [
    	{
            "number": "9278923470",
            "status": "PROCESSED",
            "accrual": 500,
            "uploaded_at": "2020-12-10T15:15:45+03:00"
        },
        {
            "number": "12345678903",
            "status": "PROCESSING",
            "uploaded_at": "2020-12-10T15:12:01+03:00"
        },
        {
            "number": "346436439",
            "status": "INVALID",
            "uploaded_at": "2020-12-09T16:09:53+03:00"
        }
    ]
    
  • 204 — нет данных для ответа.

  • 401 — пользователь не авторизован.

  • 500 — внутренняя ошибка сервера.


Получение текущего баланса пользователя

Хендлер: GET /api/user/balance.

Хендлер доступен только авторизованному пользователю. В ответе должны содержаться данные о текущей сумме баллов лояльности, а также сумме использованных за весь период регистрации баллов.

Формат запроса:

GET /api/user/balance HTTP/1.1
Content-Length: 0

Возможные коды ответа:

  • 200 — успешная обработка запроса.

    Формат ответа:

    200 OK HTTP/1.1
    Content-Type: application/json
    ...
    
    {
    	"current": 500.5,
    	"withdrawn": 42
    }
    
  • 401 — пользователь не авторизован.

  • 500 — внутренняя ошибка сервера.


Запрос на списание средств

Хендлер: POST /api/user/balance/withdraw

Хендлер доступен только авторизованному пользователю. Номер заказа представляет собой гипотетический номер нового заказа пользователя в счет оплаты которого списываются баллы.

Примечание: для успешного списания достаточно успешной регистрации запроса, никаких внешних систем начисления не предусмотрено и не требуется реализовывать.

Формат запроса:

POST /api/user/balance/withdraw HTTP/1.1
Content-Type: application/json

{
	"order": "2377225624",
    "sum": 751
}

Здесь order — номер заказа, а sum — сумма баллов к списанию в счёт оплаты.

Возможные коды ответа:

  • 200 — успешная обработка запроса;
  • 401 — пользователь не авторизован;
  • 402 — на счету недостаточно средств;
  • 422 — неверный номер заказа;
  • 500 — внутренняя ошибка сервера.

Получение информации о выводе средств

Хендлер: GET /api/user/withdrawals.

Хендлер доступен только авторизованному пользователю. Факты выводов в выдаче должны быть отсортированы по времени вывода от самых новых к самым старым. Формат даты — RFC3339.

Формат запроса:

GET /api/user/withdrawals HTTP/1.1
Content-Length: 0

Возможные коды ответа:

  • 200 — успешная обработка запроса.

    Формат ответа:

    200 OK HTTP/1.1
    Content-Type: application/json
    ...
    
    [
        {
            "order": "2377225624",
            "sum": 500,
            "processed_at": "2020-12-09T16:09:57+03:00"
        }
    ]
    
  • 204 - нет ни одного списания.

  • 401 — пользователь не авторизован.

  • 500 — внутренняя ошибка сервера.


Взаимодействие с системой расчёта начислений баллов лояльности

Для взаимодействия с системой доступен один хендлер:

  • GET /api/orders/{number} — получение информации о расчёте начислений баллов лояльности.

Формат запроса:

GET /api/orders/{number} HTTP/1.1
Content-Length: 0

Возможные коды ответа:

  • 200 — успешная обработка запроса.

    Формат ответа:

    200 OK HTTP/1.1
    Content-Type: application/json
    ...
    
    {
        "order": "<number>",
        "status": "PROCESSED",
        "accrual": 500
    }
    

    Поля объекта ответа:

    • order — номер заказа;

    • status — статус расчёта начисления:

      • REGISTERED — заказ зарегистрирован, но не начисление не рассчитано;
      • INVALID — заказ не принят к расчёту, и вознаграждение не будет начислено;
      • PROCESSING — расчёт начисления в процессе;
      • PROCESSED — расчёт начисления окончен;
    • accrual — рассчитанные баллы к начислению, при отсутствии начисления — поле отсутствует в ответе.

  • 204 - заказ не зарегистрирован в системе расчета.

  • 429 — превышено количество запросов к сервису.

    Формат ответа:

    429 Too Many Requests HTTP/1.1
    Content-Type: text/plain
    Retry-After: 60
    
    No more than N requests per minute allowed
    
  • 500 — внутренняя ошибка сервера.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published