feat: add hotel_admin (Системный администратор) and technician roles + protect hotel owner from deletion

- Migration 035: extend role constraint to include hotel_admin and technician; migrate existing manager users to hotel_admin
- auth.ts: registration now assigns hotel_admin (not manager) to hotel owner
- seed.ts: demo user manager@grand-palace.ru seeded as hotel_admin
- types.ts: expand JwtPayload role union with all roles
- users.ts: hotel_admin included in access checks; role creation/edit/delete rules enforced; hotel_admin users are undeletable and uneditable (non-super_admin); role cannot be set to hotel_admin via PATCH
- rooms.ts / channels.ts: hotel_admin added to write-access checks
- UsersPage.tsx: hotel_admin and technician added to StaffRole, ROLE_META, DEFAULT_POSITIONS, mapRole, backendRoleMap, INITIAL_ROLE_PERMISSIONS; delete button hidden for hotel_admin; role selector locked for hotel_admin users; hotel_admin excluded from new-user role selector

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-26 00:39:48 +03:00
parent 943b97c200
commit d5267335a0
8 changed files with 128 additions and 53 deletions

View File

@@ -60,7 +60,7 @@ const rooms: FastifyPluginAsync = async (fastify) => {
'/api/hotels/:slug/rooms',
{ onRequest: [fastify.authenticate] },
async (request, reply) => {
if (!['manager', 'super_admin'].includes(request.user.role)) {
if (!['manager', 'hotel_admin', 'super_admin'].includes(request.user.role)) {
return reply.code(403).send({ error: 'Forbidden' })
}
const { slug } = request.params
@@ -127,7 +127,7 @@ const rooms: FastifyPluginAsync = async (fastify) => {
'/api/hotels/:slug/rooms/:id',
{ onRequest: [fastify.authenticate] },
async (request, reply) => {
if (!['manager', 'super_admin'].includes(request.user.role)) {
if (!['manager', 'hotel_admin', 'super_admin'].includes(request.user.role)) {
return reply.code(403).send({ error: 'Forbidden' })
}
const { slug, id } = request.params
@@ -179,7 +179,7 @@ const rooms: FastifyPluginAsync = async (fastify) => {
'/api/hotels/:slug/rooms/:id',
{ onRequest: [fastify.authenticate] },
async (request, reply) => {
if (!['manager', 'super_admin'].includes(request.user.role)) {
if (!['manager', 'hotel_admin', 'super_admin'].includes(request.user.role)) {
return reply.code(403).send({ error: 'Forbidden' })
}
const { slug, id } = request.params