Skip to content

Admin-controlled lock on entrance and massif sensitivity  #1684

Description

@ClemRz

Requirements Document

Introduction

Add an isSensitiveLocked boolean field to both entrances and massifs in the GrottoCenter API. When an administrator locks the sensitivity of an entrance or massif, only administrators can subsequently change its isSensitive value. The lock is a deliberate, symmetric admin action — it can freeze sensitivity in either state (on or off). Additionally, massif cascade operations (marking a massif as sensitive) must skip entrances whose sensitivity is locked.

Glossary

  • TEntrance: The Waterline model (api/models/TEntrance.js) representing a cave entrance in the t_entrance table.
  • TMassif: The Waterline model (api/models/TMassif.js) representing a massif in the t_massif table.
  • EntranceService: The service (api/services/EntranceService.js) containing entrance business logic including data coercion and creation.
  • MassifService: The service (api/services/MassifService.js) containing massif business logic including sensitivity cascade propagation.
  • mark-sensitive: The controller (api/controllers/v1/massif/mark-sensitive.js) that sets a massif as sensitive and cascades to child entrances.
  • unmark-sensitive: The controller (api/controllers/v1/massif/unmark-sensitive.js) that removes sensitivity from a massif (no cascade to entrances).
  • preview-sensitive: The controller (api/controllers/v1/massif/preview-sensitive.js) that returns a count of entrances that would be affected by a sensitivity cascade.
  • isSensitiveLocked: A boolean column on t_entrance and t_massif. When true, only administrators can change the isSensitive value of that entity. Defaults to false (unlocked).
  • Cascade_Operation: The process by which marking a massif as sensitive propagates isSensitive = true to all non-sensitive entrances geographically within the massif polygon.
  • Administrator: A user whose JWT token groups include the ADMINISTRATOR role as checked by RightService.hasGroup.

Requirements

Requirement 1: Add isSensitiveLocked column to entrance and massif tables

User Story: As a database administrator, I want is_sensitive_locked columns on t_entrance and t_massif, so that the lock state is persisted and queryable.

Acceptance Criteria

  1. THE t_entrance table SHALL have a column is_sensitive_locked of type boolean, NOT NULL, with a default value of false.
  2. THE t_massif table SHALL have a column is_sensitive_locked of type boolean, NOT NULL, with a default value of false.
  3. THE migration script SHALL be idempotent (using IF NOT EXISTS or equivalent safe patterns).
  4. THE TEntrance Waterline model SHALL include an isSensitiveLocked attribute mapped to the is_sensitive_locked column with type: 'boolean', allowNull: false, defaultsTo: false.
  5. THE TMassif Waterline model SHALL include an isSensitiveLocked attribute mapped to the is_sensitive_locked column with type: 'boolean', allowNull: false, defaultsTo: false.

Requirement 2: Return isSensitiveLocked in API responses

User Story: As a frontend developer, I want the API to include isSensitiveLocked in entrance and massif responses, so that the UI can render lock state indicators and enforce client-side logic.

Acceptance Criteria

  1. THE toEntrance converter SHALL include isSensitiveLocked in its output, sourced from source.isSensitiveLocked or source.is_sensitive_locked.
  2. THE toMassif converter SHALL include isSensitiveLocked in its output, sourced from source.isSensitiveLocked.
  3. WHEN isSensitiveLocked is null or undefined on the source object (e.g., old data before migration), THE converters SHALL default the output value to false.
  4. THE GET /api/v1/entrances/:id response SHALL include the isSensitiveLocked field.
  5. THE GET /api/v1/massifs/:id response (via toMassif) SHALL include the isSensitiveLocked field.

Requirement 3: Entrance update respects lock state

User Story: As a caver, I want the API to reject my attempt to change isSensitive on a locked entrance, so that administrator-locked sensitivity cannot be overridden.

Acceptance Criteria

  1. IF an entrance has isSensitiveLocked set to true and the request sender is not an Administrator, THEN THE PUT /api/v1/entrances/:id endpoint SHALL respond with 403 Forbidden when the request body contains an isSensitive value different from the current persisted value.
  2. IF an entrance has isSensitiveLocked set to true and the request sender is an Administrator, THEN THE PUT /api/v1/entrances/:id endpoint SHALL allow changes to isSensitive.
  3. IF an entrance has isSensitiveLocked set to false or undefined, THEN THE existing sensitivity permission logic SHALL apply unchanged (non-admins can mark as sensitive but cannot unmark).
  4. THE PUT /api/v1/entrances/:id endpoint SHALL allow administrators to set isSensitiveLocked to true or false.
  5. THE PUT /api/v1/entrances/:id endpoint SHALL reject (ignore or 403) attempts by non-administrators to change isSensitiveLocked.

Requirement 4: Entrance creation respects isSensitiveLocked

User Story: As a developer, I want the entrance creation flow to accept isSensitiveLocked from administrators, so that administrators can lock sensitivity at creation time.

