← Все проекты уровня 8
Уровень 8 · Пользователи и доступВариант A

Командные задачи

Командный REST-сервис с отдельными правами участника и менеджера на каждом защищённом маршруте.

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

Модель данных и назначение

Реализуйте командный сервис задач на Go с PostgreSQL, миграциями и параметризованным SQL без ORM. Пользователь имеет id, email, password_hash, role (member или manager), team_id, created_at и disabled_at. Команда имеет id и name. Задача хранит id, team_id, title, description, assignee_id, status (open, in_progress, done), due_at, created_by, timestamps. Назначенный пользователь всегда должен принадлежать той же команде; это правило проверяется не только в обработчике, но и при атомарном изменении данных. Пароль длиной от 12 до 128 Unicode-символов хранится только как стойкий хэш, пригодный для проверки паролей; секреты никогда не возвращаются и не логируются. Сессия действует ровно 24 часа.

API, проверки и эксплуатация

POST /api/auth/register принимает email, password, displayName и teamName и создаёт команду с первым пользователем-менеджером в одной транзакции. Email нормализуется регистром и trim, уникален; неверная длина пароля даёт 400. Повтор email даёт 409. POST /api/team/members доступен только manager, принимает email, password и displayName, создаёт member в собственной команде и отвечает 201; повтор email даёт 409. Поля role и teamId в теле запрещены. POST /api/auth/login выдаёт непрозрачный случайный session token, в БД хранится только его хэш; ответ содержит token и expiresAt ровно через 24 часа. POST /api/auth/logout отзывает текущую сессию и отвечает 204; повторное использование или истёкшая сессия даёт 401. Сессии ограничены сроком действия и проверяются для каждого защищённого запроса.

POST /api/tasks доступен члену и менеджеру: member может назначить задачу только себе, manager — любому активному участнику собственной команды; assignee обязателен и принадлежит этой команде, начальный status — open. GET /api/tasks поддерживает фильтры status, assigneeId, dueBefore и cursor, возвращает только задачи команды с limit 1–100, сортирует по updated_at DESC,id DESC. GET /api/tasks/{id}, PATCH /api/tasks/{id} и DELETE /api/tasks/{id} на каждом запросе проверяют сессию, команду и роль. Member может просматривать командные задачи, менять status только назначенной ему задачи и менять description только своей назначенной задачи; member не может назначать других и удалять. Manager может менять все поля и удалять задачи своей команды. Попытка доступа к чужой команде возвращает 404, недостаточная роль в собственной команде — 403. PATCH обновляет только допустимые поля и отклоняет неизвестные/пустые поля. Каждое состояние и ссылка assignee проверяются в одной транзакции. Ошибки 400/401/403/404/409 имеют единый безопасный JSON-формат. SQL-контекст имеет тайм-аут, отмена запроса прекращает работу. Подберите индексы по команде, статусу, назначенному и сортировке, исключите N+1. HTTP-сервер ограничивает тела и имеет конечные таймауты.

Структура программы

Код разделён на небольшие internal-пакеты: internal/httpapi содержит обработчики и DTO, internal/tasks — назначения и переходы задач, internal/access — роли и разрешения, internal/postgres — пользователей, сессии и SQL. main.go связывает приложение, запускает сервер и выполняет shutdown. Транспортные модели не входят в домен; правила доступа тестируются без HTTP и БД.

Критерии готовности

Ожидаемый результат

Поставка

  • Запускаемый Go REST API, PostgreSQL-миграции и README описывают регистрацию менеджера, добавление участников, 24-часовые сессии и права.
  • Детерминированные офлайн-тесты используют локальную временную базу и проверяют HTTP-статусы, роли и отсутствие секретов в ответах.

Приёмка

  • Регистрация создаёт первого manager; повтор нормализованного email возвращает 409.
  • Manager добавляет участника с кодом 201; переданные в теле role или teamId отклоняются, пароль за пределами 12–128 символов даёт 400.
  • Member не может назначить задачу другому, а manager может назначить её участнику своей команды.
  • Пользователь без сессии получает 401; logout немедленно отзывает токен, а сессия истекает через 24 часа.
  • Чужая команда скрывается ответом 404; password_hash и хэш токена не возвращаются и не логируются.
  • README показывает связи пакетов; правила ролей проверяются без HTTP/БД, SQL-доступ и сессии — отдельными сценариями.