Skip to content

Conversation

@adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented Jul 11, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a Deployments dashboard with searchable, collapsible tables showing deployable versions, job statuses, and related links for each release target.
    • Added detailed release target pages displaying deployment history, latest and in-progress versions, and environment details.
    • Enabled pinning and unpinning of deployment versions, as well as force deploying specific versions, all with user-friendly dialogs and feedback.
    • Improved job status visibility with tooltips showing policy evaluation details.
    • Added a grid-based overview of release targets for each resource.
  • Improvements

    • Enhanced navigation with updated sidebar labels and icons.
    • Streamlined job links and deployment actions into reusable components for a more consistent user experience.
  • Bug Fixes

    • Improved handling of loading and empty states across deployment and job tables.
  • Chores

    • Updated URL structure to support nested deployment and release target navigation.
    • Added new API endpoints for deployment version management, including listing, pinning, unpinning, and force deploying versions.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 11, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces a new deployment management UI and backend for release targets. It adds granular version pinning, force deploy, and job status features, replaces the release history table with a tile-based deployments overview, and implements new API endpoints for listing, pinning, unpinning, and forcibly deploying versions. Several new React components and backend procedures support these capabilities.

Changes

File(s) / Area Change Summary
.../jobs/_components/EnvironmentTableRow.tsx Updated import path for CollapsibleRow to reference a shared components directory.
.../jobs/_components/PolicyEvaluationTooltip.tsx
.../jobs/_components/ReleaseTargetRow.tsx
Refactored policy evaluation UI: replaced PolicyEvaluationHover with PolicyEvaluationTooltip, improved tooltip logic, and updated job status cell usage.
.../job/JobLinks.tsx Added new JobLinks component to render job-related external links.
.../resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx New component for displaying a searchable, collapsible table of deployment versions and jobs for a release target.
.../ForceDeployVersion.tsx New dialog component to force deploy a specific version to a release target.
.../HeaderRow.tsx
.../JobRow.tsx
.../JobStatusCell.tsx
.../VersionDropdown.tsx
.../VersionPinning.tsx
Added new components for table rows, job status, version dropdown with pin/unpin dialogs, and version pinning/unpinning dialogs.
.../layout.tsx
.../page.tsx
.../types.ts
.../useVersionSearch.ts
Added layout, page, type definitions, and a search hook for the release target deployments page.
.../deployments/_components/ReleaseHistoryTable.tsx Deleted the old release history table component.
.../deployments/_components/ReleaseTargetTile.tsx New tile component for displaying release target summary, latest and in-progress versions, and navigation actions.
.../deployments/page.tsx Switched from table to grid layout: replaced ReleaseHistoryTable with a grid of ReleaseTargetTile components.
.../deployments/layout.tsx Updated sidebar: changed "Release History" to "Deployments" with new icon and URL.
.../sidebars.ts Added ReleaseTarget enum value to Sidebars.
.../urls.ts Introduced URL builders for resource deployments and release targets, refactored resource URL structure.
packages/api/src/router/release-target-version/force-deploy-version.ts Added backend procedure for forcibly deploying a version to a release target.
.../in-progress-version.ts
.../latest-version.ts
.../list-deployable-versions.ts
Added backend procedures for fetching in-progress, latest, and deployable versions for a release target.
.../router.ts Introduced releaseTargetVersionRouter aggregating version-related endpoints.
.../utils.ts Added utility for fetching detailed release target info with joins.
.../version-pinning.ts Added procedures for pinning and unpinning deployment versions on release targets.
.../release-target.ts Extended router: added nested version router and procedure for fetching release target by ID with joined relations.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WebApp
    participant API
    participant DB
    participant Queue

    User->>WebApp: Navigate to Deployments page
    WebApp->>API: Fetch release targets
    API->>DB: Query releaseTarget (with joins)
    DB-->>API: Release target data
    API-->>WebApp: Release target data
    WebApp->>API: Fetch versions and jobs for release target
    API->>DB: Query deploymentVersion, job tables
    DB-->>API: Version/job data
    API-->>WebApp: Version/job data
    User->>WebApp: Click "Pin Version" or "Force Deploy"
    WebApp->>API: Call pinVersion/forceDeployVersion
    API->>DB: Update or insert pin/force deploy records
    API->>Queue: Enqueue evaluation or deploy job
    Queue-->>API: Ack
    API-->>WebApp: Success response
Loading

Possibly related PRs

  • ctrlplanedev/ctrlplane#468: Introduced the CollapsibleRow component, which is now referenced by a new import path in this PR.
  • ctrlplanedev/ctrlplane#604: Implemented version pinning functionality for release targets, directly related to the new pin/unpin API and UI in this PR.
  • ctrlplanedev/ctrlplane#611: Added the original PolicyEvaluationHover component and its usage, now refactored and replaced by PolicyEvaluationTooltip in this PR.

Suggested reviewers

  • jsbroks

Poem

In the meadow of code, new features sprout,
Deployments now sparkle, no more doubt!
Pin, force, or view—each version’s a delight,
Tiles and tooltips shining bright.
With every hop, a job status anew—
This bunny’s proud of what the team can do!
🐇✨🚀


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96b38fb and 3977696.

