Skip to content

Bugs - #28

Merged
Lftobs merged 5 commits into
devfrom
bugs
Jul 28, 2026
Merged

Bugs#28
Lftobs merged 5 commits into
devfrom
bugs

Conversation

@Lftobs

@Lftobs Lftobs commented Jul 28, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added project type selection for web applications and static sites.
    • Added project settings for build commands, start commands, source directory, and related configuration.
    • Added dynamic build configuration for Node.js, Rust, Go, and static projects.
    • Added deployment completion timestamps and more accurate duration reporting.
    • Improved scaling with project resource-limit validation.
  • Bug Fixes

    • Improved container recovery when containers are temporarily unavailable.
    • Fixed reverse-proxy host forwarding and Ko-fi popup placement.
    • Deployment redeployments now preserve the configured project branch.
  • Chores

    • Updated the release to version 0.2.1.

Lftobs and others added 4 commits July 20, 2026 23:19
time

- Add `finished_at` column to deployments table
- Implement status-based timestamping for
  deployment completion
- Update runtime reconciliation to skip
  non-existent containers
- Fix Ko-fi popup mounting in dashboard sidebar
- Update docker-compose configuration for local
  builds
customization

- Add `project_type`, `buildCommand`, and
  `startCommand` fields to projects.
- Implement dynamic `railpack.json` generation for
  better build/runtime compatibility.
- Add `ProjectSettingsTab` to the dashboard for
  managing build settings.
- Update Caddy reverse proxy to correctly pass the
  Host header to upstream containers.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Lftobs, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dea7f767-6685-4528-bfc0-0a85ecf82e49

📥 Commits

Reviewing files that changed from the base of the PR and between 3bb1afe and be0e65d.

📒 Files selected for processing (1)
  • docker-compose.yml
📝 Walkthrough

Walkthrough

The release adds project type and build/start command configuration, dynamic Railpack build generation, build-safe environment filtering, deployment completion timestamps, project-aware deployment branches, scaling and runtime handling updates, dashboard project settings, local Compose builds, and v0.2.1 release tooling.

Changes

Project configuration and dashboard settings

