Спроектируйте API для работы с пользователями и адресами с CRUD операциями и фильтрацией, опишите архитектуру и роуты
Что проверяют
Умеете ли вы проектировать ресурсы, а не набор методов над таблицами, и знаете ли обвязку промышленного сервиса на Spring: слои, контракт, валидацию, ошибки, постраничную выдачу.
Как отвечать
Начните с модели ресурсов. Пользователь это корневой ресурс, адрес почти всегда подчинённый, потому что сам по себе он не живёт.
POST /api/v1/users
GET /api/v1/users/{id}
PATCH /api/v1/users/{id}
DELETE /api/v1/users/{id}
GET /api/v1/users?city=...&page=0&size=20&sort=createdAt,desc
GET /api/v1/users/{id}/addresses
POST /api/v1/users/{id}/addressesСлои называйте с ответственностью: контроллер принимает и отдаёт объекты передачи данных, сервис держит бизнес-логику и границу транзакции, репозиторий это Spring Data JPA. Сущность наружу не отдаётся: ленивые связи вылезут в сериализацию, а переименование колонки станет ломающим изменением контракта.
Что обязательно назвать: валидация входа с ответом четыреста и единым телом ошибки через общий обработчик; код двести один и заголовок Location на создание; код двести четыре на удаление; разница между полным обновлением и частичным; постраничная выдача на любых списках через Pageable; фильтрация через Specification или типизированный построитель запросов, а не склейкой строк; версия в пути и описание в OpenAPI.
Где спотыкаются
Отдают сущность вместо объекта передачи данных. Дальше либо исключение ленивой инициализации, либо бесконечная рекурсия на двусторонней связи, которую лечат аннотациями сериализатора вместо нормального контракта.
Возвращают список целиком, без ограничения размера. На тестовых данных это незаметно, на проде первый же запрос вытягивает всю таблицу и кладёт сервис.
Не продумывают ошибки. Любое исключение превращается в пятисотку без тела, а иногда наоборот: ответ двести с полем об ошибке внутри. Клиенту в обоих случаях нечего разбирать, и обработка ошибок расползается по фронтенду.