Acceptance Criteria

  1. WHEN an Administrator sends isSensitiveLocked: true in a POST /api/v1/entrances request, THE created entrance SHALL have isSensitiveLocked set to true.
  2. WHEN a non-Administrator sends isSensitiveLocked: true in a POST /api/v1/entrances request, THE API SHALL ignore the field and create the entrance with isSensitiveLocked set to false.
  3. WHEN isSensitiveLocked is omitted from the request body, THE created entrance SHALL default to isSensitiveLocked: false.

Requirement 5: Massif sensitivity lock enforcement

User Story: As an administrator, I want the massif sensitivity endpoints to respect the lock state, so that the sensitivity of a locked massif cannot be changed until it is unlocked.

Acceptance Criteria

  1. IF a massif has isSensitiveLocked set to true, THEN THE POST /api/v1/massifs/:id/mark-sensitive endpoint SHALL respond with 403 Forbidden with a message indicating the massif sensitivity is locked.
  2. IF a massif has isSensitiveLocked set to true, THEN THE POST /api/v1/massifs/:id/unmark-sensitive endpoint SHALL respond with 403 Forbidden with a message indicating the massif sensitivity is locked.
  3. THE PUT /api/v1/massifs/:id endpoint SHALL allow administrators to set isSensitiveLocked to true or false.
  4. THE PUT /api/v1/massifs/:id endpoint SHALL strip isSensitiveLocked from the update payload if the request sender is not an Administrator (same pattern as isSensitive being stripped).

Requirement 6: Massif cascade skips locked entrances

User Story: As an administrator performing a massif cascade, I want the cascade to skip entrances whose sensitivity is locked, so that manually locked entrances remain unchanged.

Acceptance Criteria

  1. WHEN MassifService.propagateSensitivityToEntrances runs, THE query SHALL exclude entrances where is_sensitive_locked = true from the set of entrances to update.
  2. THE POST /api/v1/massifs/:id/mark-sensitive response SHALL include a skippedLockedCount field indicating how many entrances were skipped due to their sensitivity being locked.
  3. THE POST /api/v1/massifs/:id/mark-sensitive response SHALL continue to include the count field indicating how many entrances were actually updated.
  4. WHEN entrance auto-inheritance is triggered during entrance creation (point falls within a sensitive massif), THE auto-inheritance SHALL still apply regardless of the entrance's lock state because the entrance is new and has no prior lock.

Requirement 7: Preview endpoint reports locked entrance count

User Story: As an administrator previewing a cascade, I want to know how many entrances are locked and will be skipped, so that I can make an informed decision before confirming.

Acceptance Criteria

  1. THE GET /api/v1/massifs/:id/preview-sensitive response SHALL include a lockedCount field indicating how many entrances within the massif have isSensitiveLocked = true and isSensitive = false (i.e., locked in non-sensitive state and thus would be skipped).
  2. THE GET /api/v1/massifs/:id/preview-sensitive response SHALL continue to include the count field indicating the number of non-sensitive, non-locked entrances that would be affected.
  3. IF all non-sensitive entrances in the massif are locked, THE count field SHALL be 0 and lockedCount SHALL reflect the total locked non-sensitive entrance count.

Requirement 8: Massif update endpoint handles isSensitiveLocked

User Story: As an administrator, I want to set or unset the sensitivity lock on a massif via the update endpoint, so that I can control whether the massif's sensitivity can be changed.

Acceptance Criteria

  1. WHEN an Administrator sends isSensitiveLocked in the PUT /api/v1/massifs/:id request body, THE endpoint SHALL persist the value to the is_sensitive_locked column.
  2. WHEN a non-Administrator sends isSensitiveLocked in the PUT /api/v1/massifs/:id request body, THE endpoint SHALL strip the field (not persist it).
  3. THE MassifService.getConvertedDataFromClientRequest SHALL extract isSensitiveLocked from the request using the same coerceBool pattern used for isSensitive.

Requirement 9: Update Swagger/OpenAPI specification

User Story: As a frontend developer or API consumer, I want the OpenAPI spec to document the isSensitiveLocked field, so that I can understand the API contract without reading the source.

Acceptance Criteria

  1. THE assets/swaggerV1.yaml SHALL document isSensitiveLocked as a boolean field in the entrance request and response schemas.
  2. THE assets/swaggerV1.yaml SHALL document isSensitiveLocked as a boolean field in the massif request and response schemas.
  3. THE assets/swaggerV1.yaml SHALL document the skippedLockedCount field in the mark-sensitive response schema.
  4. THE assets/swaggerV1.yaml SHALL document the lockedCount field in the preview-sensitive response schema.
  5. THE assets/swaggerV1.yaml SHALL document the 403 response for mark-sensitive and unmark-sensitive when the massif sensitivity is locked.

Metadata

Metadata

Assignees

No fields configured for Feature.

Projects

Status
Ready

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions