Модель данных и назначение
Реализуйте командный сервис задач на 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 и БД.