Layer / File(s) Summary
Project configuration contracts and persistence
apps/api/src/types.ts, apps/api/src/db/*, apps/api/src/api/projects/index.ts, apps/web/src/api/client.ts
Project type, build command, and start command fields are added across types, migrations, repositories, and API payloads.
Project creation and settings UI
apps/web/src/components/project/create/*, apps/web/src/components/project/settings/*, apps/web/src/hooks/useProjects.ts, apps/web/src/routes/ProjectDetail.tsx
Project creation supports web/static selection, and a Settings tab edits project build and runtime fields.
Deployment lifecycle tracking
apps/api/src/db/migrate.ts, apps/api/src/db/repo/deployments.ts, apps/api/src/api/deployments/index.ts, apps/web/src/components/project/deployments/deployment-logs.tsx
Deployment branches fall back to project branches, and finished timestamps are stored and displayed.
Dynamic build pipeline
apps/api/src/orchestrator/pipeline.ts, apps/api/src/orchestrator/railpack.ts, apps/api/src/orchestrator/railpack-config-utils.ts, apps/api/src/utils/env-filter.ts
Railpack configuration is generated for Node, Rust, Go, and static projects, with project metadata and build-safe environment variables forwarded to builds.
Scaling, runtime, and proxy behavior
apps/api/src/scaling/*, apps/api/src/orchestrator/runtime.ts, apps/api/src/utils/domain-verifier.ts
Scaling validates CPU limits and applies resource flags, missing containers are retried or skipped, and Caddy forwards the upstream Host header.
Release and installation updates
VERSION, docker-compose.yml, scripts/*, apps/docs/src/content/changelogs/*, package.json
Version 0.2.1, local Compose builds, update-script handling, authentication asset installation, dependencies, and changelog content are updated.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProjectSettingsTab
  participant useUpdateProject
  participant API
  participant ProjectRepository
  participant Database
  ProjectSettingsTab->>useUpdateProject: submit project settings
  useUpdateProject->>API: update project payload
  API->>ProjectRepository: update project fields
  ProjectRepository->>Database: persist project_type and commands
  Database-->>ProjectRepository: updated row
  ProjectRepository-->>API: updated project
  API-->>ProjectSettingsTab: mutation result
Loading

Possibly related PRs

  • Lftobs/dequel#13: Both changes modify the deployment pipeline flow in pipeline.ts.
  • Lftobs/dequel#17: Both changes modify deployment creation inputs in deployments/index.ts.
  • Lftobs/dequel#25: Both changes modify Compose and update-script handling.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too vague and generic to describe the actual changes in this pull request. Use a concise, specific title that summarizes the main change, such as the new project settings and deployment/build updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugs

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

Comment @coderabbitai help to get the list of available commands.

@Lftobs
Lftobs merged commit 161b862 into dev Jul 28, 2026
4 of 5 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 17

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
apps/api/src/orchestrator/pipeline.ts (2)

391-411: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use the deployment environment for build variables.

Line 391 always loads production, while the runtime path uses deployment.environment. A non-production deployment can therefore embed production public values during its build. Use deployment.environment ?? undefined here as well.

Proposed fix
- const envVars = deployment.projectId ? await listEnvironmentVariablesForDeploy(deployment.projectId, "production") : [];
+ const envVars = deployment.projectId
+   ? await listEnvironmentVariablesForDeploy(
+       deployment.projectId,
+       deployment.environment ?? undefined,
+     )
+   : [];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/orchestrator/pipeline.ts` around lines 391 - 411, Update the
environment argument in the envVars lookup within the build pipeline before
buildWithRailpack, replacing the hardcoded "production" value with
deployment.environment ?? undefined. Keep the existing filterBuildEnvVars and
buildWithRailpack flow unchanged.

284-705: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Split this oversized orchestrator.

apps/api/src/orchestrator/pipeline.ts is 881 lines. Extract cohesive deployment-build, runtime-deploy, and rollback responsibilities before expanding it further.

As per coding guidelines, “No file should be above 500 lines of code; if it is, refactor and split into smaller files with proper feature grouping in a folder rather than scattered across the codebase”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/orchestrator/pipeline.ts` around lines 284 - 705, Refactor the
oversized runDeployment method in the deployment orchestrator into cohesive
modules under a focused orchestrator feature folder, keeping pipeline.ts below
500 lines. Extract the build/source preparation flow, runtime deployment
configuration and execution, and rollback/failure cleanup responsibilities into
appropriately named helpers or services, while preserving runDeployment’s
existing status updates, cancellation handling, cleanup, and return behavior.

Source: Coding guidelines

apps/docs/.astro/astro/content.d.ts (1)

143-165: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Generated types are stale: v0.2.1.md is missing from the changelogs collection.

This PR adds apps/docs/src/content/changelogs/v0.2.1.md, but the committed ContentEntryMap only lists up to v0.2.0.md, while an unrelated docs/changelog.md entry was added at Lines 174-180. Re-run astro sync and commit the regenerated file — or add apps/docs/.astro/ to .gitignore so this artifact stops drifting from the content directory.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/docs/.astro/astro/content.d.ts` around lines 143 - 165, Regenerate the
ContentEntryMap in the generated content types so the “changelogs” collection
includes the new “v0.2.1.md” entry and remove the unrelated “docs/changelog.md”
entry if it was generated incorrectly. Use the Astro sync workflow to update the
generated artifact, or configure the project to ignore “apps/docs/.astro/” so
committed generated types no longer drift.
apps/web/src/components/project/create/CreateProjectDialog.tsx (1)

381-499: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Split the oversized project-creation components into feature-focused modules.

Both changed files exceed the 500-line limit; extract cohesive creation-flow sections rather than extending these components further.

  • apps/web/src/components/project/create/CreateProjectDialog.tsx#L381-L499: extract step orchestration/rendering into focused create-flow components or hooks.
  • apps/web/src/components/project/create/StepBasics.tsx#L180-L222: extract general settings and source-detail sections into feature-grouped child components.

As per coding guidelines, “No file should be above 500 lines of code; if it is, refactor and split into smaller files with proper feature grouping in a folder rather than scattered across the codebase.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/project/create/CreateProjectDialog.tsx` around lines
381 - 499, Split the oversized project-creation components into feature-focused
modules while preserving behavior: in
apps/web/src/components/project/create/CreateProjectDialog.tsx lines 381-499,
extract the step orchestration/rendering around StepBasics, StepEnvironment, and
StepResources into focused components or hooks; in
apps/web/src/components/project/create/StepBasics.tsx lines 180-222, extract the
general-settings and source-details sections into grouped child components. Keep
the extracted modules within the create feature area and ensure both original
files remain under 500 lines.

Source: Coding guidelines

🧹 Nitpick comments (4)
apps/api/src/scaling/__tests__/engine.test.ts (1)

95-95: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add regression cases for the new guard and resource propagation.

This fixture no longer exercises missing projects or non-positive CPU limits. Add explicit cases for those paths and verify scale-up forwards --cpus and --memory.

As per coding guidelines, apps/api/src/**/*.ts: Run bun test in apps/api/ before committing API changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/scaling/__tests__/engine.test.ts` at line 95, Add regression
tests in the engine test suite for missing projects and non-positive CPU limits,
covering the new guard behavior. Extend the scale-up success case to verify the
generated command forwards both --cpus and --memory values, and run bun test
from apps/api before committing.

Source: Coding guidelines

apps/docs/src/content/changelogs/v0.2.1.md (1)

8-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Several entries under "Improvements" are fixes.

Host-header forwarding, the reconciliation skip, and compose config are bug fixes; moving them under "Bug Fixes" makes the release notes more scannable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/docs/src/content/changelogs/v0.2.1.md` around lines 8 - 15, Move the
entries for Caddy Host-header forwarding, runtime reconciliation skipping
non-existent containers, and Docker-compose configuration from the
“Improvements” section into “Bug Fixes” in the changelog. Leave the remaining
improvement entries unchanged.
apps/api/src/orchestrator/railpack-config-utils.ts (2)

385-465: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift

Synthesizing workspace dependency versions is likely to build the wrong thing.

