meraproject/openspec/changes/project-members-write/specs/project-members-write/spec.md
keboss-m 5c21d25d45 Initial commit: Merakomis portal, Docker stack and user-reader API.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-24 11:04:05 +03:00

5.1 KiB

Spec: project-members-write

ADDED Requirements

Requirement: Upsert project team member

The system SHALL expose PUT /api/project-members that creates or updates a row in tMerakomisTeamMember for the given project_id and emp_id.

The endpoint MUST resolve team from tMerakomisProject.team for project_id.

If a row with the same (team, emp) already exists, the system MUST UPDATE it; otherwise MUST INSERT.

The request MUST require X-Api-Key (when configured) and X-Acting-Emp-Id.

Required JSON fields: project_id, emp_id, section_id, role.

Optional JSON fields: active (default true), text (default empty string).

The response MUST include ok: true and a member object with the same fields as one item of GET /api/project-members (member_id, emp_id, emp_name, project_id, project_code, project_name, step_name, section_id, section_name, role, active).

Scenario: Add new member to project team

  • WHEN acting user has can_write_member for the project
  • AND no tMerakomisTeamMember row exists for (team, emp)
  • AND section_id is allowed for project_id
  • AND emp_id refers to a non-archived, non-removed employee
  • THEN system inserts a new TeamMember row
  • AND returns 200 with ok: true and the new member object including member_id

Scenario: Update existing member

  • WHEN a TeamMember row already exists for (team, emp)
  • AND acting user has can_write_member for the project and target employee
  • THEN system updates section, role, active, and text
  • AND returns 200 with updated member object (same member_id)

Scenario: Deactivate member

  • WHEN client sends PUT with active: false for an existing member
  • AND acting user has write permission
  • THEN system sets active to 0
  • AND member no longer appears in GET /api/project-members?active_only=true

Requirement: Validate section belongs to project

The system MUST reject writes where section_id is not listed in tMerakomisProjectSection for the given project_id.

Scenario: Invalid section for project

  • WHEN section_id is not in the project's allowed sections
  • THEN system returns 400 with a structured error indicating invalid section

Scenario: Project has no configured sections

  • WHEN tMerakomisProjectSection has no rows for project_id
  • AND client attempts to add a member
  • THEN system returns 400 indicating sections must be configured on the project first

Requirement: Validate required member fields

The system MUST reject writes when emp_id, role, or section_id is missing or zero.

Scenario: Missing role

  • WHEN role is 0 or omitted
  • THEN system returns 400 with validation error for role

Requirement: Reject invalid employee

The system MUST NOT add archived, removed, or non-existent employees to a project team.

Scenario: Archived employee

  • WHEN emp_id refers to an employee with archive=1 or removed=1
  • THEN system returns 400 with validation error for employee

Scenario: Unknown employee

  • WHEN emp_id does not exist in the employee table
  • THEN system returns 404

Requirement: Authorize member writes with isRwMember parity

The system MUST allow PUT /api/project-members only when the acting employee would pass PHP Rules::isRwMember for the project's team.

Authorization MUST grant write when acting user is admin, project director (РП), MAIN_ENGINEER (role 2) on that project's team, or department director adding/editing a subordinate employee.

Scenario: Admin can write

  • WHEN acting employee has admin type
  • THEN system allows upsert for any valid project and employee

Scenario: Project director can write

  • WHEN acting employee is tMerakomisProject.director for project_id
  • THEN system allows upsert

Scenario: GIP can write

  • WHEN acting employee's role in the project team is MAIN_ENGINEER (2)
  • THEN system allows upsert

Scenario: Department director can write subordinate

  • WHEN acting employee is director of a department subtree
  • AND emp_id is in acting user's subordinate set
  • THEN system allows upsert

Scenario: Unauthorized user denied

  • WHEN acting employee does not meet any isRwMember condition
  • THEN system returns 403 with structured error forbidden

Requirement: Extend labor permissions with can_write_member

GET /api/labor/permissions MUST accept optional project_id, member_id, and target_emp_id query parameters and MUST return can_write_member: boolean reflecting the same rules as member write authorization.

Scenario: RP checks permission before UI action

  • WHEN client calls GET /api/labor/permissions?target_emp_id={acting}&project_id={pid}
  • AND acting user is project director
  • THEN response includes can_write_member: true

Scenario: Regular employee cannot manage team

  • WHEN acting user is a plain team member without RP/GIP/dept-director rights
  • THEN response includes can_write_member: false