Skip to content

Conversation

@dheeru0198
Copy link
Member

@dheeru0198 dheeru0198 commented Jul 24, 2025

Description

  • Split the detail and list endpoints to separate views.

Type of Change

  • Code refactoring
  • Documentation update

Summary by CodeRabbit

  • New Features

    • Introduced comprehensive OpenAPI/Swagger documentation and schema generation for the API with interactive Swagger UI and Redoc endpoints.
    • Added modular, detailed API documentation with reusable parameters, responses, and examples for core entities including projects, issues, cycles, modules, states, assets, intake, users, and members.
    • Implemented new endpoints for asset management and user profile retrieval.
    • Enhanced search capabilities with semantic issue search endpoint.
    • Added granular, RESTful endpoints for cycles, modules, states, intake, and project management with explicit HTTP method controls.
    • Expanded serializer coverage for assets, cycles, modules, intake issues, and project operations.
  • Improvements

    • Refactored API views and serializers for improved modularity, clarity, and maintainability.
    • Added detailed docstrings and OpenAPI annotations across serializers and views.
    • Strengthened permission checks, validation, and error handling for all major endpoints.
    • Restricted timezone choices to commonly used options for users, projects, cycles, and workspaces.
  • Documentation

    • Added extensive OpenAPI documentation utilities and README for maintainers.
    • Introduced reusable decorators, parameters, responses, and examples to standardize API documentation.
  • Chores

    • Added drf-spectacular as a dependency for OpenAPI support.
    • Cleaned up unused imports and redundant code.
  • Style

    • Improved code organization and naming consistency across views, serializers, and URL patterns.

dheeru0198 and others added 30 commits May 29, 2025 15:02
- Introduced new asset-related endpoints for user assets and server assets, allowing for asset uploads and management.
- Added user endpoint to retrieve current user information.
- Updated URL routing to include new asset and user patterns.
- Enhanced issue handling with a new search endpoint for issues across multiple fields.
- Expanded member management with a new endpoint for workspace members.
- Updated CycleAPIEndpoint and CycleIssueAPIEndpoint to include detailed OpenAPI schema definitions for GET, POST, PATCH, and DELETE operations.
- Specified allowed HTTP methods for each endpoint in the URL routing.
- Improved documentation for cycle creation, updating, and deletion, including request and response examples.
…od definitions

- Added detailed OpenAPI schema definitions for various API endpoints including Intake, Module, and State.
- Specified allowed HTTP methods for each endpoint in the URL routing for better clarity and documentation.
- Improved request and response examples for better understanding of API usage.
- Introduced unarchive functionality for cycles and modules with appropriate endpoint definitions.
Improves the organization and maintainability of the OpenAPI documentation by modularizing the `openapi_spec_helpers.py` file.

The changes include:
- Migrates common parameters, responses, examples, and authentication extensions to separate modules.
- Introduces helper decorators for different endpoint types.
- Updates view imports to use the new module paths.
- Removes the legacy `openapi_spec_helpers.py` file.

This refactoring results in a more structured and easier-to-maintain OpenAPI documentation setup.
- Removed unnecessary parameters from the OpenAPI documentation for various endpoints in the asset, cycle, and project views.
- Updated request structures to improve clarity and consistency across the API documentation.
- Enhanced response formatting for better readability and maintainability.
Updated various API endpoints across the application to include comprehensive docstrings that clarify their functionality. Each endpoint now features a summary and detailed description, improving the overall understanding of their purpose and usage. This change enhances the OpenAPI specifications for better developer experience and documentation clarity.
- Added new serializers for handling cycle and module issue requests, including `CycleIssueRequestSerializer`, `TransferCycleIssueRequestSerializer`, `ModuleIssueRequestSerializer`, and intake issue creation/updating serializers.
- Updated existing serializers to improve clarity and maintainability, including the `UserAssetUploadSerializer` and `IssueAttachmentUploadSerializer`.
- Refactored API views to utilize the new serializers, enhancing the request handling for cycle and intake issue endpoints.
- Improved OpenAPI documentation by replacing inline request definitions with serializer references for better consistency and readability.
- Replaced inline schema definitions with dedicated decorators for various endpoint types, enhancing clarity and maintainability.
- Updated API views to utilize new decorators for user, cycle, intake, module, and project endpoints, improving consistency in OpenAPI documentation.
- Removed unnecessary parameters and responses from endpoint specifications, streamlining the documentation for better readability.
- Enhanced the organization of OpenAPI documentation by modularizing endpoint-specific decorators and parameters.
- Removed unused `StateLiteSerializer` import from the serializer module.
- Updated test setup to include a noqa comment for the `django_db_setup` fixture, ensuring clarity in the code.
- Added missing commas in user data dictionary for consistency.
pablohashescobar and others added 12 commits June 11, 2025 12:58
- Updated API endpoints in asset, cycle, intake, issue, module, project, and state views to include OpenApiRequest and OpenApiExample for better request documentation.
- Added example requests for creating and updating resources, improving clarity for API consumers.
- Ensured consistent use of OpenApi utilities across all relevant endpoints to enhance overall API documentation quality.
- Added detailed descriptions to multiple API endpoints across asset, cycle, intake, issue, module, project, state, and user views to improve clarity for API consumers.
- Ensured consistent documentation practices by including descriptions that outline the purpose and functionality of each endpoint.
- This update aims to enhance the overall usability and understanding of the API documentation.
- Changed example fields in OpenAPI documentation for issue comments from "content" to "comment_html" to reflect the correct structure.
- Introduced a new `get_queryset` method in the ProjectDetailAPIEndpoint to filter projects based on user membership and workspace, while also annotating additional project-related data such as total members, cycles, and modules.
- Updated permission checks to use the correct attribute name for project identifiers, ensuring accurate permission handling.
- Updated multiple API endpoints across asset, cycle, intake, issue, module, project, state, and user views to include new OpenApiResponse examples for better clarity on expected outcomes.
- Introduced new parameters for project and issue identifiers to improve request handling and documentation consistency.
- Enhanced existing responses with detailed examples to aid API consumers in understanding the expected data structure and error handling.
- This update aims to improve the overall usability and clarity of the API documentation.
…tiple API endpoints for consistency and clarity
 Conflicts:
	apps/api/plane/api/serializers/asset.py
	apps/api/plane/api/urls/asset.py
	apps/api/plane/api/urls/schema.py
	apps/api/plane/api/urls/user.py
	apps/api/plane/api/views/asset.py
	apps/api/plane/api/views/cycle.py
	apps/api/plane/api/views/issue.py
	apps/api/plane/api/views/user.py
	apps/api/plane/settings/openapi.py
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 24, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces a comprehensive refactor and modularization of the Plane API's OpenAPI schema generation and documentation, primarily integrating the drf-spectacular package. It splits monolithic API endpoints into granular, RESTful classes, adds domain-specific serializers, reorganizes URL routing, and centralizes OpenAPI utilities into a modular package. Numerous docstrings, enums, and validation enhancements are added throughout the codebase.

Changes

File(s) / Group Change Summary
apps/api/plane/api/serializers/asset.py, apps/api/plane/api/views/asset.py, apps/api/plane/api/urls/asset.py Introduced asset management endpoints, serializers, and URL routes for file uploads, updates, and downloads.
apps/api/plane/api/serializers/cycle.py, apps/api/plane/api/views/cycle.py, apps/api/plane/api/urls/cycle.py Refactored cycle-related API into modular endpoints and serializers with explicit create/update logic and OpenAPI docs.
apps/api/plane/api/serializers/intake.py, apps/api/plane/api/views/intake.py, apps/api/plane/api/urls/intake.py Split intake issue endpoints and serializers for list/create vs. detail/update/delete, added detailed validation and docs.
apps/api/plane/api/serializers/issue.py, apps/api/plane/api/views/issue.py, apps/api/plane/api/urls/issue.py Refactored issue, label, link, comment, activity, and attachment endpoints and serializers for RESTful separation and enhanced docs.
apps/api/plane/api/serializers/module.py, apps/api/plane/api/views/module.py, apps/api/plane/api/urls/module.py Modularized module endpoints and serializers, added bulk work item assignment, archive/unarchive, and improved validation.
apps/api/plane/api/serializers/project.py, apps/api/plane/api/views/project.py, apps/api/plane/api/urls/project.py Separated project list/create, detail/update/delete, and archive/unarchive endpoints; added create/update serializers and docs.
apps/api/plane/api/serializers/state.py, apps/api/plane/api/views/state.py, apps/api/plane/api/urls/state.py Split state endpoints and serializers for list/create vs. detail/update/delete, added docstrings and validation.
apps/api/plane/api/serializers/user.py, apps/api/plane/api/views/user.py, apps/api/plane/api/urls/user.py Added user profile endpoint and serializer with avatar URL, plus OpenAPI docs.
apps/api/plane/api/views/member.py, apps/api/plane/api/urls/member.py Removed member POST (creation) endpoint, split workspace/project member GET endpoints, added OpenAPI docs.
apps/api/plane/api/serializers/__init__.py, apps/api/plane/api/views/__init__.py Expanded imports to reflect new modular structure and serializers.
apps/api/plane/api/serializers/base.py, apps/api/plane/api/serializers/estimate.py, apps/api/plane/api/serializers/workspace.py Added or expanded docstrings for clarity.
apps/api/plane/api/urls/__init__.py Added asset and user URL patterns to main urlpatterns.
apps/api/plane/api/urls/schema.py, apps/api/plane/urls.py Introduced conditional OpenAPI schema, Swagger, and Redoc endpoints based on feature flag.
apps/api/plane/settings/common.py, apps/api/plane/settings/openapi.py Added drf-spectacular integration, OpenAPI settings, and conditional feature flag for schema generation.
apps/api/plane/utils/openapi/ (multiple new files) Modularized OpenAPI utilities: authentication extensions, parameters, responses, examples, decorators, and hooks for drf-spectacular.
apps/api/plane/app/permissions/project.py Updated permission logic to use correct project identifier attribute.
apps/api/plane/db/models/ (cycle.py, project.py, workspace.py, user.py, intake.py, module.py) Restricted timezone choices to common timezones; added enums for intake issue status and module status.
apps/api/plane/app/views/analytic/advance.py, apps/api/plane/app/views/workspace/cycle.py, apps/api/plane/bgtasks/issue_activities_task.py, apps/api/plane/db/management/commands/update_deleted_workspace_slug.py, apps/api/plane/tests/ (various) Removed unused imports for code cleanup.
apps/api/requirements/base.txt Added drf-spectacular dependency for OpenAPI support.
apps/api/plane/space/serializer/__init__.py Removed redundant imports.
apps/api/plane/api/apps.py Registered OpenAPI authentication extensions on app ready.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant APIView
    participant Serializer
    participant OpenAPIUtils
    participant drf-spectacular

    Client->>APIView: Sends HTTP request (e.g., POST /api/v1/projects/)
    APIView->>Serializer: Validate and process request data
    APIView->>OpenAPIUtils: Annotate with OpenAPI decorators, parameters, responses
    APIView->>drf-spectacular: Schema generation (if enabled)
    drf-spectacular->>OpenAPIUtils: Use auth extensions, parameters, hooks
    APIView-->>Client: Returns serialized response (with OpenAPI docs if requested)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Complexity: Extensive refactor and modularization, new features, many new files, significant changes to API structure, serializers, endpoints, and OpenAPI documentation.