Falling back to a hardcoded commonDeps table and version = "*" for everything else silently resolves dependencies the user never pinned, and the hardcoded edition = "2021" / rust-version = "1.89" may not match the real workspace. Failing the build with a clear "workspace root not found in the selected source dir" message is more predictable than guessing. At minimum, log which versions were substituted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/orchestrator/railpack-config-utils.ts` around lines 385 - 465,
Remove the synthetic workspace metadata and dependency version substitution
around commonDeps and the cargoContent replacement loop. Validate that the
selected source directory includes the workspace root and fail with a clear
“workspace root not found in the selected source dir” error when it does not,
rather than guessing versions, edition, or rust-version; preserve existing
content when the workspace root is present.

112-116: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Type the config instead of Record<string, any>.

A small interface (caches, steps, deploy.startCommand) would catch key typos in the branches below at compile time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/orchestrator/railpack-config-utils.ts` around lines 112 - 116,
Replace the broad Record<string, any> annotation on config with a focused
interface describing caches, steps, and deploy.startCommand. Use that typed
config throughout the surrounding utility so misspelled keys in its branches are
caught at compile time, while preserving the existing defaults and behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/package.json`:
- Line 13: Align the Elysia and `@sinclair/typebox` dependency declarations in
apps/api: either update the lockfile to resolve elysia within the declared
^1.1.26 range, or, if the resolved 1.4.x version is intended, update the elysia
range in package.json accordingly while retaining a compatible `@sinclair/typebox`
range.

In `@apps/api/src/api/projects/index.ts`:
- Around line 69-70: Guard the PATCH request body before the `"buildCommand" in
...` and `"startCommand" in ...` checks: require a non-null object and return
the handler’s established controlled 4xx response for primitive or otherwise
invalid bodies. Preserve the existing command normalization for valid object
bodies, and add a regression test covering JSON string or number payloads.

In `@apps/api/src/orchestrator/railpack-config-utils.ts`:
- Around line 335-371: The ancestor-walk boundary checks in the Rust lookup and
the corresponding Go lookup must not accept sibling paths that merely share the
workspace prefix. Update the checks around currentDir and the Go lookup’s
equivalent path variable to require workspace plus a path separator (or an
equivalent path.relative boundary test), while preserving traversal of the
workspace directory itself and stopping when the path leaves it.
- Around line 32-86: Restrict rewriteLocalhostBinding so it only changes
loopback values used in detected server bind/listen configuration, such as
127.0.0.1:<port> near listen, bind, or host settings, rather than replacing
every occurrence in allowed files. Preserve unrelated database targets,
allow-lists, proxy settings, and fixture data; alternatively require an explicit
project opt-in before applying the rewrite.
- Around line 235-296: Extract the duplicated static serving template into a
shared buildStaticServeScript(cleanSourceDir) helper, preferably in a sibling
static-serve-template module, and replace both serve-script branches with it.
Preserve the generated script’s behavior exactly, including directory selection,
URL decoding, file serving, SPA fallback, and 404 handling. Split
railpack-config-utils.ts and group Node, Rust, and Go detectors under a
railpack/ folder so no file exceeds 500 lines.
- Around line 235-239: Update the serveScript template construction to
interpolate cleanSourceDir using JSON.stringify(cleanSourceDir), preserving
valid and non-injectable JavaScript string syntax for quotes, backslashes, and
newlines.
- Around line 262-296: Update the generated Bun.serve static-server fetch
handler in both script copies to prevent traversal after decodeURIComponent:
resolve the requested path against staticDir, verify the resolved path remains
within staticDir, and return a 404 response without reading it when containment
fails. Apply the same containment check to the fallback flow while preserving
normal file serving and index.html fallback behavior.
- Around line 231-314: Update the isStatic classification in the surrounding
configuration flow so Node services without scripts.start or scripts.server are
not treated as static solely because hasPackageJson is true; reserve static
deployment for explicit static projects or reliably identified static builds.
Preserve the node dist/index.js fallback in the final else branch for backend
services, and avoid generating a Bun-dependent serve command when the selected
package manager/runtime is not Bun by using a compatible serving strategy.

In `@apps/api/src/orchestrator/railpack.ts`:
- Around line 357-363: Validate each user-supplied env key in the
opts.environmentVariables loop before pushing its --env argument: reject empty
keys and keys containing "=" or whitespace, using the existing error-handling
approach in the surrounding railpack flow. Only append --env for validated keys,
while preserving the current value formatting and workspace argument behavior.

In `@apps/api/src/scaling/engine.ts`:
- Around line 60-61: Update the project handling around getProjectById so a
missing or non-positive project.cpuLimit does not exit before scale-down
cleanup. Disable the scaling policy or reconcile existing replicas down to
minReplicas, then return; preserve normal scaling behavior when a valid CPU
limit exists.
- Line 283: Update Caddy route generation in
apps/api/src/scaling/engine.ts:283-283 and
apps/api/src/utils/domain-verifier.ts:147-147 so reverse_proxy target parsing
excludes the trailing “{” before counting replicas, or centralize generation to
ensure both use the same compatible format. Add regression coverage in
apps/api/src/utils/__tests__/domain-verifier.test.ts:154-160 verifying
block-style reverse_proxy output counts replicas correctly.
- Line 65: Update the scaling slug construction in the relevant scaling flow to
use the persisted project slug or a collision-safe value that includes the
canonical projectId after sanitization. Ensure the resulting routing slug is
always non-empty and unique, including for names that normalize identically or
contain only punctuation/whitespace, and keep it consistent with the slug used
by saveProject.

In `@apps/api/src/utils/env-filter.ts`:
- Around line 27-29: Remove SENTRY_AUTH_TOKEN from BUILD_SAFE_EXACT in
apps/api/src/utils/env-filter.ts (lines 27-29). In
apps/api/src/utils/__tests__/env-filter.test.ts (lines 48-56), add an assertion
confirming SENTRY_AUTH_TOKEN is rejected by the filter.

In `@apps/docs/src/content/changelogs/v0.2.1.md`:
- Line 11: Update the changelog entry to use the API’s consistent camelCase
field names, replacing project_type with projectType while preserving
buildCommand and startCommand.

In `@apps/web/src/components/project/create/CreateProjectDialog.tsx`:
- Around line 63-64: Update the dialog close-reset branch to call
setProjectType("web") alongside the existing creation-field resets, ensuring a
canceled static-project draft does not affect the next project.

In `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx`:
- Around line 89-204: Remove the redundant JSX label comments in the project
settings form, including “Project Type,” “Root Directory / Source Dir,”
“Internal Port,” “Build Command Override,” and “Start Command Override,” while
leaving the surrounding controls and behavior unchanged.
- Around line 43-47: Update the project settings payload around port to accept
only integer values in the range 1–65535, using null for blank input and
rejecting invalid values rather than persisting them. Apply the same bounds
validation in the PATCH handler before saving, including values forwarded
through the existing persistence path.

---

Outside diff comments:
In `@apps/api/src/orchestrator/pipeline.ts`:
- Around line 391-411: Update the environment argument in the envVars lookup
within the build pipeline before buildWithRailpack, replacing the hardcoded
"production" value with deployment.environment ?? undefined. Keep the existing
filterBuildEnvVars and buildWithRailpack flow unchanged.
- Around line 284-705: Refactor the oversized runDeployment method in the
deployment orchestrator into cohesive modules under a focused orchestrator
feature folder, keeping pipeline.ts below 500 lines. Extract the build/source
preparation flow, runtime deployment configuration and execution, and
rollback/failure cleanup responsibilities into appropriately named helpers or
services, while preserving runDeployment’s existing status updates, cancellation
handling, cleanup, and return behavior.

In `@apps/docs/.astro/astro/content.d.ts`:
- Around line 143-165: Regenerate the ContentEntryMap in the generated content
types so the “changelogs” collection includes the new “v0.2.1.md” entry and
remove the unrelated “docs/changelog.md” entry if it was generated incorrectly.
Use the Astro sync workflow to update the generated artifact, or configure the
project to ignore “apps/docs/.astro/” so committed generated types no longer
drift.

In `@apps/web/src/components/project/create/CreateProjectDialog.tsx`:
- Around line 381-499: Split the oversized project-creation components into
feature-focused modules while preserving behavior: in
apps/web/src/components/project/create/CreateProjectDialog.tsx lines 381-499,
extract the step orchestration/rendering around StepBasics, StepEnvironment, and
StepResources into focused components or hooks; in
apps/web/src/components/project/create/StepBasics.tsx lines 180-222, extract the
general-settings and source-details sections into grouped child components. Keep
the extracted modules within the create feature area and ensure both original
files remain under 500 lines.

---

Nitpick comments:
In `@apps/api/src/orchestrator/railpack-config-utils.ts`:
- Around line 385-465: Remove the synthetic workspace metadata and dependency
version substitution around commonDeps and the cargoContent replacement loop.
Validate that the selected source directory includes the workspace root and fail
with a clear “workspace root not found in the selected source dir” error when it
does not, rather than guessing versions, edition, or rust-version; preserve
existing content when the workspace root is present.
- Around line 112-116: Replace the broad Record<string, any> annotation on
config with a focused interface describing caches, steps, and
deploy.startCommand. Use that typed config throughout the surrounding utility so
misspelled keys in its branches are caught at compile time, while preserving the
existing defaults and behavior.

In `@apps/api/src/scaling/__tests__/engine.test.ts`:
- Line 95: Add regression tests in the engine test suite for missing projects
and non-positive CPU limits, covering the new guard behavior. Extend the
scale-up success case to verify the generated command forwards both --cpus and
--memory values, and run bun test from apps/api before committing.

In `@apps/docs/src/content/changelogs/v0.2.1.md`:
- Around line 8-15: Move the entries for Caddy Host-header forwarding, runtime
reconciliation skipping non-existent containers, and Docker-compose
configuration from the “Improvements” section into “Bug Fixes” in the changelog.
Leave the remaining improvement entries unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 48e6b465-6efc-4bed-9a97-3935d3d2b5ac

📥 Commits

Reviewing files that changed from the base of the PR and between 915d9bb and 3bb1afe.

📒 Files selected for processing (44)
  • VERSION
  • apps/api/package.json
  • apps/api/src/api/deployments/index.ts
  • apps/api/src/api/projects/index.ts
  • apps/api/src/api/scaling/index.ts
  • apps/api/src/db/migrate.ts
  • apps/api/src/db/migrations/0002_colossal_flatman.sql
  • apps/api/src/db/migrations/0003_aberrant_viper.sql
  • apps/api/src/db/migrations/meta/0002_snapshot.json
  • apps/api/src/db/migrations/meta/0003_snapshot.json
  • apps/api/src/db/migrations/meta/_journal.json
  • apps/api/src/db/repo/deployments.ts
  • apps/api/src/db/repo/projects.ts
  • apps/api/src/db/schema.ts
  • apps/api/src/orchestrator/pipeline.ts
  • apps/api/src/orchestrator/railpack-config-utils.ts
  • apps/api/src/orchestrator/railpack.ts
  • apps/api/src/orchestrator/runtime.ts
  • apps/api/src/scaling/__tests__/engine.test.ts
  • apps/api/src/scaling/engine.ts
  • apps/api/src/types.ts
  • apps/api/src/utils/__tests__/domain-verifier.test.ts
  • apps/api/src/utils/__tests__/env-filter.test.ts
  • apps/api/src/utils/domain-verifier.ts
  • apps/api/src/utils/env-filter.ts
  • apps/docs/.astro/astro/content.d.ts
  • apps/docs/package.json
  • apps/docs/src/content/changelogs/v0.2.1.md
  • apps/web/package.json
  • apps/web/src/api/client.ts
  • apps/web/src/components/layout/Sidebar.tsx
  • apps/web/src/components/layout/SupportSection.tsx
  • apps/web/src/components/project/create/CreateProjectDialog.tsx
  • apps/web/src/components/project/create/StepBasics.tsx
  • apps/web/src/components/project/deployments/deployment-logs.tsx
  • apps/web/src/components/project/settings/ProjectSettingsTab.tsx
  • apps/web/src/hooks/useProjects.ts
  • apps/web/src/index.css
  • apps/web/src/routes/ProjectDetail.tsx
  • apps/web/src/types/index.ts
  • docker-compose.yml
  • package.json
  • scripts/dequel
  • scripts/install.sh
💤 Files with no reviewable changes (1)
  • apps/web/src/index.css

Comment thread apps/api/package.json
},
"dependencies": {
"@elysiajs/cors": "^1.1.1",
"@sinclair/typebox": "^0.34.13",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
curl -s https://registry.npmjs.org/elysia/1.1.26 | jq '.dependencies["`@sinclair/typebox`"]'
curl -s https://registry.npmjs.org/@sinclair/typebox | jq '."dist-tags"'

Repository: Lftobs/dequel

Length of output: 490


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== apps/api/package.json relevant dependencies =="
python3 - <<'PY'
import json, pathlib
p=pathlib.Path('apps/api/package.json')
if p.exists():
    data=json.loads(p.read_text())
    for sec in ['dependencies','devDependencies','peerDependencies']:
        vals={k:v for k,v in data.get(sec,{}).items() if k in {'`@sinclair/typebox`','elysia'} or k.startswith('`@sinclair/typebox`')}
        if vals:
            print(sec, vals)
PY

echo
echo "== elysia package files mentioning TypeBox references =="
git ls-files '*.js' '*.ts' 'apps/**' 'packages/**' 2>/dev/null | rg 'packages|apps' | head -100
echo
rg -n "Symbol\.for\('TypeBox\.Kind'\)|function TypeBox|TypeBox\.Kind|Symbol\.FOR|Elysia" package.json apps packages 2>/dev/null || true

echo
echo "== lockfile `@sinclair/typebox` resolution snippets =="
for f in package-lock.json pnpm-lock.yaml yarn.lock bun.lockb bun.lock apps/api/package-lock.json apps/api/pnpm-lock.yaml apps/api/yarn.lock; do
  if [ -f "$f" ]; then
    echo "--- $f"
    rg -n -A2 -B2 '`@sinclair/typebox`|elysia' "$f" | head -200
  fi
done

echo
echo "== elysia 1.1.26 package registry summary =="
curl -s https://registry.npmjs.org/elysia/1.1.26 | jq '{version, dependencies, peerDependencies}'
echo
echo "== elysia 1.1.x `@sinclair/typebox` range across patch/minor if available =="
for patch in 1.1.0 1.1.1 1.1.10 1.1.20 1.1.26; do
  echo "--- $patch"
  curl -s "https://registry.npmjs.org/elysia/$patch" | jq '{version, dependencies, peerDependencies}' | rg '"`@sinclair/typebox`"|"Version|"Peer'
done

echo
echo "== local typebox import snippets =="
rg -n '"`@sinclair/typebox`"|from "`@sinclair/typebox`"|require\("`@sinclair/typebox`"\)' apps/api -S 2>/dev/null || true

Repository: Lftobs/dequel

Length of output: 7245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== bun.lock `@sinclair/typebox` entries =="
if [ -f apps/api/bun.lock ]; then
  rg -n -A3 -B3 '`@sinclair/typebox`' apps/api/bun.lock
else
  echo "apps/api/bun.lock not found"
fi

echo
echo "== npm elysia 1.1.26 package tarball TypeBox file references =="
tmp="$(mktemp -d)"
curl -sL https://registry.npmjs.org/elysia/-/elysia-1.1.26.tgz -o "$tmp/elysia.tgz"
tar -xzf "$tmp/elysia.tgz" -C "$tmp"
rg -n "TypeBox\.Kind|Symbol\.for|`@sinclair/typebox`" "$tmp/package"/dist "$tmp/package/src" 2>/dev/null | head -200 || true
echo
echo "== `@sinclair/typebox` 0.32.34 and 0.34.13 Kind symbol =="
for v in 0.32.34 0.34.13; do
  echo "--- $v"
  curl -sL "https://registry.npmjs.org/@sinclair%2ftypebox/-/typebox-$v.tgz" -o "$tmp/typebox-$v.tgz"
  tar -xzf "$tmp/typebox-$v.tgz" -C "$tmp"
  rg -n "Symbol\.for\('TypeBox\.Kind'\)|let Kind|exports\.Kind" "$tmp/package/src" | head -100
done

Repository: Lftobs/dequel

Length of output: 24922


🏁 Script executed:

#!/bin/bash
set -euo pipefail

tmp="$(mktemp -d)"

echo "== elysia latest package summary =="
curl -s https://registry.npmjs.org/elysia/latest\?metadata=true | jq '{latest: ."dist-tags".latest, version: .version, dependencies: .dependencies, peerDependencies: .peerDependencies}'

echo
echo "== bun.lock package map around elysia/typebox/exact =="
python3 - <<'PY'
from pathlib import Path
p = Path('apps/api/bun.lock')
text = p.read_text(errors='replace').splitlines()
for i,line in enumerate(text,1):
    if any(pkg in line for pkg in ['`@sinclair/typebox`', 'elysia', 'exact-mirror']):
        start=max(1,i-2); end=min(len(text),i+3)
        print(f'[{i}] {line}')
        for n in range(start,end+1):
            if n!=i:
                print(f'[{n}] {text[n-1]}')
        print()
PY

echo
echo "== TypeBox 0.32.34 Kind export =="
curl -sL "https://registry.npmjs.org/@sinclair%2ftypebox/-/typebox-0.32.34.tgz" -o "$tmp/tbox-0.32.34.tgz"
tar -xzf "$tmp/tbox-0.32.34.tgz" -C "$tmp/0.32"
rg -n "KindSymbol|Symbol\.for\(\"TypeBox\.Kind\"\)|exports\.Kind|return .*KindSymbol" "$tmp/0.32/package" | head -50

echo
echo "== TypeBox 0.34.13 Kind export =="
curl -sL "https://registry.npmjs.org/@sinclair%2ftypebox/-/typebox-0.34.13.tgz" -o "$tmp/tbox-0.34.13.tgz"
tar -xzf "$tmp/tbox-0.34.13.tgz" -C "$tmp/0.34"
rg -n "KindSymbol|Symbol\.for\(\"TypeBox\.Kind\"\)|exports\.Kind|return .*KindSymbol" "$tmp/0.34/package" | head -50

echo
echo "== npm tarball source file names containing KindSymbol =="
for v in 0.32.34 0.34.13; do
  echo "--- $v"
  tar -tzf "$tmp/tbox-$v.tgz" | rg 'KindSymbol|value|index|system' | head -80
done

echo
echo "== TypeBox KindSymbol definition files =="
for file in "$tmp/0.32/package/src/type-system.ts" "$tmp/0.32/package/src/type.ts" "$tmp/0.34/package/src/type-system.ts" "$tmp/0.34/package/src/type.ts"; do
  if [ -f "$file" ]; then
    echo "--- $file"
    rg -n -C 5 "KindSymbol|Symbol\.for\(\"TypeBox\.Kind\"\)" "$file" || true
  fi
done

Repository: Lftobs/dequel

Length of output: 7105


Align @sinclair/typebox with the installed Elysia package.

apps/api/package.json declares elysia: ^1.1.26, but apps/api/bun.lock resolves elysia@1.4.28, whose peer dependency requires @sinclair/typebox >= 0.34.0 < 1. If you stay with Elysia 1.1.x, update the lockfile to match; if Elysia 1.4.x is intended, update the package range to avoid drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/package.json` at line 13, Align the Elysia and `@sinclair/typebox`
dependency declarations in apps/api: either update the lockfile to resolve
elysia within the declared ^1.1.26 range, or, if the resolved 1.4.x version is
intended, update the elysia range in package.json accordingly while retaining a
compatible `@sinclair/typebox` range.