📒 Files selected for processing (3)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/EnvironmentTableRow.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx (7 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

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 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.

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.

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: 6

🧹 Nitpick comments (4)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (2)

14-15: Consider adding content or semantic meaning to empty table cells.

The component has empty TableCell elements that might indicate missing functionality or create accessibility issues. Consider adding appropriate content, using proper table headers, or adding semantic attributes if these cells are intentionally empty.

Also applies to: 25-25


13-13: Fixed height may cause layout issues with varying content.

The fixed height of 49px might cause content overflow or layout inconsistencies if job data varies significantly. Consider using flexible sizing or ensuring content constraints.

packages/api/src/router/release-target-version/utils.ts (1)

5-9: Consider consolidating duplicate type definitions.

The ReleaseTarget type is defined both here and in apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts. Consider moving this to a shared location or importing from a common types file to maintain consistency and avoid duplication.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx (1)

21-48: Consider using async/await for cleaner error handling.

The promise chaining works but could be more readable with async/await pattern.

- const onSubmit = () =>
-   forceDeploy
-     .mutateAsync({ releaseTargetId, versionId })
-     .then(() => setOpen(false))
-     .then(() => router.refresh())
-     .then(() => invalidate())
-     .then(() =>
-       toast.success(`Force deployed ${releaseTarget.resource.name}`),
-     )
-     .catch(() =>
-       toast.error(`Failed to force deploy ${releaseTarget.resource.name}`),
-     );
+ const onSubmit = async () => {
+   try {
+     await forceDeploy.mutateAsync({ releaseTargetId, versionId });
+     setOpen(false);
+     router.refresh();
+     await invalidate();
+     toast.success(`Force deployed ${releaseTarget.resource.name}`);
+   } catch {
+     toast.error(`Failed to force deploy ${releaseTarget.resource.name}`);
+   }
+ };
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe1b1ee and 96b38fb.

📒 Files selected for processing (29)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/EnvironmentTableRow.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (3 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx (8 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionPinning.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/layout.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseHistoryTable.tsx (0 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/layout.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/sidebars.ts (1 hunks)
  • apps/webservice/src/app/urls.ts (1 hunks)
  • packages/api/src/router/release-target-version/force-deploy-version.ts (1 hunks)
  • packages/api/src/router/release-target-version/in-progress-version.ts (1 hunks)
  • packages/api/src/router/release-target-version/latest-version.ts (1 hunks)
  • packages/api/src/router/release-target-version/list-deployable-versions.ts (1 hunks)
  • packages/api/src/router/release-target-version/router.ts (1 hunks)
  • packages/api/src/router/release-target-version/utils.ts (1 hunks)
  • packages/api/src/router/release-target-version/version-pinning.ts (1 hunks)
  • packages/api/src/router/release-target.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseHistoryTable.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • CLAUDE.md

⚙️ CodeRabbit Configuration File

**/*.{js,jsx,ts,tsx}

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • CLAUDE.md
**/*.{js,jsx,ts,tsx,json,css,md,yml,yaml}

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • CLAUDE.md
🧠 Learnings (29)
📓 Common learnings
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: e2e/tests/api/policies/retry-policy.spec.ts:23-24
Timestamp: 2025-06-24T23:52:50.732Z
Learning: The user adityachoudhari26 prefers not to add null safety checks or defensive programming in test code, particularly in e2e tests, as they prioritize simplicity and focus on the main functionality being tested rather than comprehensive error handling within the test itself.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: e2e/tests/api/policies/retry-policy.spec.ts:117-130
Timestamp: 2025-06-24T23:53:25.398Z
Learning: User adityachoudhari26 prefers to keep non-null assertions in e2e test code without extensive null safety checks, reasoning that test failures serve the same purpose of catching issues and the extra validation doesn't add much value in test contexts.
apps/webservice/src/app/[workspaceSlug]/sidebars.ts (2)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/EnvironmentTableRow.tsx (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#287
File: packages/validators/src/jobs/conditions/status-condition.ts:4-4
Timestamp: 2025-01-21T19:52:22.838Z
Learning: In apps/webservice/src/app/api/github/webhook/workflow/handler.ts, the external "completed" status is intentionally mapped to JobStatus.Successful to handle GitHub workflow status conversions.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/layout.tsx (2)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
packages/api/src/router/release-target-version/router.ts (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx (5)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, dynamic route parameters (params) return Promises instead of direct values in async contexts. When accessing properties like `params.deploymentId` in an async function, use `(await params).deploymentId` to avoid the "params should be awaited before using its properties" error. This applies to API routes, page components, and other async contexts.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, params in dynamic routes must be awaited before accessing their properties in async contexts. For example, `params.deploymentId` should be accessed as `(await params).deploymentId` in async functions.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
packages/api/src/router/release-target-version/in-progress-version.ts (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#500
File: packages/db/src/schema/job.ts:117-120
Timestamp: 2025-04-21T18:34:54.764Z
Learning: In the system's job schema, the relationship between job and releaseJob is a true one-to-one relationship - a release job should only ever point to one job and vice versa. The implementation uses `one(releaseJob, ...)` in the jobRelations to reflect this business rule.
apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (11)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: CR
PR: ctrlplanedev/ctrlplane#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-30T21:36:42.935Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript with explicit types (prefer interfaces for public APIs)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: CR
PR: ctrlplanedev/ctrlplane#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-30T21:36:42.935Z
Learning: Applies to **/*.{ts,tsx} : Consistent type imports: `import type { Type } from "module"`
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#363
File: apps/webservice/tsconfig.json:14-15
Timestamp: 2025-03-09T08:56:53.603Z
Learning: In the ctrlplane project, they use Next.js standalone output mode, which means they intentionally exclude `.next/types` in their tsconfig.json despite including `.next/types/**/*.ts` in their include pattern.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#579
File: packages/db/src/schema/rules/concurrency.ts:0-0
Timestamp: 2025-06-01T19:10:11.535Z
Learning: In the ctrlplane codebase, when defining database schemas with Drizzle ORM, it's an intentional pattern to spread base fields (like `basePolicyRuleFields`) and then redefine specific fields to add additional constraints (like unique constraints or foreign key references). The TypeScript field overwriting behavior is deliberately used to override base field definitions with more specific requirements.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#500
File: packages/db/src/schema/job.ts:117-120
Timestamp: 2025-04-21T18:34:54.764Z
Learning: In the system's job schema, the relationship between job and releaseJob is a true one-to-one relationship - a release job should only ever point to one job and vice versa. The implementation uses `one(releaseJob, ...)` in the jobRelations to reflect this business rule.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, dynamic route parameters (params) return Promises instead of direct values in async contexts. When accessing properties like `params.deploymentId` in an async function, use `(await params).deploymentId` to avoid the "params should be awaited before using its properties" error. This applies to API routes, page components, and other async contexts.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, params in dynamic routes must be awaited before accessing their properties in async contexts. For example, `params.deploymentId` should be accessed as `(await params).deploymentId` in async functions.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
packages/api/src/router/release-target-version/utils.ts (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#395
File: packages/api/src/router/environment-page/resources/router.ts:40-45
Timestamp: 2025-03-24T18:46:38.894Z
Learning: The `takeFirst` utility function in the codebase (from `@ctrlplane/db`) throws an Error with message "Found non unique or inexistent value" if the result array doesn't contain exactly one element, making additional null/undefined checks unnecessary after its use.
apps/webservice/src/app/urls.ts (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:382-390
Timestamp: 2024-11-27T23:18:59.456Z
Learning: In the codebase, releases are not scoped to a specific resource.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#236
File: packages/api/src/router/workspace-integrations.ts:222-231
Timestamp: 2024-12-02T01:47:59.631Z
Learning: In `packages/api/src/router/workspace-integrations.ts`, when creating IAM policies for roles that need to assume customer-provided roles with unknown ARNs, it's acceptable to keep `Resource` as `"*"` in the policy document, while limiting the `Action` to `"sts:AssumeRole"`, since ARNs are not known in advance.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx (8)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
packages/api/src/router/release-target-version/latest-version.ts (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx (6)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#183
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx:46-57
Timestamp: 2024-10-30T00:03:57.878Z
Learning: Accessibility and validation feedback improvements are not desired for form fields in the `Overview` component within `apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
packages/api/src/router/release-target-version/version-pinning.ts (2)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/layout.tsx (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, dynamic route parameters (params) return Promises instead of direct values in async contexts. When accessing properties like `params.deploymentId` in an async function, use `(await params).deploymentId` to avoid the "params should be awaited before using its properties" error. This applies to API routes, page components, and other async contexts.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, params in dynamic routes must be awaited before accessing their properties in async contexts. For example, `params.deploymentId` should be accessed as `(await params).deploymentId` in async functions.
packages/api/src/router/release-target-version/list-deployable-versions.ts (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
packages/api/src/router/release-target-version/force-deploy-version.ts (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#500
File: packages/db/src/schema/job.ts:117-120
Timestamp: 2025-04-21T18:34:54.764Z
Learning: In the system's job schema, the relationship between job and releaseJob is a true one-to-one relationship - a release job should only ever point to one job and vice versa. The implementation uses `one(releaseJob, ...)` in the jobRelations to reflect this business rule.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#579
File: packages/rule-engine/src/rules/concurrency-rule.ts:8-11
Timestamp: 2025-06-01T19:10:47.122Z
Learning: In packages/rule-engine/src/rules/concurrency-rule.ts, the ConcurrencyRule should remain simple without additional validation since database and Zod schemas already handle concurrency validation. The user prefers this rule to be "dumb" and just perform the comparison check rather than duplicating validation logic.
packages/api/src/router/release-target.ts (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#578
File: apps/webservice/src/app/[workspaceSlug]/(app)/resources/(sidebar)/providers/integrations/github/GithubDialog.tsx:58-58
Timestamp: 2025-05-30T21:48:48.868Z
Learning: In the ctrlplane codebase, the shadcn form UI version allows initializing forms with `useForm({ schema: formSchema })` directly, without needing to import and use `zodResolver` from '@hookform/resolvers/zod'. This is different from standard react-hook-form usage.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#183
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx:28-34
Timestamp: 2024-10-30T00:03:58.927Z
Learning: In the Ctrlplane project, error handling for API mutations in React components is not required unless specified by the user.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#363
File: apps/webservice/tsconfig.json:14-15
Timestamp: 2025-03-09T08:56:53.603Z
Learning: In the ctrlplane project, they use Next.js standalone output mode, which means they intentionally exclude `.next/types` in their tsconfig.json despite including `.next/types/**/*.ts` in their include pattern.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionPinning.tsx (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#287
File: packages/validators/src/jobs/conditions/status-condition.ts:4-4
Timestamp: 2025-01-21T19:52:22.838Z
Learning: In apps/webservice/src/app/api/github/webhook/workflow/handler.ts, the external "completed" status is intentionally mapped to JobStatus.Successful to handle GitHub workflow status conversions.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#183
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx:46-57
Timestamp: 2024-10-30T00:03:57.878Z
Learning: Accessibility and validation feedback improvements are not desired for form fields in the `Overview` component within `apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx`.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (8)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
🧬 Code Graph Analysis (14)
packages/api/src/router/release-target-version/router.ts (6)
packages/api/src/trpc.ts (1)
  • createTRPCRouter (55-55)
packages/api/src/router/release-target-version/in-progress-version.ts (1)
  • inProgressVersion (10-50)
packages/api/src/router/release-target-version/latest-version.ts (1)
  • latestVersion (10-46)
packages/api/src/router/release-target-version/list-deployable-versions.ts (1)
  • listDeployableVersions (107-154)
packages/api/src/router/release-target-version/version-pinning.ts (2)
  • pinVersion (11-45)
  • unpinVersion (47-71)
packages/api/src/router/release-target-version/force-deploy-version.ts (1)
  • forceDeployVersion (94-123)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx (2)
packages/db/src/schema/release.ts (1)
  • releaseTarget (21-47)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (1)
  • ReleaseTargetVersionsTable (86-118)
packages/api/src/router/release-target-version/in-progress-version.ts (3)
packages/api/src/trpc.ts (1)
  • protectedProcedure (173-173)
packages/db/src/schema/job.ts (1)
  • JobStatus (149-149)
packages/db/src/common.ts (1)
  • takeFirstOrNull (15-20)
apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx (1)
packages/ui/src/button.tsx (1)
  • buttonVariants (80-80)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (3)
packages/ui/src/table.tsx (2)
  • TableRow (117-117)
  • TableCell (118-118)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (1)
  • JobStatusCell (9-25)
packages/db/src/schema/job.ts (1)
  • job (75-108)
packages/api/src/router/release-target-version/utils.ts (3)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (1)
  • ReleaseTarget (3-7)
packages/db/src/client.ts (1)
  • db (15-15)
packages/db/src/common.ts (1)
  • takeFirst (9-13)
apps/webservice/src/app/urls.ts (2)
packages/db/src/schema/release.ts (1)
  • releaseTarget (21-47)
packages/db/src/schema/resource.ts (1)
  • resource (58-86)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx (1)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (1)
  • ReleaseTargetTile (121-159)
packages/api/src/router/release-target-version/latest-version.ts (3)
packages/api/src/trpc.ts (1)
  • protectedProcedure (173-173)
packages/db/src/schema/job.ts (1)
  • JobStatus (149-149)
packages/db/src/common.ts (1)
  • takeFirstOrNull (15-20)
packages/api/src/router/release-target-version/force-deploy-version.ts (9)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (1)
  • ReleaseTarget (3-7)
packages/api/src/router/release-target-version/utils.ts (2)
  • ReleaseTarget (5-9)
  • getReleaseTarget (11-36)
packages/db/src/client.ts (1)
  • db (15-15)
packages/db/src/common.ts (2)
  • takeFirstOrNull (15-20)
  • takeFirst (9-13)
packages/rule-engine/src/manager/version-manager.ts (1)
  • VersionReleaseManager (35-233)
packages/rule-engine/src/manager/variable-manager.ts (1)
  • VariableReleaseManager (17-148)
packages/api/src/trpc.ts (1)
  • protectedProcedure (173-173)
packages/db/src/queries/create-release-job.ts (1)
  • createReleaseJob (19-95)
packages/events/src/index.ts (1)
  • getQueue (28-34)
packages/api/src/router/release-target.ts (3)
packages/api/src/trpc.ts (2)
  • createTRPCRouter (55-55)
  • protectedProcedure (173-173)
packages/api/src/router/release-target-version/router.ts (1)
  • releaseTargetVersionRouter (8-15)
packages/db/src/common.ts (1)
  • takeFirstOrNull (15-20)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (9)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (2)
  • Version (10-10)
  • ReleaseTarget (3-7)
apps/webservice/src/app/[workspaceSlug]/(app)/_components/CollapsibleRow.tsx (1)
  • CollapsibleRow (7-24)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx (1)
  • HeaderRow (74-104)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx (1)
  • VersionDropdown (24-93)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (1)
  • JobRow (8-26)
packages/ui/src/skeleton.tsx (1)
  • Skeleton (15-15)
packages/ui/src/table.tsx (5)
  • TableHeader (113-113)
  • TableRow (117-117)
  • TableHead (116-116)
  • Table (112-112)
  • TableBody (114-114)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts (1)
  • useVersionSearch (4-18)
apps/webservice/src/app/[workspaceSlug]/(app)/_components/CollapsibleSearchInput.tsx (1)
  • CollapsibleSearchInput (9-48)
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (2)
packages/ui/src/tooltip.tsx (4)
  • TooltipProvider (30-30)
  • Tooltip (30-30)
  • TooltipTrigger (30-30)
  • TooltipContent (30-30)
packages/ui/src/skeleton.tsx (1)
  • Skeleton (15-15)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (3)
packages/db/src/schema/job.ts (1)
  • JobStatus (149-149)
packages/ui/src/table.tsx (1)
  • TableCell (118-118)
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (1)
  • PolicyEvaluationTooltip (161-215)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
🔇 Additional comments (44)
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (3)

123-152: LGTM - Well-structured policy evaluation logic.

The getIsPassingAllRules helper function correctly centralizes the logic for determining if all policy rules pass. The implementation properly handles:

  • Null safety with early return
  • Approval rule validation across different types
  • Version selector rule checking
  • Rollout time validation using proper date comparison

The logic flow is clear and the function serves its purpose well.


154-159: LGTM - Consistent blocked policy UI.

The PolicyBlockCell component provides a clean, consistent UI element for indicating blocked policy states. The shield icon and text are appropriate for this use case.


161-215: LGTM - Proper tooltip implementation with good UX.

The tooltip refactoring from HoverCard to Tooltip pattern is well-implemented:

  • Proper loading states with Skeleton component
  • Conditional rendering based on policy evaluation results
  • Appropriate tooltip positioning and styling
  • Good user experience with policy evaluation details

The component correctly integrates the new helper function and provides comprehensive policy information.

apps/webservice/src/app/[workspaceSlug]/sidebars.ts (1)

12-12: LGTM - Clean enum addition.

The addition of ReleaseTarget = "release-target" follows the existing naming convention and properly supports the new release target functionality introduced in this PR.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/layout.tsx (2)

7-7: LGTM - Updated import for new deployment UI.

The icon change from IconHistory to IconRocket aligns with the shift from release history to deployments view.


98-102: LGTM - Consistent sidebar link update.

The sidebar link updates are well-aligned with the new deployment management UI:

  • Updated URL to use baseUrl() method
  • Changed icon from history to rocket
  • Updated label from "Release History" to "Deployments"

These changes properly reflect the functionality shift described in the PR objectives.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx (2)

2-2: LGTM - Updated import for new tile-based UI.

The import change from ReleaseHistoryTable to ReleaseTargetTile aligns with the PR's objective of replacing the release history table with a tile-based deployments overview.


14-19: LGTM - Well-implemented tile-based grid layout.

The refactoring from a single table component to a grid of tile components is well-executed:

  • Proper mapping over releaseTargets with correct key usage
  • Clean 3-column grid layout with appropriate spacing
  • Each tile receives the complete releaseTarget object as expected by the component

This implementation successfully replaces the previous release history table with the new tile-based deployments overview as described in the PR objectives.

packages/api/src/router/release-target-version/router.ts (1)

1-15: LGTM! Clean router structure.

The router properly aggregates all release target version procedures into a cohesive API surface. The import organization and endpoint naming are consistent with the project's conventions.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts (1)

1-18: LGTM! Well-structured search parameter management.

The hook properly manages URL search parameters using Next.js navigation APIs. The conditional logic for setting/removing parameters is correct, and using router.replace appropriately updates the URL without adding history entries.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (1)

1-25: LGTM! Well-structured status cell component.

The component is properly typed, follows React patterns, and integrates well with the PolicyEvaluationTooltip for enhanced UX. The implementation is clean and focused on its single responsibility.

apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx (1)

1-30: LGTM! Secure and well-styled link component.

The component properly handles external links with appropriate security attributes (target="_blank" and rel="noopener noreferrer"), provides good empty state handling, and uses consistent styling with buttonVariants.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx (1)

1-18: LGTM! Proper Next.js 15 async page implementation.

The page correctly awaits params before accessing properties, handles the not found case appropriately, and follows Next.js server component patterns. The implementation is clean and focused.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (1)

8-12: Component structure and type usage look good.

The component properly uses TypeScript with explicit types, follows React best practices, and correctly integrates with the JobStatusCell component. The date formatting using formatDistanceToNowStrict is appropriate for displaying relative job creation times.

Also applies to: 16-26

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (1)

1-11: Well-structured type definitions with proper TypeScript usage.

The type definitions follow TypeScript best practices:

  • Proper use of import type for type-only imports
  • Clean intersection types that extend base schema types with related entities
  • Consistent naming conventions and structure
  • Appropriate use of generic types like Record<string, string> for the links property

This provides a solid foundation for type safety across the deployment management UI.

packages/api/src/router/release-target-version/utils.ts (1)

11-36: Database query implementation is correct and well-structured.

The getReleaseTarget function:

  • Uses proper inner joins to fetch related data
  • Correctly applies the takeFirst utility for single result handling
  • Returns a well-typed result matching the ReleaseTarget interface
  • Follows established database query patterns in the codebase

The query structure ensures data integrity by requiring all related entities to exist.

packages/api/src/router/release-target-version/in-progress-version.ts (2)

10-18: Authorization check is properly implemented.

The procedure correctly uses ReleaseTargetGet permission and validates access to the specific release target ID. This follows the established authorization patterns in the codebase.


19-50: Database query logic is correct for finding in-progress versions.

The query implementation:

  • Properly joins all necessary tables to get version and job data
  • Correctly filters for non-successful job statuses using ne(schema.job.status, JobStatus.Successful)
  • Orders by job creation time descending to get the most recent
  • Uses takeFirstOrNull appropriately since there might not be any in-progress versions
  • Transforms the result into a clean format with version and job properties

The complex join structure is necessary to traverse the relationships between release targets, versions, and jobs.

packages/api/src/router/release-target.ts (1)

17-20: Good integration of version management functionality.

The addition of the releaseTargetVersionRouter as a nested router properly organizes the version-related endpoints under the release target namespace. This follows good API design practices.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/layout.tsx (2)

23-31: LGTM! Proper Next.js 15 async params handling and metadata generation.

The implementation correctly uses await params as required for Next.js 15 and properly handles the case where release target is not found with notFound().


59-74: LGTM! Clean layout component structure.

The layout component properly fetches data, handles error cases, and provides a clean structure with the header and children. The destructuring of release target properties is efficient.

packages/api/src/router/release-target-version/latest-version.ts (2)

10-18: LGTM! Proper authorization implementation.

The authorization check correctly uses Permission.ReleaseTargetGet and validates against the release target ID.


19-46: LGTM! Well-structured database query with proper result handling.

The query correctly joins the necessary tables to find the latest successful deployment version. The use of takeFirstOrNull aligns with the established pattern and the final extraction of deployment_version is appropriate.

apps/webservice/src/app/urls.ts (2)

125-151: LGTM! Well-structured URL builders following established patterns.

The new releaseTarget and resourceDeployments functions maintain consistency with the existing URL building patterns and provide good nesting structure for the new deployment UI features.


156-156: LGTM! Proper integration with existing resource URL builder.

The update to use the new resourceDeployments function maintains backward compatibility while enabling the new nested URL structure.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (3)

23-59: LGTM! Well-structured VersionRow component with proper destructuring.

The component correctly destructures the latest job and other jobs, and uses the CollapsibleRow pattern effectively with HeaderRow and JobRow components.


61-71: LGTM! Effective loading state with visual feedback.

The loading state provides good visual feedback with skeleton components and opacity fade effect to indicate loading progress.


86-118: LGTM! Clean table component with proper state management.

The component properly integrates search functionality, loading states, and data fetching. The 5-second refetch interval is appropriate for deployment status updates.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx (1)

49-78: LGTM! Well-structured dialog with proper loading states.

The dialog component properly handles loading states, user feedback, and follows established UI patterns with appropriate button variants.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx (1)

24-93: Well-structured dropdown component with proper state management.

The component correctly handles version pinning states and cache invalidation. Good use of conditional rendering and proper event handling with preventDefault() and stopPropagation().

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx (1)

20-104: Clean component structure with good separation of concerns.

The component effectively breaks down the row into logical sub-components. The TruncatedTextTooltip pattern is a nice touch for handling overflow text.

apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (1)

29-159: Good implementation of loading states and data fetching patterns.

The component properly handles loading states with skeletons and implements a sensible refetch interval for in-progress deployments. The tooltip patterns provide good UX for displaying additional metadata.

packages/api/src/router/release-target-version/version-pinning.ts (1)

11-71: Well-implemented version pinning procedures with proper authorization.

Both procedures follow the established patterns with appropriate authorization checks and event dispatching. The use of takeFirst for version retrieval ensures data integrity by failing loudly on unexpected results.

apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx (3)

113-126: LGTM! Good integration with PolicyEvaluationTooltip.

The JobStatusCell component now properly wraps its content with PolicyEvaluationTooltip and accepts the required props for policy evaluation context.


143-146: LGTM! Good refactoring to use JobLinks component.

The LinksCell component has been properly refactored to delegate link rendering to the JobLinks component, which promotes consistency and reusability.


214-219: LGTM! Consistent PolicyEvaluationTooltip usage.

The PolicyEvaluationTooltip is properly applied to the "No jobs" case, providing consistent policy evaluation feedback across all job status scenarios.

packages/api/src/router/release-target-version/list-deployable-versions.ts (4)

16-30: LGTM! Good separation of policy-based version selection logic.

The getVersionSelectorSql function properly retrieves applicable policies, sorts them by priority, and generates SQL conditions for deployment version selection.


88-102: LGTM! Efficient job data aggregation with proper metadata handling.

The lodash chain properly groups job rows by job ID and extracts job metadata (especially links) correctly. The JSON parsing of links metadata is handled safely.


142-151: LGTM! Well-designed sorting logic for deployment versions.

The comparator function properly prioritizes the desired version first, then sorts by latest job creation date, and finally by deployment version creation date as fallback.


107-154: LGTM! Comprehensive API procedure with proper authorization and data flow.

The procedure correctly implements:

  • Input validation with Zod schema
  • Authorization checks using Permission.ReleaseTargetGet
  • Proper database querying with filtering and pagination
  • Efficient data enrichment with job information
  • Consistent error handling patterns
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionPinning.tsx (4)

34-51: LGTM! Proper async mutation handling with comprehensive error handling.

The onSubmit function correctly chains the mutation, state updates, cache invalidation, router refresh, and toast notifications. Error handling is properly implemented with catch block.


53-79: LGTM! Well-structured dialog with proper loading states.

The dialog implementation correctly:

  • Uses controlled state with open and setOpen
  • Provides clear user feedback with loading states
  • Implements proper button states (disabled during pending)
  • Uses consistent UI components from the design system

94-105: LGTM! Consistent error handling and mutation pattern.

The UnpinVersionDialog follows the same excellent pattern as PinVersionDialog with proper async handling, cache invalidation, and user feedback.


107-131: LGTM! Consistent dialog structure and user experience.

The UnpinVersionDialog maintains the same high-quality patterns as the PinVersionDialog, ensuring consistent user experience across both pin and unpin operations.

Comment on lines +22 to +55
byId: protectedProcedure
.input(z.string().uuid())
.meta({
authorizationCheck: ({ canUser, input }) =>
canUser.perform(Permission.ReleaseTargetGet).on({
type: "releaseTarget",
id: input,
}),
})
.query(async ({ ctx, input }) =>
ctx.db
.select()
.from(schema.releaseTarget)
.innerJoin(
schema.resource,
eq(schema.releaseTarget.resourceId, schema.resource.id),
)
.innerJoin(
schema.environment,
eq(schema.releaseTarget.environmentId, schema.environment.id),
)
.innerJoin(
schema.deployment,
eq(schema.releaseTarget.deploymentId, schema.deployment.id),
)
.where(eq(schema.releaseTarget.id, input))
.then(takeFirstOrNull)
.then((dbResult) => {
if (dbResult == null) return null;
const { release_target, resource, environment, deployment } =
dbResult;
return { ...release_target, resource, environment, deployment };
}),
),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Eliminate code duplication by using the getReleaseTarget utility.

The byId procedure duplicates the exact same query logic that's already implemented in the getReleaseTarget utility function from packages/api/src/router/release-target-version/utils.ts. This creates maintenance overhead and potential inconsistencies.

Replace the inline query with the utility function:

-import {
-  and,
-  count,
-  eq,
-  notInArray,
-  takeFirst,
-  takeFirstOrNull,
-} from "@ctrlplane/db";
+import { and, count, eq, notInArray, takeFirst } from "@ctrlplane/db";
+import { getReleaseTarget } from "./release-target-version/utils";
-  .query(async ({ ctx, input }) =>
-    ctx.db
-      .select()
-      .from(schema.releaseTarget)
-      .innerJoin(
-        schema.resource,
-        eq(schema.releaseTarget.resourceId, schema.resource.id),
-      )
-      .innerJoin(
-        schema.environment,
-        eq(schema.releaseTarget.environmentId, schema.environment.id),
-      )
-      .innerJoin(
-        schema.deployment,
-        eq(schema.releaseTarget.deploymentId, schema.deployment.id),
-      )
-      .where(eq(schema.releaseTarget.id, input))
-      .then(takeFirstOrNull)
-      .then((dbResult) => {
-        if (dbResult == null) return null;
-        const { release_target, resource, environment, deployment } =
-          dbResult;
-        return { ...release_target, resource, environment, deployment };
-      }),
-  ),
+  .query(async ({ input }) => {
+    try {
+      return await getReleaseTarget(input);
+    } catch {
+      return null;
+    }
+  }),

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/api/src/router/release-target.ts lines 22 to 55, the byId procedure
duplicates the query logic already implemented in the getReleaseTarget utility
function from packages/api/src/router/release-target-version/utils.ts. To fix
this, import the getReleaseTarget function and replace the inline query inside
the byId procedure with a call to getReleaseTarget, passing the necessary
context and input parameters. This will eliminate code duplication and ensure
consistency.

Comment on lines +145 to +147
<Button variant="outline" size="sm">
Lock
</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Lock button is missing onClick handler.

The Lock button doesn't have an onClick handler, making it non-functional. If this is intentional (placeholder for future functionality), consider disabling it or adding a tooltip to indicate it's not yet implemented.

🤖 Prompt for AI Agents
In
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx
around lines 145 to 147, the Lock button lacks an onClick handler, rendering it
non-functional. To fix this, either add a proper onClick handler to implement
the intended locking functionality or, if it's a placeholder, disable the button
and/or add a tooltip explaining that the feature is not yet implemented.

Comment on lines +18 to +93
const getVersionRelease = async (
releaseTarget: ReleaseTarget,
versionId: string,
) => {
const existingVersionRelease = await db
.select()
.from(schema.versionRelease)
.where(
and(
eq(schema.versionRelease.releaseTargetId, releaseTarget.id),
eq(schema.versionRelease.versionId, versionId),
),
)
.then(takeFirstOrNull);

if (existingVersionRelease != null) return existingVersionRelease;

const { workspaceId } = releaseTarget.resource;
const vrm = new VersionReleaseManager(db, {
...releaseTarget,
workspaceId,
});
const { release: versionRelease } = await vrm.upsertRelease(versionId);

return versionRelease;
};

const getVariableSetRelease = async (releaseTarget: ReleaseTarget) => {
const releaseTargetId = releaseTarget.id;
const existingVariableSetRelease = await db
.select()
.from(schema.variableSetRelease)
.where(eq(schema.variableSetRelease.releaseTargetId, releaseTargetId))
.then(takeFirstOrNull);

if (existingVariableSetRelease != null) return existingVariableSetRelease;

const { workspaceId } = releaseTarget.resource;

const varrm = new VariableReleaseManager(db, {
...releaseTarget,
workspaceId,
});

const { chosenCandidate: variableValues } = await varrm.evaluate();

const { release: variableRelease } =
await varrm.upsertRelease(variableValues);

return variableRelease;
};

const getRelease = async (
versionReleaseId: string,
variableReleaseId: string,
) => {
const existingRelease = await db
.select()
.from(schema.release)
.where(
and(
eq(schema.release.versionReleaseId, versionReleaseId),
eq(schema.release.variableReleaseId, variableReleaseId),
),
)
.then(takeFirstOrNull);

if (existingRelease != null) return existingRelease;

return db
.insert(schema.release)
.values({ versionReleaseId, variableReleaseId })
.returning()
.then(takeFirst);
};

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Helper functions should accept database client parameter for transaction support.

The helper functions use db directly, making them inflexible for transaction contexts. Consider refactoring them to accept a database client parameter:

 const getVersionRelease = async (
+  db: typeof ctx.db,
   releaseTarget: ReleaseTarget,
   versionId: string,
 ) => {

This would allow these functions to participate in transactions when needed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getVersionRelease = async (
releaseTarget: ReleaseTarget,
versionId: string,
) => {
const existingVersionRelease = await db
.select()
.from(schema.versionRelease)
.where(
and(
eq(schema.versionRelease.releaseTargetId, releaseTarget.id),
eq(schema.versionRelease.versionId, versionId),
),
)
.then(takeFirstOrNull);
if (existingVersionRelease != null) return existingVersionRelease;
const { workspaceId } = releaseTarget.resource;
const vrm = new VersionReleaseManager(db, {
...releaseTarget,
workspaceId,
});
const { release: versionRelease } = await vrm.upsertRelease(versionId);
return versionRelease;
};
const getVariableSetRelease = async (releaseTarget: ReleaseTarget) => {
const releaseTargetId = releaseTarget.id;
const existingVariableSetRelease = await db
.select()
.from(schema.variableSetRelease)
.where(eq(schema.variableSetRelease.releaseTargetId, releaseTargetId))
.then(takeFirstOrNull);
if (existingVariableSetRelease != null) return existingVariableSetRelease;
const { workspaceId } = releaseTarget.resource;
const varrm = new VariableReleaseManager(db, {
...releaseTarget,
workspaceId,
});
const { chosenCandidate: variableValues } = await varrm.evaluate();
const { release: variableRelease } =
await varrm.upsertRelease(variableValues);
return variableRelease;
};
const getRelease = async (
versionReleaseId: string,
variableReleaseId: string,
) => {
const existingRelease = await db
.select()
.from(schema.release)
.where(
and(
eq(schema.release.versionReleaseId, versionReleaseId),
eq(schema.release.variableReleaseId, variableReleaseId),
),
)
.then(takeFirstOrNull);
if (existingRelease != null) return existingRelease;
return db
.insert(schema.release)
.values({ versionReleaseId, variableReleaseId })
.returning()
.then(takeFirst);
};
const getVersionRelease = async (
db: typeof ctx.db,
releaseTarget: ReleaseTarget,
versionId: string,
) => {
const existingVersionRelease = await db
.select()
.from(schema.versionRelease)
.where(
and(
eq(schema.versionRelease.releaseTargetId, releaseTarget.id),
eq(schema.versionRelease.versionId, versionId),
),
)
.then(takeFirstOrNull);
if (existingVersionRelease != null) return existingVersionRelease;
const { workspaceId } = releaseTarget.resource;
const vrm = new VersionReleaseManager(db, {
...releaseTarget,
workspaceId,
});
const { release: versionRelease } = await vrm.upsertRelease(versionId);
return versionRelease;
};
🤖 Prompt for AI Agents
In packages/api/src/router/release-target-version/force-deploy-version.ts from
lines 18 to 93, the helper functions getVersionRelease, getVariableSetRelease,
and getRelease currently use the global db client directly, which prevents them
from participating in transactions. Refactor these functions to accept a
database client parameter and use that client for all database operations
instead of the global db. This change will allow callers to pass a transactional
database client when needed, enabling proper transaction support.

Comment on lines +108 to +123
.mutation(async ({ ctx, input }) => {
const { releaseTargetId, versionId } = input;
const releaseTarget = await getReleaseTarget(releaseTargetId);
const [versionRelease, variableRelease] = await Promise.all([
getVersionRelease(releaseTarget, versionId),
getVariableSetRelease(releaseTarget),
]);
const release = await getRelease(versionRelease.id, variableRelease.id);
const releaseJob = await createReleaseJob(ctx.db, release);

getQueue(Channel.DispatchJob).add(releaseJob.id, {
jobId: releaseJob.id,
});

return releaseJob;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider wrapping database operations in a transaction.

The mutation performs multiple database operations that should be atomic. While createReleaseJob is called with ctx.db, consider wrapping all operations in an explicit transaction to ensure consistency if any operation fails.

 .mutation(async ({ ctx, input }) => {
+  return ctx.db.transaction(async (tx) => {
     const { releaseTargetId, versionId } = input;
     const releaseTarget = await getReleaseTarget(releaseTargetId);
     const [versionRelease, variableRelease] = await Promise.all([
       getVersionRelease(releaseTarget, versionId),
       getVariableSetRelease(releaseTarget),
     ]);
     const release = await getRelease(versionRelease.id, variableRelease.id);
-    const releaseJob = await createReleaseJob(ctx.db, release);
+    const releaseJob = await createReleaseJob(tx, release);
 
     getQueue(Channel.DispatchJob).add(releaseJob.id, {
       jobId: releaseJob.id,
     });
 
     return releaseJob;
+  });
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.mutation(async ({ ctx, input }) => {
const { releaseTargetId, versionId } = input;
const releaseTarget = await getReleaseTarget(releaseTargetId);
const [versionRelease, variableRelease] = await Promise.all([
getVersionRelease(releaseTarget, versionId),
getVariableSetRelease(releaseTarget),
]);
const release = await getRelease(versionRelease.id, variableRelease.id);
const releaseJob = await createReleaseJob(ctx.db, release);
getQueue(Channel.DispatchJob).add(releaseJob.id, {
jobId: releaseJob.id,
});
return releaseJob;
});
.mutation(async ({ ctx, input }) => {
return ctx.db.transaction(async (tx) => {
const { releaseTargetId, versionId } = input;
const releaseTarget = await getReleaseTarget(releaseTargetId);
const [versionRelease, variableRelease] = await Promise.all([
getVersionRelease(releaseTarget, versionId),
getVariableSetRelease(releaseTarget),
]);
const release = await getRelease(versionRelease.id, variableRelease.id);
const releaseJob = await createReleaseJob(tx, release);
getQueue(Channel.DispatchJob).add(releaseJob.id, {
jobId: releaseJob.id,
});
return releaseJob;
});
});
🤖 Prompt for AI Agents
In packages/api/src/router/release-target-version/force-deploy-version.ts around
lines 108 to 123, the mutation performs multiple database operations that should
be atomic but currently are not wrapped in a transaction. To fix this, wrap all
database calls including getReleaseTarget, getVersionRelease,
getVariableSetRelease, getRelease, and createReleaseJob inside a single explicit
transaction using ctx.db.transaction or equivalent. This ensures that if any
operation fails, all changes are rolled back to maintain data consistency.

@adityachoudhari26 adityachoudhari26 merged commit 7964685 into main Jul 11, 2025
4 of 6 checks passed
@adityachoudhari26 adityachoudhari26 deleted the resource-deployments-ui branch July 11, 2025 19:06
adityachoudhari26 added a commit that referenced this pull request Jul 11, 2025
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.

2 participants