New, fully separate app module "العلاقات العامة والمراسم / Public
Relations and Protocol". Does not touch executive-meetings; all new
tables are prefixed protocol_ and are additive-only, routes under
/protocol.
Includes:
- 6 protocol_ tables (rooms, room bookings, external meetings, gifts,
gift issues, audit log) in lib/db.
- API routes + role-scoped middleware (protocol_super_admin, pr_manager,
officer, requester, viewer) with requireProtocolAccess gating.
- Room-booking conflict prevention (overlap rule newStart<existingEnd
AND newEnd>existingStart vs pending/approved) with AR error message.
- Gifts/shields (دروع) registry + issuance with stock tracking.
- Bilingual AR/EN frontend page (tabs + dialogs) at /protocol, app tile,
i18n keys, and seed data (roles, permission, default rooms).
Concurrency/security hardening from code review:
- All role guards now validate users.isActive (inactive-user bypass fix).
- Per-room SELECT ... FOR UPDATE lock serializes booking check-then-write.
- Approve paths re-read inside the transaction and use state-conditional
updates (WHERE ... AND status='pending' RETURNING).
- Gift issuance claims the issue conditionally, then does an atomic
conditional stock decrement; failure rolls back the claim.
Verified: drizzle push (6 tables), seed, frontend + api-server typecheck
(only pre-existing errors in untouched files), unauth gating returns 401,
conflict predicate confirmed. Architect review PASS.