Possibly related PRs

Suggested labels

external api, 🛠️refactor, requires approval

Suggested reviewers

  • pablohashescobar
  • prateekshourya29

Poem

In fields of code where schemas grow,
The rabbits hop, the endpoints flow.
URLs split, serializers bloom,
OpenAPI shines—no more monolithic gloom!
With docs so clear and enums in tow,
This patch brings sunshine where APIs go.
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e4416b and c360850.

📒 Files selected for processing (8)
  • apps/api/plane/api/serializers/module.py (5 hunks)
  • apps/api/plane/api/urls/member.py (1 hunks)
  • apps/api/plane/api/urls/module.py (1 hunks)
  • apps/api/plane/api/views/cycle.py (17 hunks)
  • apps/api/plane/api/views/intake.py (8 hunks)
  • apps/api/plane/api/views/issue.py (34 hunks)
  • apps/api/plane/utils/openapi/__init__.py (1 hunks)
  • apps/api/plane/utils/openapi/auth.py (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch openapi-specification

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@dheeru0198 dheeru0198 changed the title Restructuring of the external API code Restructuring of the external API code for better maintainability Jul 24, 2025
@dheeru0198 dheeru0198 requested a review from Copilot July 24, 2025 15:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a comprehensive OpenAPI/Swagger documentation system for the Plane REST API by integrating drf-spectacular. The changes include modularizing OpenAPI utilities, restructuring API views for better documentation support, and establishing a maintainable documentation framework.

Key changes implemented:

  • OpenAPI Module Structure: Created a modular plane/utils/openapi/ package with separate files for authentication, parameters, responses, examples, decorators, and schema processing hooks
  • View Restructuring: Split combined list/detail views into separate endpoints following REST conventions for better API documentation clarity
  • Documentation Integration: Added comprehensive OpenAPI decorators and examples across all API endpoints with consistent parameter and response definitions

Reviewed Changes

Copilot reviewed 64 out of 64 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
apps/api/plane/utils/openapi/*.py New modular OpenAPI utilities replacing monolithic helpers
apps/api/plane/api/views/*.py Restructured API views with OpenAPI documentation decorators
apps/api/plane/settings/*.py Added OpenAPI configuration and conditional drf-spectacular integration
apps/api/plane/urls.py Added OpenAPI schema and documentation UI endpoints
apps/api/requirements/base.txt Added drf-spectacular dependency for OpenAPI generation

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 24, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

I'll review this PR for you. Let me gather the necessary information about the changes first.


🏁 Script executed:

#!/bin/bash
# Get PR information and status
gh pr view 7477 --json title,body,state,isDraft,additions,deletions,changedFiles,files

# Get the list of changed files
gh pr diff 7477 --name-only

# Get the actual diff content for review
gh pr diff 7477

Length of output: 276303


@sriramveeraghanta This is an excellent and comprehensive refactoring PR! I can see significant improvements in API structure, documentation, and maintainability. Here's my detailed review:

🎯 Overall Assessment: Excellent Work

This PR demonstrates a mature approach to API design with proper separation of concerns, comprehensive documentation, and improved maintainability.

Major Strengths

1. Proper API Endpoint Separation

The split between list/create and detail endpoints is a best practice:

# Before: Single endpoint handling all operations
class IssueAPIEndpoint(BaseAPIView):
    def get(self, request, slug, project_id, pk=None):
        if pk:
            # Detail logic
        else:
            # List logic

# After: Properly separated endpoints
class IssueListCreateAPIEndpoint(BaseAPIView):
    def get(self, request, slug, project_id):
        # List logic only

class IssueDetailAPIEndpoint(BaseAPIView):
    def get(self, request, slug, project_id, pk):
        # Detail logic only

2. Enhanced Serializer Architecture

The introduction of specific create/update serializers follows Django best practices:

# Create serializer with validation
class CycleCreateSerializer(BaseSerializer):
    class Meta:
        fields = ["name", "description", "start_date", "end_date", ...]

# Update serializer extending create
class CycleUpdateSerializer(CycleCreateSerializer):
    class Meta(CycleCreateSerializer.Meta):
        fields = CycleCreateSerializer.Meta.fields + ["owned_by"]

3. Comprehensive OpenAPI Documentation

The addition of detailed API documentation with examples is outstanding:

@cycle_docs(
    operation_id="create_cycle",
    summary="Create cycle",
    description="Create a new development cycle...",
    request=OpenApiRequest(request=CycleCreateSerializer, examples=[CYCLE_CREATE_EXAMPLE]),
    responses={201: OpenApiResponse(response=CycleSerializer, examples=[CYCLE_EXAMPLE])},
)

4. Improved URL Structure

The URL patterns are now more RESTful and explicit:

# Clear separation of list vs detail endpoints
path("cycles/", CycleListCreateAPIEndpoint.as_view(http_method_names=["get", "post"]))
path("cycles/<uuid:pk>/", CycleDetailAPIEndpoint.as_view(http_method_names=["get", "patch", "delete"]))

🔧 Technical Improvements

1. Generic Base Classes

Moving from APIView to GenericAPIView provides better structure:

class BaseAPIView(TimezoneMixin, GenericAPIView, BasePaginator):
    # Better foundation for CRUD operations

2. Asset Management

The new asset management system with presigned URLs is well-designed:

class UserAssetEndpoint(BaseAPIView):
    def post(self, request):
        # Generate presigned URL for S3 upload
        # Clean separation of concerns

3. Consistent Response Patterns

All endpoints now follow consistent response patterns with proper HTTP status codes.

⚠️ Areas for Consideration

1. Backward Compatibility

Since this changes URL patterns significantly, ensure:

  • Proper deprecation notices for old endpoints
  • Migration guide for API consumers
  • Version compatibility considerations

2. Performance Impact

With 64 files changed, monitor:

  • Import performance impact
  • Memory usage with new documentation overhead
  • Response time changes

3. Error Handling

Consider standardizing error responses across all new endpoints:

# Consistent error response format
{
    "error": "Description",
    "code": "ERROR_CODE", 
    "details": {...}
}

🚀 Recommendations

1. Add Migration Strategy

Consider adding a migration guide in the PR description or documentation.

2. Testing Coverage

Given the scope of changes, ensure comprehensive test coverage for all new endpoints.

3. Rate Limiting

With improved API structure, consider implementing rate limiting decorators.

4. Caching Strategy

The new structure allows for better caching strategies - consider implementing appropriate caching.

🎉 Excellent Additions

  1. Search Functionality: The new IssueSearchEndpoint with semantic search is a great addition
  2. Timezone Improvements: Moving from pytz.all_timezones to pytz.common_timezones is more practical
  3. Asset Management: Comprehensive file upload system with validation
  4. Documentation: The OpenAPI documentation is thorough and professional

📝 Minor Suggestions

  1. Consider adding API versioning headers for future-proofing
  2. Add request/response logging for better debugging
  3. Consider adding bulk operation endpoints where appropriate

Conclusion

This is an exemplary refactoring that significantly improves:

  • Code maintainability and readability
  • API documentation and usability
  • Separation of concerns
  • Developer experience

The restructuring follows Django and DRF best practices while maintaining functionality. The comprehensive documentation will greatly benefit API consumers.

Status: Ready to merge once any backward compatibility concerns are addressed! 🚢

Great work on this substantial improvement to the API architecture!

@sriramveeraghanta sriramveeraghanta marked this pull request as ready for review July 24, 2025 18:01
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 27

🔭 Outside diff range comments (14)
apps/api/plane/authentication/provider/oauth/github.py (2)

95-103: expires_in interpreted as Unix epoch – access-token expiry will be wrong.
GitHub returns seconds until expiry, not an epoch timestamp. Converting it with datetime.fromtimestamp skews the value to 1970-01-01 + N seconds.

-"access_token_expired_at": (
-    datetime.fromtimestamp(
-        token_response.get("expires_in"), tz=pytz.utc
-    )
-    if token_response.get("expires_in")
-    else None
-),
+"access_token_expired_at": (
+    datetime.utcnow().replace(tzinfo=pytz.utc)
+    + timedelta(seconds=token_response["expires_in"])
+    if token_response.get("expires_in")
+    else None
+),

Same logic applies to refresh_token_expired_at.


118-123: External HTTP calls lack a timeout – potential request hang.

Add a reasonable timeout (e.g., 5 s) and surface requests.Timeout in the existing except block.

-emails_response = requests.get(emails_url, headers=headers).json()
+emails_response = requests.get(emails_url, headers=headers, timeout=5).json()
apps/api/plane/api/serializers/user.py (1)

24-34: Fix duplicate email field in Meta.fields.

The email field appears twice in the fields list (lines 32 and 33), which could cause serialization issues.

        fields = [
            "id",
            "first_name",
            "last_name",
            "email",
            "avatar",
            "avatar_url",
            "display_name",
-            "email",
        ]
apps/api/plane/api/serializers/module.py (2)

135-152: Optimize member update logic

The current implementation deletes all members and recreates them, which is inefficient and could trigger unnecessary database operations and signals. Consider updating only the differences.

        if members is not None:
-            ModuleMember.objects.filter(module=instance).delete()
-            ModuleMember.objects.bulk_create(
-                [
-                    ModuleMember(
-                        module=instance,
-                        member_id=str(member),
-                        project=instance.project,
-                        workspace=instance.project.workspace,
-                        created_by=instance.created_by,
-                        updated_by=instance.updated_by,
-                    )
-                    for member in members
-                ],
-                batch_size=10,
-                ignore_conflicts=True,
-            )
+            # Get current members
+            current_members = set(instance.module_members.values_list('member_id', flat=True))
+            new_members = set(str(member) for member in members)
+            
+            # Remove members that are no longer in the list
+            members_to_remove = current_members - new_members
+            if members_to_remove:
+                ModuleMember.objects.filter(module=instance, member_id__in=members_to_remove).delete()
+            
+            # Add new members
+            members_to_add = new_members - current_members
+            if members_to_add:
+                ModuleMember.objects.bulk_create(
+                    [
+                        ModuleMember(
+                            module=instance,
+                            member_id=member_id,
+                            project=instance.project,
+                            workspace=instance.project.workspace,
+                            created_by=instance.created_by,
+                            updated_by=instance.updated_by,
+                        )
+                        for member_id in members_to_add
+                    ],
+                    batch_size=10,
+                    ignore_conflicts=True,
+                )

244-251: Fix error message to reference Module instead of Issue

The error message incorrectly references "Issue" when it should reference "Module".

    def create(self, validated_data):
        if ModuleLink.objects.filter(
            url=validated_data.get("url"), module_id=validated_data.get("module_id")
        ).exists():
            raise serializers.ValidationError(
-                {"error": "URL already exists for this Issue"}
+                {"error": "URL already exists for this Module"}
            )
        return ModuleLink.objects.create(**validated_data)
apps/api/plane/api/views/member.py (2)

121-125: Use HTTP 404 for non-existent workspace

Consistent with the previous comment, return HTTP_404_NOT_FOUND for better RESTful semantics.

-        if not Workspace.objects.filter(slug=slug).exists():
-            return Response(
-                {"error": "Provided workspace does not exist"},
-                status=status.HTTP_400_BAD_REQUEST,
-            )
+        if not Workspace.objects.filter(slug=slug).exists():
+            return Response(
+                {"error": "Provided workspace does not exist"},
+                status=status.HTTP_404_NOT_FOUND,
+            )

127-130: Add project existence check

The endpoint should verify that the project exists before attempting to query its members, consistent with the workspace check pattern.

Add this check after the workspace validation:

# Check if the project exists
if not Project.objects.filter(id=project_id, workspace__slug=slug).exists():
    return Response(
        {"error": "Provided project does not exist"},
        status=status.HTTP_404_NOT_FOUND,
    )

Note: You'll need to import the Project model at the top of the file.

apps/api/plane/api/views/state.py (1)

86-108: Extract duplicate external ID validation logic

The external ID duplicate checking logic is repeated in the patch method. Consider extracting this to a reusable method to follow DRY principles.

Add a helper method to the class:

def check_external_id_duplicate(self, external_id, external_source, project_id, workspace_slug, exclude_id=None):
    """Check if an external ID already exists for the given source."""
    query = State.objects.filter(
        project_id=project_id,
        workspace__slug=workspace_slug,
        external_source=external_source,
        external_id=external_id,
    )
    if exclude_id:
        query = query.exclude(id=exclude_id)
    
    existing_state = query.first()
    if existing_state:
        return existing_state
    return None

Then use it in both post and patch methods.

apps/api/plane/api/views/intake.py (1)

332-333: Replace magic numbers with named constants for role checks

The code uses magic numbers (5, 15, 20) for role comparisons without clear meaning.

Define role constants in a central location:

# In a constants file or at the module level
class ProjectMemberRole:
    GUEST = 5
    VIEWER = 10
    MEMBER = 15
    ADMIN = 20

# Then use in the code:
if project_member.role <= ProjectMemberRole.GUEST and str(intake_issue.created_by_id) != str(request.user.id):
    # ...

if project_member.role > ProjectMemberRole.MEMBER:
    # ...

Also applies to: 406-406

apps/api/plane/api/serializers/issue.py (1)

31-34: Remove duplicate Django imports and consolidate at the top.

These Django imports should be consolidated with the Django imports at lines 1-5 to maintain clean import organization.

# Django imports
from django.utils import timezone
from lxml import html
from django.db import IntegrityError
+from django.core.exceptions import ValidationError
+from django.core.validators import URLValidator

#  Third party imports
from rest_framework import serializers

# Module imports
from plane.db.models import (
    Issue,
    IssueType,
    IssueActivity,
    IssueAssignee,
    FileAsset,
    IssueComment,
    IssueLabel,
    IssueLink,
    Label,
    ProjectMember,
    State,
    User,
)

from .base import BaseSerializer
from .cycle import CycleLiteSerializer, CycleSerializer
from .module import ModuleLiteSerializer, ModuleSerializer
from .state import StateLiteSerializer
from .user import UserLiteSerializer

-# Django imports
-from django.core.exceptions import ValidationError
-from django.core.validators import URLValidator
apps/api/plane/api/views/module.py (1)

419-421: Use ModuleUpdateSerializer for update operations.

The code uses ModuleSerializer for updates, but ModuleUpdateSerializer was imported and should be used for consistency with the pattern established in other endpoints.

-serializer = ModuleSerializer(
+serializer = ModuleUpdateSerializer(
    module, data=request.data, context={"project_id": project_id}, partial=True
)
apps/api/plane/api/views/issue.py (3)

285-298: API contract inconsistency with external ID filtering

The GET method returns a single issue object when external_id and external_source parameters are provided, but returns a paginated response otherwise. This breaks the API contract as the endpoint should always return the same response structure.

Consider returning a paginated response with a single item:

 if external_id and external_source:
-    issue = Issue.objects.get(
+    issues = Issue.objects.filter(
         external_id=external_id,
         external_source=external_source,
         workspace__slug=slug,
         project_id=project_id,
     )
-    return Response(
-        IssueSerializer(issue, fields=self.fields, expand=self.expand).data,
-        status=status.HTTP_200_OK,
-    )
+    return self.paginate(
+        request=request,
+        queryset=issues,
+        on_results=lambda issues: IssueSerializer(
+            issues, many=True, fields=self.fields, expand=self.expand
+        ).data,
+    )

300-386: Extract duplicated ordering logic into a shared method

The ordering logic for priority, state, labels, and assignees is duplicated between IssueListCreateAPIEndpoint.get() and IssueDetailAPIEndpoint.get(). This violates the DRY principle.

Create a shared method in BaseAPIView or a mixin:

def apply_issue_ordering(self, queryset, order_by_param):
    """Apply custom ordering logic for issues"""
    # Priority Ordering
    if order_by_param == "priority" or order_by_param == "-priority":
        priority_order = ["urgent", "high", "medium", "low", "none"]
        priority_order = (
            priority_order if order_by_param == "priority" else priority_order[::-1]
        )
        return queryset.annotate(
            priority_order=Case(
                *[
                    When(priority=p, then=Value(i))
                    for i, p in enumerate(priority_order)
                ],
                output_field=CharField(),
            )
        ).order_by("priority_order")
    
    # State Ordering
    elif order_by_param in ["state__name", "state__group", "-state__name", "-state__group"]:
        state_order = ["backlog", "unstarted", "started", "completed", "cancelled"]
        state_order = (
            state_order
            if order_by_param in ["state__name", "state__group"]
            else state_order[::-1]
        )
        return queryset.annotate(
            state_order=Case(
                *[
                    When(state__group=state_group, then=Value(i))
                    for i, state_group in enumerate(state_order)
                ],
                default=Value(len(state_order)),
                output_field=CharField(),
            )
        ).order_by("state_order")
    
    # assignee and label ordering
    elif order_by_param in ["labels__name", "-labels__name", "assignees__first_name", "-assignees__first_name"]:
        return queryset.annotate(
            max_values=Max(
                order_by_param[1::]
                if order_by_param.startswith("-")
                else order_by_param
            )
        ).order_by(
            "-max_values" if order_by_param.startswith("-") else "max_values"
        )
    else:
        return queryset.order_by(order_by_param)

Then use it in both endpoints:

issue_queryset = self.apply_issue_ordering(issue_queryset, order_by_param)

Also applies to: 574-660


1119-1129: Fix incorrect model check for label external ID validation

The code checks Issue.objects instead of Label.objects when validating external ID uniqueness for labels.

 if (
     str(request.data.get("external_id"))
     and (label.external_id != str(request.data.get("external_id")))
-    and Issue.objects.filter(
+    and Label.objects.filter(
         project_id=project_id,
         workspace__slug=slug,
         external_source=request.data.get(
             "external_source", label.external_source
         ),
         external_id=request.data.get("external_id"),
     ).exists()
 ):
♻️ Duplicate comments (3)
apps/api/plane/db/models/workspace.py (1)

115-115: Timezone choice optimization already coordinated

The change from pytz.all_timezones to pytz.common_timezones reduces the choice set from ~594 to ~403 options, improving performance while maintaining practical timezone coverage.

apps/api/plane/settings/common.py (1)

445-450: Address the unused SPECTACULAR_SETTINGS import.

The SPECTACULAR_SETTINGS is imported but not explicitly used, which could lead to it being ignored by drf-spectacular if not properly registered.

Consider explicitly assigning the settings to ensure they're properly registered:

if ENABLE_DRF_SPECTACULAR:
    REST_FRAMEWORK["DEFAULT_SCHEMA_CLASS"] = "drf_spectacular.openapi.AutoSchema"
    INSTALLED_APPS.append("drf_spectacular")
    from .openapi import SPECTACULAR_SETTINGS  # noqa: F401
+   # Ensure SPECTACULAR_SETTINGS are properly registered
+   globals().update({"SPECTACULAR_SETTINGS": SPECTACULAR_SETTINGS})
apps/api/plane/api/views/asset.py (1)

465-470: Exception handling is implemented securely

The exception is logged internally for debugging while returning a generic error message to users, which is the correct security practice. The static analysis warning appears to be a false positive.

🧹 Nitpick comments (25)
apps/api/plane/tests/conftest.py (1)

9-12: Rename the shadowed fixture parameter instead of suppressing F811

Adding # noqa: F811 silences the redefinition warning, but the parameter name django_db_setup still shadows the fixture you are overriding, which is confusing to readers and linters alike. Prefer renaming the parameter (e.g. _django_db_setup) and drop the noqa—clarity beats suppression.

-@pytest.fixture(scope="session")
-def django_db_setup(django_db_setup):  # noqa: F811
+@pytest.fixture(scope="session")
+def django_db_setup(_django_db_setup):
     """Set up the Django database for the test session"""
     pass
apps/api/plane/authentication/provider/oauth/github.py (1)

61-61: Triple-quoted f-string is overkill for a one-liner.
A simple single-quoted f-string improves readability.

-redirect_uri = f"""{"https" if request.is_secure() else "http"}://{request.get_host()}/auth/github/callback/"""
+redirect_uri = f'{"https" if request.is_secure() else "http"}://{request.get_host()}/auth/github/callback/'
apps/api/plane/db/models/intake.py (1)

38-44: Good centralization of status constants.

The IntakeIssueStatus enum provides a clean, centralized way to manage intake issue statuses with semantic meaning. This improves maintainability and follows Django best practices.

Consider updating the IntakeIssue.status field to use this enum for consistency:

 status = models.IntegerField(
-    choices=(
-        (-2, "Pending"),
-        (-1, "Rejected"),
-        (0, "Snoozed"),
-        (1, "Accepted"),
-        (2, "Duplicate"),
-    ),
+    choices=IntakeIssueStatus.choices,
     default=-2,
 )

You could also use default=IntakeIssueStatus.PENDING for better semantic clarity.

apps/api/plane/db/models/module.py (1)

54-61: Excellent centralization of module status constants.

The ModuleStatus enum provides a clean, semantic way to manage module statuses and improves code maintainability. The text-based choices align well with the existing field values.

Consider updating the Module.status field to use this enum for consistency and to eliminate duplication:

 status = models.CharField(
-    choices=(
-        ("backlog", "Backlog"),
-        ("planned", "Planned"),
-        ("in-progress", "In Progress"),
-        ("paused", "Paused"),
-        ("completed", "Completed"),
-        ("cancelled", "Cancelled"),
-    ),
+    choices=ModuleStatus.choices,
     default="planned",
     max_length=20,
 )

You could also use default=ModuleStatus.PLANNED for better semantic clarity.

apps/api/plane/api/serializers/project.py (1)

78-91: Consider optimizing database queries in create method.

The create method performs multiple database operations that could be optimized. Consider using get_or_create or bulk operations where appropriate.

 def create(self, validated_data):
     identifier = validated_data.get("identifier", "").strip().upper()
     if identifier == "":
         raise serializers.ValidationError(detail="Project Identifier is required")
 
-    if ProjectIdentifier.objects.filter(
-        name=identifier, workspace_id=self.context["workspace_id"]
-    ).exists():
-        raise serializers.ValidationError(detail="Project Identifier is taken")
+    # Use select_for_update to prevent race conditions
+    if ProjectIdentifier.objects.select_for_update().filter(
+        name=identifier, workspace_id=self.context["workspace_id"]
+    ).exists():
+        raise serializers.ValidationError(detail="Project Identifier is taken")
 
     project = Project.objects.create(
         **validated_data, workspace_id=self.context["workspace_id"]
     )
     return project
apps/api/plane/utils/openapi/hooks.py (1)

56-56: Consider handling edge cases in method mapping.

The fallback method summary is appropriate, but consider adding logging for unmapped methods to help with debugging.

-    return method_summaries.get(method, f"{method} {resource}")
+    summary = method_summaries.get(method, f"{method} {resource}")
+    # TODO: Consider logging unmapped HTTP methods for debugging
+    return summary
apps/api/plane/api/serializers/asset.py (1)

106-124: Add trailing comma for consistency

Add a trailing comma after the last element in the read_only_fields list for better diff readability and consistency with Python best practices.

        read_only_fields = [
            "id",
            "created_by",
            "updated_by",
            "created_at",
            "updated_at",
            "workspace",
            "project",
            "issue",
            "comment",
            "page",
            "draft_issue",
            "user",
            "is_deleted",
            "deleted_at",
            "storage_metadata",
            "asset_url",
-        ]
+        ]
apps/api/plane/utils/openapi/README.md (3)

7-16: Specify language for fenced code block

Add a language identifier to the fenced code block for proper syntax highlighting.

-```
+```text
plane/utils/openapi/
├── __init__.py          # Main module that re-exports everything
├── auth.py              # Authentication extensions
├── parameters.py        # Common OpenAPI parameters
├── responses.py         # Common OpenAPI responses
├── examples.py          # Common OpenAPI examples
├── decorators.py        # Helper decorators for different endpoint types
└── hooks.py            # Schema processing hooks (pre/post processing)

71-71: Remove trailing colon from heading

Remove the trailing punctuation from the heading to follow markdown best practices.

-### What was migrated:
+### What was migrated

81-81: Remove trailing colon from heading

Remove the trailing punctuation from the heading to follow markdown best practices.

-### Files updated:
+### Files updated
apps/api/plane/utils/openapi/examples.py (1)

1-817: Consider splitting this file for better maintainability

This file contains over 800 lines of example data. Consider splitting it into multiple files organized by domain (e.g., examples/issues.py, examples/cycles.py, examples/modules.py) to improve maintainability and make it easier to find specific examples.

Example structure:

examples/
├── __init__.py
├── issues.py      # Issue-related examples
├── cycles.py      # Cycle-related examples
├── modules.py     # Module-related examples
├── assets.py      # Asset-related examples
└── common.py      # Common/shared examples
apps/api/plane/api/views/member.py (1)

128-135: Optimize database queries

The current implementation makes two separate queries. Consider using a single query with select_related for better performance.

-        # Get the workspace members that are present inside the workspace
-        project_members = ProjectMember.objects.filter(
-            project_id=project_id, workspace__slug=slug
-        ).values_list("member_id", flat=True)
-
-        # Get all the users that are present inside the workspace
-        users = UserLiteSerializer(
-            User.objects.filter(id__in=project_members), many=True
-        ).data
+        # Get project members with user data in a single query
+        project_members = ProjectMember.objects.filter(
+            project_id=project_id, workspace__slug=slug
+        ).select_related("member")
+
+        # Serialize the users
+        users = UserLiteSerializer(
+            [pm.member for pm in project_members], many=True
+        ).data
apps/api/plane/api/urls/module.py (1)

29-30: Consider adding GET method for module-issue detail

The ModuleIssueDetailAPIEndpoint only supports DELETE operations. Consider adding GET to allow retrieving individual module-issue relationships for consistency with RESTful patterns.

-        ModuleIssueDetailAPIEndpoint.as_view(http_method_names=["delete"]),
+        ModuleIssueDetailAPIEndpoint.as_view(http_method_names=["get", "delete"]),
apps/api/plane/api/views/state.py (1)

154-154: Remove unnecessary parentheses

The extra parentheses around self.get_queryset() are redundant.

         return self.paginate(
             request=request,
-            queryset=(self.get_queryset()),
+            queryset=self.get_queryset(),
             on_results=lambda states: StateSerializer(
apps/api/plane/api/views/project.py (2)

293-293: Optimize by avoiding redundant database query

The project is queried again immediately after creation, which is unnecessary since you already have the instance from the serializer.

-project = self.get_queryset().filter(pk=serializer.instance.id).first()
+project = serializer.instance

If you need the annotations from get_queryset(), consider refactoring to apply them to the single instance rather than querying again.


484-484: Avoid redundant database query after update

Similar to the create method, this queries the project again unnecessarily.

-project = self.get_queryset().filter(pk=serializer.instance.id).first()
+project = serializer.instance
apps/api/plane/api/views/intake.py (1)

407-407: Remove redundant serializer instantiation

The IntakeIssueSerializer is instantiated twice for the same object.

-serializer = IntakeIssueUpdateSerializer(
+intake_serializer = IntakeIssueUpdateSerializer(
     intake_issue, data=request.data, partial=True
 )
 # ... rest of the code ...
-serializer = IntakeIssueSerializer(intake_issue)
+serializer = IntakeIssueSerializer(intake_issue)
 return Response(serializer.data, status=status.HTTP_200_OK)

Consider reusing the serializer or restructuring the logic to avoid redundancy.

Also applies to: 457-457

apps/api/plane/api/serializers/issue.py (2)

377-422: Robust URL validation with duplicate prevention.

The serializer implements comprehensive validation. Consider whether restricting to only http/https schemes is appropriate for all use cases - other schemes like ftp://, file://, or custom schemes might be valid for issue links.

If other URL schemes should be supported, consider making the allowed schemes configurable:

ALLOWED_URL_SCHEMES = getattr(settings, 'ISSUE_LINK_ALLOWED_SCHEMES', ['http://', 'https://'])

def validate_url(self, value):
    # Check URL format
    validate_url = URLValidator()
    try:
        validate_url(value)
    except ValidationError:
        raise serializers.ValidationError("Invalid URL format.")
    
    # Check URL scheme
    if not any(value.startswith(scheme) for scheme in ALLOWED_URL_SCHEMES):
        raise serializers.ValidationError(f"URL must start with one of: {', '.join(ALLOWED_URL_SCHEMES)}")
    
    return value

689-705: Consider field naming consistency with URL patterns.

The field names project__identifier and workspace__slug use double underscores, but according to the AI summary, URL parameters were standardized to use single underscores. Consider using project_identifier and workspace_slug for consistency.

class IssueSearchSerializer(serializers.Serializer):
    """
    Serializer for work item search result data formatting.

    Provides standardized search result structure including work item identifiers,
    project context, and workspace information for search API responses.
    """

    id = serializers.CharField(required=True, help_text="Issue ID")
    name = serializers.CharField(required=True, help_text="Issue name")
    sequence_id = serializers.CharField(required=True, help_text="Issue sequence ID")
-    project__identifier = serializers.CharField(
+    project_identifier = serializers.CharField(
        required=True, help_text="Project identifier"
    )
    project_id = serializers.CharField(required=True, help_text="Project ID")
-    workspace__slug = serializers.CharField(required=True, help_text="Workspace slug")
+    workspace_slug = serializers.CharField(required=True, help_text="Workspace slug")
apps/api/plane/api/views/cycle.py (2)

962-963: Fix comment to match the actual model name.

The comment refers to "CycleWorkItems" but the code uses "CycleIssue".

-# Get all CycleWorkItems already created
+# Get all CycleIssues already created
cycle_issues = list(
    CycleIssue.objects.filter(~Q(cycle_id=cycle_id), issue_id__in=issues)
)

1192-1636: Consider refactoring this extensive method for better maintainability.

This 400+ line method handles multiple responsibilities: validation, analytics calculation, progress snapshot creation, and issue transfer. Consider extracting helper methods for:

  • Analytics calculation (estimate and issue distribution)
  • Progress snapshot generation
  • Issue transfer logic

This would improve readability and testability.

apps/api/plane/utils/openapi/decorators.py (2)

13-26: Consider improving the merge function implementation

The current implementation reassigns kwargs after removing keys, which works but could be cleaner. Also, directly mutating the defaults dictionary could cause issues if it's reused.

Consider this cleaner implementation:

 def _merge_schema_options(defaults, kwargs):
     """Helper function to merge responses and parameters from kwargs into defaults"""
+    # Create a copy to avoid mutating the original defaults
+    merged = defaults.copy()
+    
     # Merge responses
     if "responses" in kwargs:
-        defaults["responses"].update(kwargs["responses"])
-        kwargs = {k: v for k, v in kwargs.items() if k != "responses"}
+        merged["responses"] = {**defaults.get("responses", {}), **kwargs["responses"]}
 
     # Merge parameters
     if "parameters" in kwargs:
-        defaults["parameters"].extend(kwargs["parameters"])
-        kwargs = {k: v for k, v in kwargs.items() if k != "parameters"}
+        merged["parameters"] = defaults.get("parameters", []) + kwargs["parameters"]
 
-    defaults.update(kwargs)
-    return defaults
+    # Add remaining kwargs (excluding responses and parameters)
+    merged.update({k: v for k, v in kwargs.items() if k not in ["responses", "parameters"]})
+    return merged

This approach:

  • Creates a copy to avoid side effects
  • Uses cleaner syntax without reassigning kwargs
  • Handles missing keys more gracefully

87-99: Ensure consistent tag naming for work item related endpoints

There's inconsistency in tag naming for work item related endpoints:

  • Line 90: "tags": ["Work Items"]
  • Line 135: "tags": ["Work Items"]
  • Line 165: "tags": ["Work Item Links"]
  • Line 180: "tags": ["Work Item Comments"]
  • Line 195: "tags": ["Work Item Activity"]
  • Line 210: "tags": ["Work Item Attachments"]

Consider standardizing to either singular or plural form consistently. The current mix might confuse API consumers when filtering by tags.

Also applies to: 132-144, 163-174, 177-189, 192-204, 207-219

apps/api/plane/utils/openapi/parameters.py (1)

35-40: Consider using unique example UUIDs for different entity types

All UUID parameters use the same example value "550e8400-e29b-41d4-a716-446655440000". Using different values would make the examples more realistic and help distinguish between entity types in the documentation.

For example:

  • Project: "550e8400-e29b-41d4-a716-446655440000"
  • Asset: "660e8400-e29b-41d4-a716-446655440001"
  • Cycle: "770e8400-e29b-41d4-a716-446655440002"
  • Module: "880e8400-e29b-41d4-a716-446655440003"
  • Issue: "990e8400-e29b-41d4-a716-446655440004"

Also applies to: 49-54, 94-99, 109-114, 125-129, 141-144, 155-159, 170-174, 186-190, 201-205, 216-220, 231-235, 246-250, 430-433

apps/api/plane/api/views/issue.py (1)

912-912: Standardize terminology in error messages

Error messages inconsistently use "work item" vs "Issue":

  • Line 912: "Only admin or creator can delete the work item"
  • Line 1540: "Work item comment with the same external id..."
  • Line 1697: "Work item comment with the same external id..."

While other parts of the code use "Issue".

Consider standardizing to either "work item" or "issue" throughout the codebase for consistency. Since the API documentation uses "Work Items" in tags, "work item" might be the preferred term.

Also applies to: 1540-1540, 1697-1697

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98a00f5 and 4e4416b.

📒 Files selected for processing (64)
  • apps/api/plane/api/apps.py (1 hunks)
  • apps/api/plane/api/serializers/__init__.py (1 hunks)
  • apps/api/plane/api/serializers/asset.py (1 hunks)
  • apps/api/plane/api/serializers/base.py (1 hunks)
  • apps/api/plane/api/serializers/cycle.py (5 hunks)
  • apps/api/plane/api/serializers/estimate.py (1 hunks)
  • apps/api/plane/api/serializers/intake.py (2 hunks)
  • apps/api/plane/api/serializers/issue.py (8 hunks)
  • apps/api/plane/api/serializers/module.py (5 hunks)
  • apps/api/plane/api/serializers/project.py (2 hunks)
  • apps/api/plane/api/serializers/state.py (2 hunks)
  • apps/api/plane/api/serializers/user.py (1 hunks)
  • apps/api/plane/api/serializers/workspace.py (1 hunks)
  • apps/api/plane/api/urls/__init__.py (1 hunks)
  • apps/api/plane/api/urls/asset.py (1 hunks)
  • apps/api/plane/api/urls/cycle.py (1 hunks)
  • apps/api/plane/api/urls/intake.py (1 hunks)
  • apps/api/plane/api/urls/issue.py (1 hunks)
  • apps/api/plane/api/urls/member.py (1 hunks)
  • apps/api/plane/api/urls/module.py (1 hunks)
  • apps/api/plane/api/urls/project.py (1 hunks)
  • apps/api/plane/api/urls/schema.py (1 hunks)
  • apps/api/plane/api/urls/state.py (1 hunks)
  • apps/api/plane/api/urls/user.py (1 hunks)
  • apps/api/plane/api/views/__init__.py (1 hunks)
  • apps/api/plane/api/views/asset.py (1 hunks)
  • apps/api/plane/api/views/base.py (2 hunks)
  • apps/api/plane/api/views/cycle.py (17 hunks)
  • apps/api/plane/api/views/intake.py (8 hunks)
  • apps/api/plane/api/views/issue.py (34 hunks)
  • apps/api/plane/api/views/member.py (1 hunks)
  • apps/api/plane/api/views/module.py (13 hunks)
  • apps/api/plane/api/views/project.py (9 hunks)
  • apps/api/plane/api/views/state.py (5 hunks)
  • apps/api/plane/api/views/user.py (1 hunks)
  • apps/api/plane/app/permissions/project.py (1 hunks)
  • apps/api/plane/app/views/analytic/advance.py (0 hunks)
  • apps/api/plane/app/views/workspace/cycle.py (0 hunks)
  • apps/api/plane/authentication/provider/oauth/github.py (1 hunks)
  • apps/api/plane/bgtasks/issue_activities_task.py (0 hunks)
  • apps/api/plane/db/management/commands/update_deleted_workspace_slug.py (0 hunks)
  • apps/api/plane/db/models/cycle.py (1 hunks)
  • apps/api/plane/db/models/intake.py (1 hunks)
  • apps/api/plane/db/models/module.py (1 hunks)
  • apps/api/plane/db/models/project.py (1 hunks)
  • apps/api/plane/db/models/user.py (1 hunks)
  • apps/api/plane/db/models/workspace.py (2 hunks)
  • apps/api/plane/settings/common.py (2 hunks)
  • apps/api/plane/settings/openapi.py (1 hunks)
  • apps/api/plane/space/serializer/__init__.py (1 hunks)
  • apps/api/plane/tests/conftest.py (1 hunks)
  • apps/api/plane/tests/conftest_external.py (0 hunks)
  • apps/api/plane/tests/contract/app/test_authentication.py (1 hunks)
  • apps/api/plane/tests/unit/models/test_workspace_model.py (1 hunks)
  • apps/api/plane/urls.py (2 hunks)
  • apps/api/plane/utils/openapi/README.md (1 hunks)
  • apps/api/plane/utils/openapi/__init__.py (1 hunks)
  • apps/api/plane/utils/openapi/auth.py (1 hunks)
  • apps/api/plane/utils/openapi/decorators.py (1 hunks)
  • apps/api/plane/utils/openapi/examples.py (1 hunks)
  • apps/api/plane/utils/openapi/hooks.py (1 hunks)
  • apps/api/plane/utils/openapi/parameters.py (1 hunks)
  • apps/api/plane/utils/openapi/responses.py (1 hunks)
  • apps/api/requirements/base.txt (1 hunks)
💤 Files with no reviewable changes (5)
  • apps/api/plane/db/management/commands/update_deleted_workspace_slug.py
  • apps/api/plane/app/views/workspace/cycle.py
  • apps/api/plane/tests/conftest_external.py
  • apps/api/plane/bgtasks/issue_activities_task.py
  • apps/api/plane/app/views/analytic/advance.py
🧰 Additional context used
🧠 Learnings (19)
apps/api/plane/tests/unit/models/test_workspace_model.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/urls/member.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/app/permissions/project.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/space/serializer/__init__.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/db/models/project.py (1)

Learnt from: vamsikrishnamathala
PR: #6820
File: web/core/hooks/use-timezone-converter.tsx:19-39
Timestamp: 2025-03-26T07:22:45.741Z
Learning: In the Plane project, the getProjectUTCOffset function in the timezone converter hook is designed to return undefined when there is no difference between the project's timezone and UTC (when offset is 0).

apps/api/plane/api/serializers/workspace.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/serializers/project.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/serializers/__init__.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/db/models/workspace.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/serializers/module.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/serializers/intake.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/serializers/asset.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/views/intake.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/serializers/cycle.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/views/project.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/views/member.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/urls/issue.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/serializers/issue.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

apps/api/plane/api/views/issue.py (1)

Learnt from: NarayanBavisetti
PR: #7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

🧬 Code Graph Analysis (1)
apps/api/plane/utils/openapi/responses.py (1)
apps/api/plane/utils/openapi/examples.py (1)
  • get_sample_for_schema (801-816)
🪛 markdownlint-cli2 (0.17.2)
apps/api/plane/utils/openapi/README.md

7-7: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


71-71: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


81-81: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🔇 Additional comments (87)
apps/api/plane/tests/unit/models/test_workspace_model.py (1)

4-4: ✅ Unused User import safely removed

User wasn’t referenced in this test, so dropping it tightens the import list without side-effects. LGTM.

apps/api/plane/authentication/provider/oauth/github.py (2)

21-21: Unnecessary f-string successfully removed – nice micro-cleanup.
The constant no longer incurs the runtime cost of evaluating an f-string, improving clarity.


131-135: Verify auth scheme & add timeout for org-membership check.

  1. GitHub accepts both token and Bearer schemes depending on the token type; confirm the correct one for OAuth-app tokens.
  2. Include a timeout to avoid blocking.
-headers = {"Authorization": f"Bearer {self.token_data.get('access_token')}"}
+headers = {
+    "Authorization": f"Bearer {self.token_data.get('access_token')}",  # change to 'token' if required
+    "Accept": "application/json",
+}
...
-response = requests.get(
+response = requests.get(
     f"{self.org_membership_url}/{self.organization_id}/memberships/{github_username}",
-    headers=headers,
+    headers=headers,
+    timeout=5,
 )
apps/api/plane/tests/contract/app/test_authentication.py (1)

9-9: Good cleanup of unused import.

The removal of MagicMock import is correct - all the test methods use the patch decorator which provides standard Mock objects that are sufficient for the test assertions being performed.

apps/api/plane/db/models/user.py (1)

104-104: Excellent improvement to timezone choices.

Switching from pytz.all_timezones to pytz.common_timezones is a smart decision that:

  • Reduces choice overload for users (from ~590 to ~400 options)
  • Eliminates deprecated and obscure timezones
  • Maintains consistency with similar changes in other models

This change is backward compatible and follows timezone selection best practices.

apps/api/plane/db/models/cycle.py (1)

74-74: Consistent timezone standardization.

The change to pytz.common_timezones aligns with the broader timezone standardization effort across models. This is particularly beneficial for cycles since they manage time-sensitive start and end dates.

apps/api/plane/api/serializers/base.py (1)

6-11: Excellent documentation addition.

The comprehensive docstring clearly explains the BaseSerializer's key features and purpose. This is particularly valuable given that this is a foundational class used throughout the application. The documentation accurately reflects the implementation and aligns with the broader API documentation enhancements in this PR.

apps/api/plane/api/apps.py (1)

7-12: Proper Django app initialization pattern.

The ready() method implementation follows Django best practices:

  • Correctly imports the OpenAPI auth module for side-effect registration
  • Uses appropriate try-except handling to prevent startup failures
  • Includes proper # noqa comment for the intentionally unused import

This aligns well with the broader OpenAPI integration effort described in the PR.

apps/api/plane/db/models/project.py (1)

123-123: Good improvement: Switching to common timezones for better UX.

This change from pytz.all_timezones to pytz.common_timezones is a practical improvement that reduces the timezone choices to a more manageable and user-friendly subset. This aligns with similar changes across other models (Cycle, User, Workspace) for consistency and improves the user experience by removing obscure/deprecated timezone options.

apps/api/plane/api/urls/__init__.py (1)

8-9: Clean integration of new URL patterns.

The addition of asset and user URL patterns follows the established pattern and supports the new asset management and user profile API endpoints mentioned in the PR objectives. The placement is logical with asset patterns at the beginning and user patterns at the end.

Also applies to: 12-12, 20-20

apps/api/requirements/base.txt (1)

68-69: drf-spectacular version is up to date

The project specifies drf-spectacular==0.28.0 (apps/api/requirements/base.txt, lines 68–69), which matches the latest stable release on PyPI as of November 30, 2024. No update is required.

apps/api/plane/api/urls/state.py (1)

3-6: Excellent RESTful API restructuring.

The separation of state endpoints into distinct list-create and detail operations with explicit HTTP method restrictions follows excellent RESTful design principles. This improves API clarity, security, and aligns with the broader API restructuring effort described in the PR objectives.

Also applies to: 11-11, 16-16

apps/api/plane/space/serializer/__init__.py (1)

3-3: Good cleanup: Removing unnecessary serializer imports.

The removal of StateLiteSerializer from both .issue and .state module imports is a good cleanup that reduces unnecessary dependencies and aligns with the broader serializer modularization effort described in the PR objectives.

Also applies to: 5-5

apps/api/plane/api/urls/member.py (1)

8-8: Good restriction to GET-only methods.

The explicit restriction to GET methods aligns well with the refactoring effort to separate concerns and remove member creation functionality from this endpoint.

apps/api/plane/api/serializers/estimate.py (1)

7-12: Excellent documentation enhancement.

The detailed docstring clearly explains the serializer's purpose and context, making it easier for developers to understand how estimation points are used in sprint planning and velocity calculations.

apps/api/plane/api/urls/user.py (1)

1-11: Clean and well-structured user endpoint configuration.

The URL pattern follows REST conventions with "users/me/" for current user profile access, appropriately restricted to GET requests. This fits well with the API restructuring objectives.

apps/api/plane/db/models/workspace.py (1)

3-3: LGTM: Clean import optimization

Good cleanup removing unused type imports (Tuple, Dict) and other unused imports mentioned in the summary. This improves code maintainability and reduces unnecessary dependencies.

apps/api/plane/app/permissions/project.py (1)

78-83: LGTM: Consistent project identifier attribute naming

The change from project__identifier to project_identifier standardizes the view attribute naming and aligns with the broader API refactoring. The permission logic remains functionally equivalent while improving consistency across the codebase.

apps/api/plane/api/serializers/workspace.py (1)

7-12: Excellent documentation enhancement

The expanded docstring clearly explains the serializer's purpose, scope, and intended use cases. This improves API discoverability and aligns with the comprehensive OpenAPI documentation improvements across the codebase.

apps/api/plane/api/urls/intake.py (2)

3-6: LGTM: Proper endpoint separation

Splitting the monolithic endpoint into specialized ListCreate and Detail endpoints follows RESTful design principles and improves code organization as outlined in the PR objectives.


12-19: Excellent HTTP method restrictions

Explicitly restricting HTTP methods per endpoint (GET/POST for collection, GET/PATCH/DELETE for individual resources) improves API clarity and security by preventing unintended operations.

apps/api/plane/api/views/user.py (3)

14-17: LGTM: Clean class structure

The endpoint class follows Django REST framework best practices with proper inheritance from BaseAPIView and clear model/serializer declarations.


18-29: Excellent OpenAPI documentation

Comprehensive OpenAPI decoration with operation ID, summary, description, and response examples. This exemplifies the thorough documentation approach mentioned in the PR objectives and improves API discoverability.


30-37: Simple and effective implementation

The GET method implementation is straightforward and secure, using the authenticated user from the request context. The clear docstring and proper status code usage follow best practices.

apps/api/plane/api/urls/schema.py (1)

1-21: Well-structured OpenAPI schema configuration.

The URL configuration follows drf-spectacular best practices with proper endpoint separation and correct view references. The schema UI views correctly reference the base schema endpoint by name, enabling proper documentation generation.

apps/api/plane/api/views/base.py (2)

16-16: Excellent foundation for the API refactoring.

The switch from APIView to GenericAPIView provides the necessary foundation for the endpoint separation strategy mentioned in the PR objectives. This enables better support for mixins, serializer integration, and the granular view classes being introduced.


39-39: Proper inheritance structure maintained.

The class definition correctly maintains the existing mixin and paginator functionality while upgrading to the more capable GenericAPIView base class.

apps/api/plane/urls.py (2)

5-9: Good import organization for optional feature.

The drf-spectacular imports are properly organized and will only be used when the feature is enabled.


22-35: Excellent feature gating implementation.

The conditional inclusion of schema URLs based on ENABLE_DRF_SPECTACULAR is a best practice for optional features. The URL structure follows standard conventions and maintains consistency with the schema configuration.

apps/api/plane/api/urls/project.py (2)

3-7: Improved endpoint separation aligns with PR objectives.

The split from a single generic endpoint to specific list/create, detail, and archive/unarchive endpoints exemplifies the refactoring goals mentioned in the PR summary. This separation improves maintainability and follows RESTful design principles.


10-27: Excellent HTTP method restrictions and URL structure.

The explicit http_method_names restrictions provide clear API boundaries and improve security. The URL patterns are now more RESTful and self-documenting with proper separation of concerns.

apps/api/plane/api/serializers/state.py (3)

7-12: Excellent documentation for StateSerializer.

The comprehensive docstring clearly explains the serializer's role in state management, including its handling of default state validation and automatic switching behavior. This improves code maintainability and developer understanding.


34-34: Proper field protection for slug.

Adding slug to read_only_fields prevents unintended modification of this system-generated field, which is a good security and data integrity practice.


39-44: Clear documentation for lightweight serializer.

The docstring effectively communicates the StateLiteSerializer's purpose for minimal data transfer and UI optimization, helping developers choose the appropriate serializer for their use case.

apps/api/plane/api/urls/asset.py (1)

9-40: Excellent RESTful URL structure with proper HTTP method restrictions.

The URL patterns demonstrate good separation of concerns:

  • Clear distinction between creation endpoints (POST only) and detail endpoints (PATCH/DELETE or GET/PATCH)
  • Consistent naming conventions for user assets, user server assets, and generic workspace assets
  • Appropriate use of UUID parameters for asset identification and string slugs for workspace identification

The explicit HTTP method restrictions using http_method_names parameter enhance security by preventing unintended HTTP methods on each endpoint.

apps/api/plane/api/serializers/user.py (1)

10-20: Well-documented serializer enhancement.

The added docstring clearly explains the serializer's purpose and use cases, and the new avatar_url field with proper help text enhances the API's functionality for avatar handling.

apps/api/plane/api/urls/cycle.py (2)

3-10: Excellent endpoint refactoring for better separation of concerns.

The import changes reflect the proper splitting of monolithic endpoints into focused, method-specific classes that follow single responsibility principle.


13-52: Well-structured RESTful URL patterns with explicit HTTP method restrictions.

The refactoring demonstrates several improvements:

  1. Clear separation: List/create operations are distinct from detail operations
  2. Explicit methods: Each endpoint clearly defines allowed HTTP methods
  3. Consistent patterns: All cycle-related endpoints follow the same structural approach
  4. Enhanced functionality: New archived cycles endpoints provide additional capabilities

The URL structure aligns perfectly with REST principles and improves API maintainability.

apps/api/plane/api/views/__init__.py (1)

1-56: Comprehensive import reorganization reflecting improved API architecture.

The expanded and reorganized imports demonstrate the successful modularization of the API:

  1. Granular separation: Monolithic endpoints split into focused list/create and detail classes
  2. Enhanced coverage: New domains added (assets, intake, user endpoints)
  3. Clear structure: Import organization makes the API's capabilities immediately apparent
  4. Consistent patterns: All resource types follow the same separation approach

This centralized import structure serves as an excellent overview of the refactored API's capabilities and maintains clean separation of concerns.

apps/api/plane/settings/common.py (1)

78-80: Good addition for preserving original URL parameter names.

The SCHEMA_COERCE_PATH_PK: False setting is valuable for maintaining consistency between Django URL patterns and generated API schemas, preventing automatic conversion of "pk" parameters to "id".

apps/api/plane/api/serializers/__init__.py (4)

3-8: LGTM! Proper serializer exposure for project operations.

The addition of ProjectCreateSerializer and ProjectUpdateSerializer aligns well with the API refactoring goals of separating concerns between create and update operations.


11-24: Comprehensive issue serializer imports support enhanced functionality.

The expanded issue serializer imports provide good separation of concerns with dedicated serializers for different operations (create, update, upload, search). This modular approach improves maintainability.


26-47: Well-structured module imports follow consistent patterns.

The cycle, module, and intake serializer imports follow a consistent naming pattern with dedicated create/update serializers, which supports the overall API restructuring effort.


49-55: New asset management serializers enhance file handling capabilities.

The asset serializer imports support the new presigned URL functionality mentioned in the PR objectives, providing secure file upload workflows.

apps/api/plane/settings/openapi.py (4)

7-32: Well-structured basic API configuration with appropriate settings.

The API metadata is comprehensive and the schema generation settings are properly configured. Disabling caching (SCHEMA_CACHE_TIMEOUT: 0) is appropriate for development but consider enabling it in production for performance.


49-256: Excellent and comprehensive API tag documentation.

The tag definitions are exceptionally well-written with clear descriptions, key features, and use cases. This will greatly improve API discoverability and developer experience.


268-271: Enum overrides configuration is well-structured.

The enum name overrides for ModuleStatusEnum and IntakeWorkItemStatusEnum provide better OpenAPI schema readability.


260-262: Verification complete: authentication class path is correct.

The plane.api.middleware.api_authentication.APIKeyAuthentication class is defined in apps/api/plane/api/middleware/api_authentication.py and matches the whitelist entry. No further changes are needed.

apps/api/plane/utils/openapi/auth.py (2)

11-29: Well-implemented API key authentication extension.

The APIKeyAuthenticationExtension is properly configured with appropriate security definition for API key authentication via the X-API-Key header.


32-49: Proper bearer token authentication configuration.

The APITokenAuthenticationExtension correctly implements bearer token authentication with appropriate OpenAPI security definition.

apps/api/plane/api/serializers/project.py (6)

5-11: Appropriate model imports for enhanced validation.

The additional imports (ProjectIdentifier, WorkspaceMember, State, Estimate) support the enhanced validation logic in the new serializers.


16-54: Well-structured ProjectCreateSerializer with comprehensive field definition.

The serializer properly defines all necessary fields for project creation with appropriate read-only field restrictions.


55-76: Robust validation for workspace membership.

The validation logic properly ensures both project lead and default assignee are workspace members. This aligns with the retrieved learning about workspace member validation in the Plane codebase.


94-135: Excellent ProjectUpdateSerializer with proper validation extensions.

The update serializer properly extends the create serializer and adds specific validation for default state and estimate references. The validation logic correctly ensures referenced objects belong to the project.


138-143: Good documentation addition to existing ProjectSerializer.

The added docstring clearly describes the serializer's purpose and functionality.


218-223: Appropriate documentation for ProjectLiteSerializer.

The docstring accurately describes the lightweight nature and intended use cases of this serializer.

apps/api/plane/utils/openapi/hooks.py (4)

10-23: Solid endpoint filtering logic with minor suggestions.

The filtering function correctly targets /api/v1/ paths and excludes unwanted methods and server paths. The logic is sound and performant.


26-36: Robust path processing with good edge case handling.

The path parsing logic properly handles empty parts and parameter placeholders. The fallback to using the tag when no path parts are found is a good defensive programming practice.


38-44: Complete HTTP method coverage with clear mappings.

The method summary mappings cover all standard HTTP methods with appropriate action verbs.


46-54: Smart special case handling for archive and transfer operations.

The special handling for archive/unarchive and transfer operations provides more intuitive operation summaries. The rstrip("s") approach for singularizing tag names is simple and effective for most cases.

apps/api/plane/api/serializers/asset.py (2)

41-52: LGTM!

The AssetUpdateSerializer is well-designed with appropriate use of JSONField for flexible attribute storage.


80-91: LGTM!

The GenericAssetUpdateSerializer is simple and well-designed for its purpose.

apps/api/plane/api/serializers/intake.py (5)

8-33: LGTM!

The IssueForIntakeSerializer is well-designed with appropriate field selection and read-only constraints for audit fields.


35-65: LGTM!

The IntakeIssueCreateSerializer properly implements nested serialization with clear field definitions and appropriate read-only constraints.


67-91: LGTM!

Excellent addition of the docstring to improve documentation. The serializer properly handles expanded issue details and intake relationships.


93-124: LGTM!

The IntakeIssueUpdateSerializer correctly implements partial update functionality with optional nested issue updates.


126-141: LGTM!

The IssueDataSerializer appropriately uses a plain serializer for request validation with proper field constraints and choice validation.

apps/api/plane/api/serializers/module.py (3)

198-220: LGTM!

The ModuleIssueSerializer is well-documented and properly structured for managing module-issue relationships.


254-265: LGTM!

The ModuleLiteSerializer is well-documented and appropriately designed for lightweight data transfer.


267-279: LGTM!

The ModuleIssueRequestSerializer is well-designed for bulk issue assignment operations with proper validation.

apps/api/plane/utils/openapi/examples.py (1)

801-817: LGTM!

The get_sample_for_schema function is well-implemented with proper handling of paginated response schemas.

apps/api/plane/api/serializers/cycle.py (2)

11-81: Well-structured timezone-aware serializer

The CycleCreateSerializer implementation is excellent with proper timezone handling, date validation, and UTC conversion. The separation of concerns and comprehensive validation logic follows best practices.


98-185: Well-designed serializer architecture

The remaining serializers (CycleSerializer, CycleIssueSerializer, CycleLiteSerializer, CycleIssueRequestSerializer, and TransferCycleIssueRequestSerializer) are well-structured with clear separation of concerns, comprehensive documentation, and appropriate field definitions for their respective use cases.

apps/api/plane/api/views/asset.py (1)

405-630: Well-implemented generic asset management

The GenericAssetEndpoint implementation is comprehensive with proper validation, external ID conflict detection, workspace verification, and secure presigned URL generation. The error handling is appropriately granular.

apps/api/plane/utils/openapi/responses.py (1)

378-378: Ignore unnecessary serializer-instantiation concern

We’ve verified that no serializers passed into create_paginated_response override __init__ to require positional arguments—every one inherits DRF’s default signature, which defaults all parameters. Instantiating with item_schema() is safe for spectacular’s schema generation.

Likely an incorrect or invalid review comment.

apps/api/plane/api/serializers/issue.py (7)

37-43: Excellent documentation addition!

The comprehensive docstring clearly explains the serializer's purpose and capabilities, improving code maintainability.


309-316: Clear and concise documentation for the lightweight serializer.

The docstring effectively communicates the performance-oriented purpose of this serializer.


323-353: Well-structured serializer following REST best practices.

The separation of create/update operations into a dedicated serializer improves API clarity and follows the single responsibility principle.


354-361: Good documentation that clarifies the serializer's comprehensive nature.

The docstring effectively distinguishes this full serializer from the create/update variant.


454-476: Clean implementation of the full link serializer.

Follows the established pattern of having dedicated serializers for different operations.


477-667: Comprehensive documentation improvements across all serializers.

The consistent addition of descriptive docstrings significantly improves code maintainability and API documentation.


669-688: Well-designed file upload validation serializer.

The serializer provides clear field documentation and validates essential metadata before file upload operations.

apps/api/plane/api/views/cycle.py (1)

171-288: Well-structured cycle filtering with comprehensive statistics.

The implementation provides flexible filtering options and detailed issue count annotations. The pagination is properly applied to all views except "current" which returns all current cycles.

apps/api/plane/api/urls/issue.py (1)

20-95: Excellent URL restructuring with clear HTTP method restrictions.

The refactoring improves API clarity by:

  • Explicitly defining allowed HTTP methods for each endpoint
  • Separating list/create from detail operations
  • Adding semantic search functionality
  • Maintaining consistent parameter naming with single underscores
apps/api/plane/api/views/module.py (1)

546-915: Well-implemented module issue management endpoints.

The module issue endpoints follow consistent patterns with proper:

  • Bulk operation handling
  • Activity tracking
  • Permission checks
  • Optimized querysets with annotations
apps/api/plane/api/views/issue.py (2)

149-223: Well-structured workspace-level issue retrieval endpoint

The refactored WorkspaceIssueAPIEndpoint with proper OpenAPI documentation and clear parameter handling is a significant improvement. The endpoint now properly uses project and issue identifiers for workspace-level access.


2258-2333: Well-implemented semantic search functionality

The new IssueSearchEndpoint provides excellent search capabilities with:

  • Smart regex matching for sequence IDs
  • Flexible workspace/project scoping
  • Efficient query construction using Q objects

The implementation is clean and follows best practices.

…esponse handling, removing redundant external ID checks and custom ordering logic.
@sriramveeraghanta sriramveeraghanta changed the title Restructuring of the external API code for better maintainability [WEB-4045] feat: restructuring of the external APIs for better maintainability Jul 24, 2025
@makeplane
Copy link

makeplane bot commented Jul 24, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

@sriramveeraghanta sriramveeraghanta merged commit 514686d into preview Jul 24, 2025
4 of 6 checks passed
@sriramveeraghanta sriramveeraghanta deleted the openapi-specification branch July 24, 2025 18:47
lifeiscontent pushed a commit that referenced this pull request Aug 18, 2025
…inability (#7477)

* Basic setup for drf-spectacular

* Updated to only handle /api/v1 endpoints

* feat: add asset and user endpoints with URL routing

- Introduced new asset-related endpoints for user assets and server assets, allowing for asset uploads and management.
- Added user endpoint to retrieve current user information.
- Updated URL routing to include new asset and user patterns.
- Enhanced issue handling with a new search endpoint for issues across multiple fields.
- Expanded member management with a new endpoint for workspace members.

* Group endpoints by tags

* Detailed schema definitions and examples for asset endpoints

* Removed unnecessary extension

* Specify avatar_url field separately

* chore: add project docs

* chore: correct all errors

* chore: added open spec in work items

* feat: enhance cycle API endpoints with detailed OpenAPI specifications

- Updated CycleAPIEndpoint and CycleIssueAPIEndpoint to include detailed OpenAPI schema definitions for GET, POST, PATCH, and DELETE operations.
- Specified allowed HTTP methods for each endpoint in the URL routing.
- Improved documentation for cycle creation, updating, and deletion, including request and response examples.

* chore: added open spec in labels

* chore: work item properties

* feat: enhance API endpoints with OpenAPI specifications and HTTP method definitions

- Added detailed OpenAPI schema definitions for various API endpoints including Intake, Module, and State.
- Specified allowed HTTP methods for each endpoint in the URL routing for better clarity and documentation.
- Improved request and response examples for better understanding of API usage.
- Introduced unarchive functionality for cycles and modules with appropriate endpoint definitions.

* chore: run formatter

* Removed unnecessary settings for authentication

* Refactors OpenAPI documentation structure

Improves the organization and maintainability of the OpenAPI documentation by modularizing the `openapi_spec_helpers.py` file.

The changes include:
- Migrates common parameters, responses, examples, and authentication extensions to separate modules.
- Introduces helper decorators for different endpoint types.
- Updates view imports to use the new module paths.
- Removes the legacy `openapi_spec_helpers.py` file.

This refactoring results in a more structured and easier-to-maintain OpenAPI documentation setup.

* Refactor OpenAPI endpoint specifications

- Removed unnecessary parameters from the OpenAPI documentation for various endpoints in the asset, cycle, and project views.
- Updated request structures to improve clarity and consistency across the API documentation.
- Enhanced response formatting for better readability and maintainability.

* Enhance API documentation with detailed endpoint descriptions

Updated various API endpoints across the application to include comprehensive docstrings that clarify their functionality. Each endpoint now features a summary and detailed description, improving the overall understanding of their purpose and usage. This change enhances the OpenAPI specifications for better developer experience and documentation clarity.

* Enhance API serializers and views with new request structures

- Added new serializers for handling cycle and module issue requests, including `CycleIssueRequestSerializer`, `TransferCycleIssueRequestSerializer`, `ModuleIssueRequestSerializer`, and intake issue creation/updating serializers.
- Updated existing serializers to improve clarity and maintainability, including the `UserAssetUploadSerializer` and `IssueAttachmentUploadSerializer`.
- Refactored API views to utilize the new serializers, enhancing the request handling for cycle and intake issue endpoints.
- Improved OpenAPI documentation by replacing inline request definitions with serializer references for better consistency and readability.

* Refactor OpenAPI documentation and endpoint specifications

- Replaced inline schema definitions with dedicated decorators for various endpoint types, enhancing clarity and maintainability.
- Updated API views to utilize new decorators for user, cycle, intake, module, and project endpoints, improving consistency in OpenAPI documentation.
- Removed unnecessary parameters and responses from endpoint specifications, streamlining the documentation for better readability.
- Enhanced the organization of OpenAPI documentation by modularizing endpoint-specific decorators and parameters.

* chore: correct formatting

* chore: correct formatting for all api folder files

* refactor: clean up serializer imports and test setup

- Removed unused `StateLiteSerializer` import from the serializer module.
- Updated test setup to include a noqa comment for the `django_db_setup` fixture, ensuring clarity in the code.
- Added missing commas in user data dictionary for consistency.

* feat: add project creation and update serializers with validation

- Introduced `ProjectCreateSerializer` and `ProjectUpdateSerializer` to handle project creation and updates, respectively.
- Implemented validation to ensure project leads and default assignees are members of the workspace.
- Updated API views to utilize the new serializers for creating and updating projects, enhancing request handling.
- Added OpenAPI documentation references for the new serializers in the project API endpoints.

* feat: update serializers to include additional read-only fields

* refactor: rename intake issue serializers and enhance structure

- Renamed `CreateIntakeIssueRequestSerializer` to `IntakeIssueCreateSerializer` and `UpdateIntakeIssueRequestSerializer` to `IntakeIssueUpdateSerializer` for clarity.
- Introduced `IssueSerializer` for nested issue data in intake requests, improving the organization of serializer logic.
- Updated API views to utilize the new serializer names, ensuring consistency across the codebase.

* refactor: rename issue serializer for intake and enhance API documentation

- Renamed `IssueSerializer` to `IssueForIntakeSerializer` for better clarity in the context of intake issues.
- Updated references in `IntakeIssueCreateSerializer` and `IntakeIssueUpdateSerializer` to use the new `IssueForIntakeSerializer`.
- Added OpenAPI documentation for the `get_workspace_work_item` endpoint, detailing parameters and responses for improved clarity.

* chore: modules and cycles serializers

* feat: add new serializers for label and issue link management

- Introduced `LabelCreateUpdateSerializer`, `IssueLinkCreateSerializer`, `IssueLinkUpdateSerializer`, and `IssueCommentCreateSerializer` to enhance the handling of label and issue link data.
- Updated existing API views to utilize the new serializers for creating and updating labels, issue links, and comments, improving request handling and validation.
- Added `IssueSearchSerializer` for searching issues, streamlining the search functionality in the API.

* Don't consider read only fields as required

* Add setting to separate request and response definitions

* Fixed avatar_url warning on openapi spec generation

* Made spectacular disabled by default

* Moved spectacular settings into separate file and added detailed descriptions to tags

* Specify methods for asset urls

* Better server names

* Enhance API documentation with summaries for various endpoints

- Added summary descriptions for user asset, cycle, intake, issue, member, module, project, state, and user API endpoints to improve clarity and usability of the API documentation.
- Updated the OpenAPI specifications to reflect these changes, ensuring better understanding for developers interacting with the API.

* Add contact information to OpenAPI settings

- Included contact details for Plane in the OpenAPI settings to enhance API documentation and provide developers with a direct point of contact for support.
- This addition aims to improve the overall usability and accessibility of the API documentation.

* Reordered tags and improved description relavancy

* Enhance OpenAPI documentation for cycle and issue endpoints

- Added response definitions for the `get_cycle_issues` and `delete_cycle_issue` methods in the CycleIssueAPIEndpoint to clarify expected outcomes.
- Included additional response codes for the IssueSearchEndpoint to handle various error scenarios, improving the overall API documentation and usability.

* Enhance serializer documentation across multiple files

- Updated docstrings for various serializers including UserAssetUploadSerializer, AssetUpdateSerializer, and others to provide clearer descriptions of their functionality and usage.
- Improved consistency in formatting and language across serializer classes to enhance readability and maintainability.
- Added detailed explanations for new serializers related to project, module, and cycle management, ensuring comprehensive documentation for developers.

* Refactor API endpoints for cycles, intake, modules, projects, and states

- Replaced existing API endpoint classes with more descriptive names such as CycleListCreateAPIEndpoint, CycleDetailAPIEndpoint, IntakeIssueListCreateAPIEndpoint, and others to enhance clarity.
- Updated URL patterns to reflect the new endpoint names, ensuring consistency across the API.
- Improved documentation and method summaries for better understanding of endpoint functionalities.
- Enhanced query handling in the new endpoint classes to streamline data retrieval and improve performance.

* Refactor issue and label API endpoints for clarity and functionality

- Renamed existing API endpoint classes to more descriptive names such as IssueListCreateAPIEndpoint, IssueDetailAPIEndpoint, LabelListCreateAPIEndpoint, and LabelDetailAPIEndpoint to enhance clarity.
- Updated URL patterns to reflect the new endpoint names, ensuring consistency across the API.
- Improved method summaries and documentation for better understanding of endpoint functionalities.
- Streamlined query handling in the new endpoint classes to enhance data retrieval and performance.

* Refactor asset API endpoint methods and introduce new status enums

- Updated the GenericAssetEndpoint to only allow POST requests for asset creation, removing the GET method.
- Modified the get method to require asset_id, ensuring that asset retrieval is always tied to a specific asset.
- Added new IntakeIssueStatus and ModuleStatus enums to improve clarity and management of asset and module states.
- Enhanced OpenAPI settings to include these new enums for better documentation and usability.

* enforce naming convention

* Added LICENSE to openapi spec

* Enhance OpenAPI documentation for various API endpoints

- Updated API endpoints in asset, cycle, intake, issue, module, project, and state views to include OpenApiRequest and OpenApiExample for better request documentation.
- Added example requests for creating and updating resources, improving clarity for API consumers.
- Ensured consistent use of OpenApi utilities across all relevant endpoints to enhance overall API documentation quality.

* Enhance OpenAPI documentation for various API endpoints

- Added detailed descriptions to multiple API endpoints across asset, cycle, intake, issue, module, project, state, and user views to improve clarity for API consumers.
- Ensured consistent documentation practices by including descriptions that outline the purpose and functionality of each endpoint.
- This update aims to enhance the overall usability and understanding of the API documentation.

* Update OpenAPI examples and enhance project queryset logic

- Changed example fields in OpenAPI documentation for issue comments from "content" to "comment_html" to reflect the correct structure.
- Introduced a new `get_queryset` method in the ProjectDetailAPIEndpoint to filter projects based on user membership and workspace, while also annotating additional project-related data such as total members, cycles, and modules.
- Updated permission checks to use the correct attribute name for project identifiers, ensuring accurate permission handling.

* Enhance OpenAPI documentation and add response examples

- Updated multiple API endpoints across asset, cycle, intake, issue, module, project, state, and user views to include new OpenApiResponse examples for better clarity on expected outcomes.
- Introduced new parameters for project and issue identifiers to improve request handling and documentation consistency.
- Enhanced existing responses with detailed examples to aid API consumers in understanding the expected data structure and error handling.
- This update aims to improve the overall usability and clarity of the API documentation.

* refactor: update terminology from 'issues' to 'work items' across multiple API endpoints for consistency and clarity

* use common timezones from pytz for choices

* Moved the openapi utils to the new folder structure

* Added exception logging in GenericAssetEndpoint to improve error handling

* Fixed code rabbit suggestions

* Refactored IssueDetailAPIEndpoint to streamline issue retrieval and response handling, removing redundant external ID checks and custom ordering logic.

---------

Co-authored-by: pablohashescobar <[email protected]>
Co-authored-by: NarayanBavisetti <[email protected]>
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.

5 participants