Comment on lines +69 to +70
buildCommand: "buildCommand" in (body ?? {}) ? (body.buildCommand ?? "") || null : undefined,
startCommand: "startCommand" in (body ?? {}) ? (body.startCommand ?? "") || null : undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard primitive PATCH bodies before using in.

Because body is any, a valid JSON string or number can reach this handler. Lines [69-70] then throw a TypeError because the right-hand operand of in must be an object, producing a 500 instead of a controlled 4xx response. Validate that body is a non-null object before these checks and add a regression test.

Suggested fix
 async ({ params: { id }, body, set }: any) => {
+  if (body === null || typeof body !== "object" || Array.isArray(body)) {
+    set.status = 400;
+    return { error: "body must be an object" };
+  }
+
   const project = await updateProject(id, {
...
-    buildCommand: "buildCommand" in (body ?? {}) ? ...
+    buildCommand: Object.prototype.hasOwnProperty.call(body, "buildCommand") ? ...
📝 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
buildCommand: "buildCommand" in (body ?? {}) ? (body.buildCommand ?? "") || null : undefined,
startCommand: "startCommand" in (body ?? {}) ? (body.startCommand ?? "") || null : undefined,
async ({ params: { id }, body, set }: any) => {
if (body === null || typeof body !== "object" || Array.isArray(body)) {
set.status = 400;
return { error: "body must be an object" };
}
const project = await updateProject(id, {
buildCommand: Object.prototype.hasOwnProperty.call(body, "buildCommand") ? (body.buildCommand ?? "") || null : undefined,
startCommand: Object.prototype.hasOwnProperty.call(body, "startCommand") ? (body.startCommand ?? "") || null : undefined,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/api/projects/index.ts` around lines 69 - 70, Guard the PATCH
request body before the `"buildCommand" in ...` and `"startCommand" in ...`
checks: require a non-null object and return the handler’s established
controlled 4xx response for primitive or otherwise invalid bodies. Preserve the
existing command normalization for valid object bodies, and add a regression
test covering JSON string or number payloads.

Comment on lines +32 to +86
try {
const entries = await readdir(dir, {
withFileTypes: true,
});
for (const entry of entries) {
const fullPath = join(
dir,
entry.name,
);
if (entry.isDirectory()) {
if (ignoreDirs.has(entry.name)) {
continue;
}
await rewriteLocalhostBinding(
fullPath,
onLog,
);
} else if (entry.isFile()) {
const ext = entry.name
.split(".")
.pop();
if (ext && allowedExts.has(ext)) {
try {
let content =
await Bun.file(
fullPath,
).text();
if (
content.includes(
"127.0.0.1",
)
) {
content =
content.replaceAll(
"127.0.0.1",
"0.0.0.0",
);
await Bun.write(
fullPath,
content,
);
await onLog(
`Auto-rewrote 127.0.0.1 to 0.0.0.0 in ${entry.name} for container compatibility.`,
);
}
} catch {
// Ignore read errors
}
}
}
}
} catch {
// Ignore readdir/directory access errors
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Blanket 127.0.0.1 → 0.0.0.0 rewrite over the whole tree can corrupt user code and config.

This mutates every .json/.toml/.yml/.py/.java… file under the build dir, not just server bind addresses. Things like DB/test/proxy targets, allow-lists, and fixture data pointing at loopback get silently rewritten, and the failure only shows up at runtime. Consider restricting to detected bind/listen patterns (e.g. 127.0.0.1:<port> adjacent to listen/bind/host) or gating it behind an opt-in project setting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/orchestrator/railpack-config-utils.ts` around lines 32 - 86,
Restrict rewriteLocalhostBinding so it only changes loopback values used in
detected server bind/listen configuration, such as 127.0.0.1:<port> near listen,
bind, or host settings, rather than replacing every occurrence in allowed files.
Preserve unrelated database targets, allow-lists, proxy settings, and fixture
data; alternatively require an explicit project opt-in before applying the
rewrite.

Comment on lines +231 to +314
const hasServerScript = !!scripts.server;
const isStatic = projectType === "static" || (!scripts.start && !hasServerScript && (scripts.build || hasPackageJson));

if (isStatic) {
const serveScript = `
const fs = require("fs");
const path = require("path");
const PORT = Number(process.env.PORT || 3000);
const cleanSourceDir = "${cleanSourceDir}";
let staticDir = ".";
const candidates = [
path.join(cleanSourceDir, "dist"),
path.join(cleanSourceDir, "build"),
path.join(cleanSourceDir, "out"),
path.join(cleanSourceDir, "public"),
"dist",
"build",
"out",
"public",
"."
];
for (const dir of candidates) {
const fullPath = path.join(process.cwd(), dir);
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) {
if (fs.existsSync(path.join(fullPath, "index.html"))) {
staticDir = dir;
break;
}
}
}
console.log("Serving static directory:", staticDir, "on port", PORT);
Bun.serve({
port: PORT,
async fetch(req) {
const url = new URL(req.url);
let decodedPathname = "/";
try {
decodedPathname = decodeURIComponent(url.pathname);
} catch {
decodedPathname = url.pathname;
}
let filePath = path.join(staticDir, decodedPathname);
if (decodedPathname.endsWith("/")) {
filePath = path.join(filePath, "index.html");
}
let file = Bun.file(filePath);
if (await file.exists()) {
return new Response(file, {
headers: {
"content-type": file.type || "application/octet-stream"
}
});
}
const fallbackPath = path.join(staticDir, "index.html");
const fallbackFile = Bun.file(fallbackPath);
if (await fallbackFile.exists()) {
return new Response(fallbackFile, {
headers: {
"content-type": fallbackFile.type || "text/html"
}
});
}
return new Response("Not Found", { status: 404 });
}
});
`;
await Bun.write(join(workspace, "dequel-serve.js"), serveScript);
config.deploy.startCommand = "bun dequel-serve.js";
} else if (scripts.start) {
config.deploy.startCommand =
cleanSourceDir
? `cd ${cleanSourceDir} && ${pm} run start`
: `${pm} run start`;
} else if (scripts.server) {
config.deploy.startCommand =
cleanSourceDir
? `cd ${cleanSourceDir} && ${pm} run server`
: `${pm} run server`;
} else {
config.deploy.startCommand =
cleanSourceDir
? `cd ${cleanSourceDir} && node dist/index.js`
: "node dist/index.js";
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

isStatic misclassifies Node services and makes the node dist/index.js fallback unreachable.

hasPackageJson is always true inside this branch, so the condition collapses to !scripts.start && !scripts.server. Any Node backend without a start script (bin entry, main, node server.js documented in README) is deployed as a static file server, and the else at Line 309 is dead code. Also, bun dequel-serve.js assumes bun exists in the runtime image even when pm is npm/yarn/pnpm.

🐛 Suggested tightening
-			const hasServerScript = !!scripts.server;
-			const isStatic = projectType === "static" || (!scripts.start && !hasServerScript && (scripts.build || hasPackageJson));
+			const hasServerScript = !!scripts.server;
+			const isStatic =
+				projectType === "static" ||
+				(!projectType && !scripts.start && !hasServerScript && !!scripts.build);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/orchestrator/railpack-config-utils.ts` around lines 231 - 314,
Update the isStatic classification in the surrounding configuration flow so Node
services without scripts.start or scripts.server are not treated as static
solely because hasPackageJson is true; reserve static deployment for explicit
static projects or reliably identified static builds. Preserve the node
dist/index.js fallback in the final else branch for backend services, and avoid
generating a Bun-dependent serve command when the selected package
manager/runtime is not Bun by using a compatible serving strategy.

Comment on lines +235 to +239
const serveScript = `
const fs = require("fs");
const path = require("path");
const PORT = Number(process.env.PORT || 3000);
const cleanSourceDir = "${cleanSourceDir}";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Unescaped interpolation of cleanSourceDir into a generated JS string literal.

A source dir containing ", \, or a newline produces a syntactically broken dequel-serve.js (or injects code). Use JSON.stringify(cleanSourceDir) instead of manual quoting.

🛡️ Proposed fix
-const cleanSourceDir = "${cleanSourceDir}";
+const cleanSourceDir = ${JSON.stringify(cleanSourceDir)};
📝 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 serveScript = `
const fs = require("fs");
const path = require("path");
const PORT = Number(process.env.PORT || 3000);
const cleanSourceDir = "${cleanSourceDir}";
const serveScript = `
const fs = require("fs");
const path = require("path");
const PORT = Number(process.env.PORT || 3000);
const cleanSourceDir = ${JSON.stringify(cleanSourceDir)};
`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/orchestrator/railpack-config-utils.ts` around lines 235 - 239,
Update the serveScript template construction to interpolate cleanSourceDir using
JSON.stringify(cleanSourceDir), preserving valid and non-injectable JavaScript
string syntax for quotes, backslashes, and newlines.

Comment on lines +27 to +29
"SENTRY_DSN",
"SENTRY_AUTH_TOKEN",
]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not classify SENTRY_AUTH_TOKEN as build-safe.

Decrypted project variables that pass this filter are forwarded to Railpack as build-time --env values. This allowlist entry exposes a credential to arbitrary build commands and conflicts with the test suite’s secret-rejection policy.

  • apps/api/src/utils/env-filter.ts#L27-L29: remove SENTRY_AUTH_TOKEN from BUILD_SAFE_EXACT.
  • apps/api/src/utils/__tests__/env-filter.test.ts#L48-L56: add an assertion that SENTRY_AUTH_TOKEN is rejected.
📍 Affects 2 files
  • apps/api/src/utils/env-filter.ts#L27-L29 (this comment)
  • apps/api/src/utils/__tests__/env-filter.test.ts#L48-L56
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/utils/env-filter.ts` around lines 27 - 29, Remove
SENTRY_AUTH_TOKEN from BUILD_SAFE_EXACT in apps/api/src/utils/env-filter.ts
(lines 27-29). In apps/api/src/utils/__tests__/env-filter.test.ts (lines 48-56),
add an assertion confirming SENTRY_AUTH_TOKEN is rejected by the filter.

- Caddy reverse proxy now passes the Host header correctly to upstream containers ([f20e3fa](https://github.com/Lftobs/dequel/commit/f20e3fa))
- Runtime reconciliation skips non-existent containers ([dc4593c](https://github.com/Lftobs/dequel/commit/dc4593c))
- Docker-compose configuration updated for local builds ([dc4593c](https://github.com/Lftobs/dequel/commit/dc4593c))
- Add `project_type`, `buildCommand`, and `startCommand` fields to projects ([f20e3fa](https://github.com/Lftobs/dequel/commit/f20e3fa))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Inconsistent field naming in a user-facing changelog.

project_type is snake_case while buildCommand/startCommand are camelCase. Pick one representation (API field names are projectType, buildCommand, startCommand).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/docs/src/content/changelogs/v0.2.1.md` at line 11, Update the changelog
entry to use the API’s consistent camelCase field names, replacing project_type
with projectType while preserving buildCommand and startCommand.

Comment on lines +63 to +64
const [projectType, setProjectType] =
useState("web");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reset the project type when the dialog closes.

Canceling a static-project draft leaves projectType set to static for the next project, while every other creation field is reset. Add setProjectType("web") in the close-reset branch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/project/create/CreateProjectDialog.tsx` around lines
63 - 64, Update the dialog close-reset branch to call setProjectType("web")
alongside the existing creation-field resets, ensuring a canceled static-project
draft does not affect the next project.

Comment on lines +43 to +47
sourceDir: sourceDir.trim() || null,
buildCommand: buildCommand.trim() || null,
startCommand: startCommand.trim() || null,
port: port.trim() ? Number(port) || null : null,
description: description.trim() || null,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject invalid port values instead of persisting them.

Number(port) || null accepts values such as -1 and 70000; this form has no bounds, and the supplied PATCH handler forwards truthy values to persistence. Validate integer ports in 1..65535 here and enforce the same range in the API before saving.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx` around lines
43 - 47, Update the project settings payload around port to accept only integer
values in the range 1–65535, using null for blank input and rejecting invalid
values rather than persisting them. Apply the same bounds validation in the
PATCH handler before saving, including values forwarded through the existing
persistence path.

Comment on lines +89 to +204
{/* Project Type */}
<div className="space-y-2.5">
<label className="font-semibold text-xs text-zinc-400">
Project Type
</label>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<button
type="button"
onClick={() => setProjectType("web")}
className={cn(
"flex flex-col items-start gap-2 p-4 rounded-xl border text-left transition-all select-none active:scale-[0.98]",
projectType === "web"
? "border-amber-500/30 bg-amber-500/5 text-zinc-200"
: "border-[#222227] bg-[#141418] hover:bg-[#1a1a20] text-zinc-400"
)}
>
<div className="flex items-center gap-1.5 font-bold text-xs text-zinc-250">
<Box className="h-4 w-4 text-amber-500" />
Web Application
</div>
<span className="text-[10px] text-zinc-500 leading-relaxed">
Build and launch standard persistent backend engines or databases (Node.js, Rust, Go, Python, APIs).
</span>
</button>
<button
type="button"
onClick={() => setProjectType("static")}
className={cn(
"flex flex-col items-start gap-2 p-4 rounded-xl border text-left transition-all select-none active:scale-[0.98]",
projectType === "static"
? "border-amber-500/30 bg-amber-500/5 text-zinc-200"
: "border-[#222227] bg-[#141418] hover:bg-[#1a1a20] text-zinc-400"
)}
>
<div className="flex items-center gap-1.5 font-bold text-xs text-zinc-250">
<Globe className="h-4 w-4 text-amber-500" />
Static Site
</div>
<span className="text-[10px] text-zinc-500 leading-relaxed">
Generate static client bundles (Vite, Astro, Vue) served automatically by Dequel's SPA static web server.
</span>
</button>
</div>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
{/* Root Directory / Source Dir */}
<div className="space-y-2">
<label htmlFor="sourceDir" className="font-semibold text-xs text-zinc-400">
Root Directory
</label>
<Input
id="sourceDir"
placeholder="e.g. apps/web (leave empty for repo root)"
className="bg-[#141418] border-[#222227] focus:border-amber-500 text-zinc-200 text-xs h-9 rounded-lg"
value={sourceDir}
onChange={(e) => setSourceDir(e.target.value)}
/>
<p className="text-[10px] text-zinc-500 leading-normal">
Path inside your repository where build operations should run.
</p>
</div>

{/* Internal Port */}
<div className="space-y-2">
<label htmlFor="port" className="font-semibold text-xs text-zinc-400">
Port
</label>
<Input
id="port"
type="number"
placeholder="e.g. 3000"
className="bg-[#141418] border-[#222227] focus:border-amber-500 text-zinc-200 text-xs h-9 rounded-lg"
value={port}
onChange={(e) => setPort(e.target.value)}
/>
<p className="text-[10px] text-zinc-500 leading-normal">
The internal port number your application container listens on.
</p>
</div>

{/* Build Command Override */}
<div className="space-y-2">
<label htmlFor="buildCommand" className="font-semibold text-xs text-zinc-400">
Build Command
</label>
<Input
id="buildCommand"
placeholder="e.g. npm run build (leave empty for auto)"
className="bg-[#141418] border-[#222227] focus:border-amber-500 text-zinc-200 text-xs h-9 rounded-lg font-mono"
value={buildCommand}
onChange={(e) => setBuildCommand(e.target.value)}
/>
<p className="text-[10px] text-zinc-500 leading-normal">
Override the build command execution. Leave blank to let Dequel auto-detect it.
</p>
</div>

{/* Start Command Override */}
<div className="space-y-2">
<label htmlFor="startCommand" className="font-semibold text-xs text-zinc-400">
Start Command
</label>
<Input
id="startCommand"
placeholder="e.g. node dist/index.js (leave empty for auto)"
className="bg-[#141418] border-[#222227] focus:border-amber-500 text-zinc-200 text-xs h-9 rounded-lg font-mono"
value={startCommand}
onChange={(e) => setStartCommand(e.target.value)}
/>
<p className="text-[10px] text-zinc-500 leading-normal">
Override the launch start command. Leave blank to let Dequel auto-detect it.
</p>
</div>

{/* Description */}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the redundant JSX comments.

These comments only label the immediately following controls and are not necessary.

As per coding guidelines, **/*.{ts,tsx,js,jsx} permits no source comments unless absolutely necessary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx` around lines
89 - 204, Remove the redundant JSX label comments in the project settings form,
including “Project Type,” “Root Directory / Source Dir,” “Internal Port,” “Build
Command Override,” and “Start Command Override,” while leaving the surrounding
controls and behavior unchanged.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant