Skip to content

[ResourceApp][Backend][Feat] Implement Resource-Permission Endpoints#76

Open
saknarajapakshe wants to merge 4 commits intoLSFLK:mainfrom
saknarajapakshe:71-feat-permission-enpoints
Open

[ResourceApp][Backend][Feat] Implement Resource-Permission Endpoints#76
saknarajapakshe wants to merge 4 commits intoLSFLK:mainfrom
saknarajapakshe:71-feat-permission-enpoints

Conversation

@saknarajapakshe
Copy link
Contributor

Overview

This PR completes the Permission domain implementation for the Resource bounded context. It adds DDD-style flows for permission endpoints and enforces consistent domain rules (unique group-resource-permission, permission type validation) with repository/service separation.

  • POST /api/resource-permissions
  • PATCH /api/resource-permissions/:id
  • DELETE /api/resource-permissions/:id
  • GET /api/groups/:id/permissions

What added

  • cmd/server/main.go: route registration for permission endpoints
  • internal/permission/handlers.go: handlers + input validation + status code mapping
  • internal/permission/service.go: permission business rules (create/update/delete/list)
  • internal/permission/repository.go: repository methods with DB checks and conflict handling
  • internal/permission/models.go: domain model and request/response models
  • internal/permission/constants.go: permission type constants and domain errors (REQUEST, APPROVE, ErrPermissionConflict, etc.)
  • internal/db/db.go: auto-migrate permission.ResourcePermission included

How to test locally

  1. ensure DB is ready (MySQL + resource_app)
  2. apply migrations
  3. run tests:
go test ./...
  1. run server:
go run ./cmd/server/main.go

5. test endpoints:

  • GET /api/groups/:groupId/permissions
  • POST /api/resource-permissions
  • PATCH /api/resource-permissions/:id
  • DELETE /api/resource-permissions/:id

Behavior expectations

  • duplicate group+resource+permission entries return 409 Conflict ("permission already exists for this group and resource")
  • invalid type returns 400 Bad Request
  • missing resources/groups/permission IDs return 404 Not Found
  • successful creations/updates return 201/200 with expected payload
  • booking/resource/user behavior is unchanged.
image image image image

related to #75

@saknarajapakshe saknarajapakshe requested a review from a team March 23, 2026 09:16
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's authorization capabilities by introducing a dedicated permission management system. It establishes a clear, DDD-aligned structure for handling resource permissions within groups, allowing for granular control over access. The changes include new API endpoints for creating, updating, deleting, and querying permissions, alongside robust validation and error handling to ensure data integrity and a consistent user experience. Furthermore, it expands existing group functionalities to manage user memberships effectively.

Highlights

  • New Permission Endpoints: Introduced new API endpoints for managing resource permissions: POST /api/resource-permissions for creation, PATCH /api/resource-permissions/:id for updating permission types, DELETE /api/resource-permissions/:id for removal, and GET /api/groups/:id/permissions to retrieve all permissions for a specific group.
  • Domain-Driven Design (DDD) Implementation: Implemented the Permission domain following DDD principles, separating concerns into handlers, services, and repositories to enforce consistent domain rules and improve maintainability.
  • Robust Validation and Error Handling: Added comprehensive validation for permission types, group and resource IDs, and implemented conflict detection for duplicate group-resource-permission entries, returning appropriate HTTP status codes (400, 404, 409, 500).
  • Database Schema Updates: Created new database tables resource_permissions and user_groups with appropriate foreign key constraints, indexes, and unique keys to support the new permission and group membership functionalities.
  • Group Membership Management: Extended group management functionalities to include adding and removing users from groups, and retrieving group members, with corresponding API endpoints and business logic.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively implements the permission domain, adding DDD-style flows for creating, updating, deleting, and listing resource permissions. The separation into handlers, services, and repositories is well-executed. My review focuses on a few areas for improvement, primarily within the repository logic and database schema design. I've identified a potential design issue with the uniqueness of permissions that should be clarified, an incorrect handling of no-op updates, an opportunity to remove a redundant database query, and a couple of minor error message inconsistencies. Overall, this is a solid contribution that completes the permission domain.

Comment on lines +61 to +63
if existing.PermissionType == permissionType {
return nil, ErrPermissionConflict
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Returning a conflict error when attempting to update a permission to the type it already has is not ideal. This action should be treated as a no-op (a successful operation that results in no change) rather than an error. API consumers may not always know the current state and shouldn't be penalized for it. A better approach is to return the existing permission object with a success status.

Suggested change
if existing.PermissionType == permissionType {
return nil, ErrPermissionConflict
}
if existing.PermissionType == permissionType {
return &existing, nil
}


INDEX `idx_resource_permissions_resource` (`resource_id`),
INDEX `idx_resource_permissions_group` (`group_id`),
UNIQUE KEY `uk_resource_group_permission` (`resource_id`, `group_id`, `permission_type`),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The unique key includes permission_type, which allows a group to have multiple permission types (e.g., both REQUEST and APPROVE) for the same resource. This might be unintentional and could lead to confusing behavior. Typically, a group has a single, highest permission level for a resource (e.g., APPROVE should imply REQUEST).

If the intent is to enforce one permission per group-resource pair, the unique key should be (resource_id, group_id). This would also align with the current ErrPermissionConflict message ("permission already exists for this group and resource").

Please clarify if the current design is intended. If so, consider updating the error message and documenting this behavior. If not, the unique constraint should be changed.

case errors.Is(err, ErrGroupNotFound), errors.Is(err, ErrUserNotFound):
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
default:
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add users to group: "})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error message string has a trailing space. This is likely a typo and can cause issues for API clients that parse error messages.

Suggested change
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add users to group: "})
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add users to group"})


var (
ErrPermissionNotFound = errors.New("permission not found")
ErrPermissionConflict = errors.New("permission already exists for this group and resource")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This error message is misleading given the database schema. The unique constraint is on (resource_id, group_id, permission_type), meaning a conflict occurs only when the same permission type is duplicated for a group and resource. The message should be more specific to reflect this.

Suggested change
ErrPermissionConflict = errors.New("permission already exists for this group and resource")
ErrPermissionConflict = errors.New("permission type already exists for this group and resource")

Comment on lines +80 to +88
var updated ResourcePermission
if err := r.db.First(&updated, "id = ?", id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, ErrPermissionNotFound
}
return nil, err
}

return &updated, nil

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This second database query to fetch the updated permission is redundant and inefficient. You have already fetched the permission into the existing variable at the beginning of the function. After a successful database update, you can simply update the PermissionType field on the existing object in memory and return it. This avoids an unnecessary database roundtrip.

existing.PermissionType = permissionType
	return &existing, nil

@saknarajapakshe saknarajapakshe changed the title 71 feat permission enpoints [ResourceApp][Backend][Feat] Implement Resource-Permission Endpoints Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant