Skip to content

Chore/UI - #36

Merged
Lftobs merged 7 commits into
devfrom
chore/ui
Aug 12, 2026
Merged

Lftobs merged 7 commits into
devfrom
chore/ui

Conversation

@Lftobs

@Lftobs Lftobs commented Aug 8, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added a streamlined project creation flow with Git, ZIP, and Docker Compose sources.
    • Added framework presets, project type selection, build configuration, environment-variable management, and custom project details.
    • Added searchable framework and database selectors with recognizable logos.
    • Added support for upload-based project creation and deployment cache clearing.
    • Added install-command and output-directory settings for web and static projects.
  • Bug Fixes

    • Improved static project detection and deployment error-log recognition.
    • Updated default PostgreSQL selection to version 16.

Lftobs added 3 commits August 4, 2026 17:01
…oyment errors

Add install_command and output_dir project columns (migration 0008) and
wire them through the railpack config generator. Summarize deployment and
rollback failures to the most actionable line instead of the full raw
stderr transcript.
@coderabbitai

coderabbitai Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request replaces the multi-step project creation flow with a single-page form. It adds framework presets, reusable selectors, source uploads, environment-variable staging, Compose mappings, project settings fields, and expanded Railpack static-project handling.

Changes

Project creation and configuration

Layer / File(s) Summary
Preset catalogs and reusable selectors
apps/web/src/utils/presets.ts, apps/web/src/components/logos/*, apps/web/src/components/ui/*, apps/web/src/types/index.ts
Adds framework presets, logos, searchable framework selection, database metadata, shared project input types, and project-name slugification.
Dedicated project creation sections
apps/web/src/components/project/create/*
Adds controlled sections for project metadata, source selection, build strategy, import details, and environment variables.
Project creation submission flow
apps/web/src/routes/CreateProjectPage.tsx, apps/web/src/api/client.ts
Adds ZIP uploads, preset-derived settings, Compose serialization, sequential environment-variable creation, cleanup on failure, and post-creation navigation.
Project settings persistence
apps/web/src/components/project/settings/ProjectSettingsTab.tsx, apps/web/src/components/project/deployments/DeploymentsTab.tsx
Adds project-type, install-command, output-directory, and clear-cache controls.
Database selection and deployment logs
apps/web/src/components/databases/CreateDatabaseDialog.tsx, apps/web/src/components/project/deployments/deployment-logs.tsx
Uses shared database selection and classifies deployment and rollback failures as errors.
Railpack configuration
apps/api/src/orchestrator/railpack-config-utils.ts, apps/api/src/orchestrator/pipeline.ts, apps/api/src/orchestrator/__tests__/railpack-config.test.ts
Adds source-directory manifests, broader static detection, generated static-server configuration, command overrides, complete build environment variables, and tests.
Local Compose build wiring
docker-compose.yml
Builds the API and web services from local directories and passes DEQUEL_VERSION to the web build.

Estimated code review effort: 5 (Critical) | ~90 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant CreateProjectPage
  participant SourceSelectionSection
  participant uploadSourceZip
  participant ProjectAPI
  participant setEnvVar
  SourceSelectionSection->>CreateProjectPage: select source
  CreateProjectPage->>uploadSourceZip: upload ZIP when selected
  uploadSourceZip->>ProjectAPI: POST multipart data to /upload
  ProjectAPI-->>CreateProjectPage: return filePath
  CreateProjectPage->>ProjectAPI: create project
  CreateProjectPage->>setEnvVar: create staged variables sequentially
  setEnvVar->>ProjectAPI: create environment variable
  ProjectAPI-->>CreateProjectPage: return project id
  CreateProjectPage->>CreateProjectPage: navigate to deployments tab
Loading
🚥 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 references UI work but is too broad to identify the main changes, which include project creation, build configuration, and deployment updates. Use a specific title that summarizes the project creation flow and build configuration changes.
✅ 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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/ui

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 marked this pull request as draft August 8, 2026 00:23

@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: 18

🧹 Nitpick comments (11)
apps/web/src/components/project/create/SourceSelectionSection.tsx (1)

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

Remove nonessential JSX section comments. The adjacent JSX already identifies these sections.

  • apps/web/src/components/project/create/SourceSelectionSection.tsx#L55-L55: delete the section comments at Lines 55, 102, and 154.
  • apps/web/src/components/project/create/ApplicationPresetSection.tsx#L32-L32: delete the section comment at Line 32.
  • apps/web/src/components/project/create/BuildStrategySection.tsx#L76-L76: delete the section comments at Lines 76, 123, 126, 137, 187, and 266.

As per coding guidelines, “No comments in source code 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/create/SourceSelectionSection.tsx` at line
55, Remove the nonessential JSX section comments from SourceSelectionSection.tsx
at lines 55, 102, and 154; ApplicationPresetSection.tsx at line 32; and
BuildStrategySection.tsx at lines 76, 123, 126, 137, 187, and 266. Leave the
surrounding JSX and behavior unchanged.

Source: Coding guidelines

apps/web/src/components/ui/DatabaseSelect.tsx (2)

60-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add aria-expanded and Escape-key dismissal.

The trigger button exposes no expanded state to assistive technology. The dropdown also cannot be closed with the keyboard. Add aria-expanded={isOpen} and aria-haspopup="listbox" on the trigger, and close on Escape. Attach the outside-click listener only when isOpen is true.

♻️ Proposed fix
   useEffect(() => {
+    if (!isOpen) return;
     function handleClickOutside(event: MouseEvent) {
       if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
         setIsOpen(false);
       }
     }
+    function handleKeyDown(event: KeyboardEvent) {
+      if (event.key === 'Escape') setIsOpen(false);
+    }
     document.addEventListener('mousedown', handleClickOutside);
-    return () => document.removeEventListener('mousedown', handleClickOutside);
-  }, []);
+    document.addEventListener('keydown', handleKeyDown);
+    return () => {
+      document.removeEventListener('mousedown', handleClickOutside);
+      document.removeEventListener('keydown', handleKeyDown);
+    };
+  }, [isOpen]);
       <button
         type="button"
+        aria-expanded={isOpen}
+        aria-haspopup="listbox"
         onClick={() => setIsOpen(!isOpen)}
🤖 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/ui/DatabaseSelect.tsx` around lines 60 - 98, Update
the trigger button in DatabaseSelect to include aria-expanded={isOpen} and
aria-haspopup="listbox". Modify the outside-click useEffect to register its
listener only while isOpen, and add Escape-key handling that calls
setIsOpen(false) when the dropdown is open; ensure cleanup removes any
registered listeners.

14-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse DATABASE_ENGINES for default versions.

apps/web/src/components/databases/CreateDatabaseDialog.tsx (lines 32-34) repeats these same defaults in a nested ternary. Two sources of truth will drift. Derive the version from this catalog in the dialog.

♻️ Proposed change in `apps/web/src/components/databases/CreateDatabaseDialog.tsx`
-	useEffect(() => {
-		setVersion(type === "postgresql" ? "16" : type === "mysql" ? "8.4" : type === "redis" ? "7.4" : type === "mongodb" ? "7.0" : "11.4");
-	}, [type]);
+	useEffect(() => {
+		const engine = DATABASE_ENGINES.find((item) => item.type === type);
+		if (engine) setVersion(engine.defaultVersion);
+	}, [type]);
🤖 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/ui/DatabaseSelect.tsx` around lines 14 - 45, Update
CreateDatabaseDialog’s default-version selection to derive the matching
defaultVersion from the DATABASE_ENGINES catalog instead of using the duplicated
nested ternary. Reuse the database type selected by the dialog and preserve the
existing behavior for supported engines.
apps/web/src/types/index.ts (1)

30-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align optionality with the sibling command fields.

buildCommand and startCommand are declared as required and nullable. Marking installCommand and outputDir optional makes consumers handle undefined as well as null. If the API always returns these fields, drop the ?.

🤖 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/types/index.ts` around lines 30 - 31, Update the type
declaration containing installCommand and outputDir to remove the optional ?
markers, matching the required-but-nullable declarations of the sibling
buildCommand and startCommand fields; keep their string | null value types
unchanged.
apps/web/src/routes/CreateProjectPage.tsx (2)

167-170: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

The navigation timer is not cleared.

setTimeout is not stored, so it cannot be cleared if the user leaves the page during the one-second delay. Store the id and clear it in an effect cleanup.

🤖 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/routes/CreateProjectPage.tsx` around lines 167 - 170, Update the
project-creation navigation flow around setSubmittingStatus and navigate to
store the setTimeout handle, then add effect cleanup that clears the handle when
the component unmounts or the pending timer is replaced. Preserve the existing
one-second delay and navigation target.

20-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the decorative section comments.

The coding guidelines forbid comments in source unless absolutely necessary. The state groups and JSX blocks here use purely decorative labels (for example lines 20, 30, 35, 46, 69, 72, and the JSX comments at lines 179-272). The variable names already convey the grouping.

As per coding guidelines: "No comments in source code 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/routes/CreateProjectPage.tsx` around lines 20 - 46, Remove the
decorative section comments throughout CreateProjectPage, including the
state-group labels and JSX block comments around the source, form,
build/runtime, and Docker Compose sections. Leave all state declarations and JSX
behavior unchanged.

Source: Coding guidelines

apps/web/src/components/project/create/ProjectNameSection.tsx (1)

40-54: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a non-label element for the static scope block, and drop the decorative comments.

Line 42 renders a label element, but no form control is associated with it. Use a span or p instead. The JSX comments at lines 40, 56, 71, and 85 restate the markup below them.

As per coding guidelines: "No comments in source code 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/create/ProjectNameSection.tsx` around lines
40 - 54, In ProjectNameSection, replace the static scope block’s label element
with a non-label element such as span or p, since it is not associated with a
form control. Remove the decorative JSX comments identifying the scope, project
name, description, and related sections, while leaving the rendered content
unchanged.

Source: Coding guidelines

apps/web/src/components/project/create/BuildSettingsSection.tsx (2)

68-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Associate the labels with the inputs, and remove the conflicting block class.

None of the label elements use htmlFor, and no Input has an id. Screen readers cannot announce the field names. The class lists also combine block and flex; only one display utility applies.

♻️ Proposed fix for the build command field
-            <label className="block text-xs font-semibold text-zinc-300 flex items-center gap-1.5">
+            <label htmlFor="build-command-input" className="text-xs font-semibold text-zinc-300 flex items-center gap-1.5">
               <Terminal className="h-3.5 w-3.5 text-orange-400" />
               Build Command
             </label>
             <Input
+              id="build-command-input"
               value={buildCommand}
🤖 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/BuildSettingsSection.tsx` around lines
68 - 107, Update the Build Command, Output Directory, and Install Command fields
so each label’s htmlFor matches a unique id on its corresponding Input, enabling
accessible label association. Remove the conflicting block utility from each
label while preserving the existing flex alignment classes.

65-151: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the unused BuildSettingsSection.

BuildSettingsSection has no consumers outside its own file, while BuildStrategySection already renders the same build command, install command, output directory, port, and root directory inputs. Remove this duplicate component to keep the create project flow maintainable.

🤖 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/BuildSettingsSection.tsx` around lines
65 - 151, Remove the unused BuildSettingsSection component and its associated
state, imports, and rendering from the create project flow. Keep
BuildStrategySection as the sole owner of the overlapping build, install, output
directory, port, and root directory inputs.
apps/web/src/components/project/settings/ProjectSettingsTab.tsx (2)

369-369: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the new JSX section comments.

The visible labels already identify these sections, so the comments at Lines [369], [403], and [420] are not necessary.

As per coding guidelines, **/*.{ts,tsx,js,jsx} files must have no comments unless absolutely necessary.

Also applies to: 403-403, 420-420

🤖 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` at line 369,
Remove the JSX section comments around the Install Command Override and the
corresponding sections near the visible labels in ProjectSettingsTab, including
all three referenced comment markers. Leave the surrounding JSX and section
labels unchanged.

Source: Coding guidelines


45-46: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Replace the remaining any reads with direct Project property access.

installCommand and outputDir are already on Project, so lines 45-46 can use project.installCommand and project.outputDir. Also replace the broader buildType, composeService, composePort, and composeServices reads with proper Project typing so future API contract changes fail 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/web/src/components/project/settings/ProjectSettingsTab.tsx` around lines
45 - 46, Replace the `any` casts in the project settings state initialization
with direct typed access on `project`, including `installCommand`, `outputDir`,
`buildType`, `composeService`, `composePort`, and `composeServices`. Ensure the
`project` value is typed as `Project` so these properties are checked against
the model and existing fallback behavior is preserved.
🤖 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/web/src/api/client.ts`:
- Around line 575-576: Update setEnvVar to call createEnvVar with projectId and
a single data object containing key, value, and optional environment, matching
createEnvVar’s signature. Preserve the existing setEnvVar parameters and ensure
staged environment variable creation receives the object-shaped request body.

In `@apps/web/src/components/databases/CreateDatabaseDialog.tsx`:
- Around line 69-71: Update the “Attach to project” and “Database Engine”
controls in the CreateDatabaseDialog JSX to use stable unique identifiers and
associate each visible label with its corresponding custom select control via
htmlFor/appropriate control labeling. Ensure DatabaseSelect and the project
Select expose or consume the identifiers so both rendered controls are
accessible by their labels.

In `@apps/web/src/components/project/create/BuildSettingsSection.tsx`:
- Around line 40-63: Make both collapsible headers keyboard-operable by removing
the toggle onClick from the wrapper div and placing the existing isExpanded
toggle handler on each chevron button; add aria-expanded={isExpanded} to the
buttons in apps/web/src/components/project/create/BuildSettingsSection.tsx lines
40-63 and apps/web/src/components/project/create/EnvVarsSection.tsx lines
87-110.

In `@apps/web/src/components/project/create/BuildStrategySection.tsx`:
- Around line 141-183: Update the Web Service and Static Site buttons in the
project type selector so changing projectType also keeps selectedPresetId and
its command settings consistent. Either make the project type selection
authoritative by clearing/replacing the incompatible preset, or select the
established explicit custom preset when users change type manually; preserve
preset-driven behavior for compatible selections.

In `@apps/web/src/components/project/create/EnvVarsSection.tsx`:
- Around line 37-51: Update parseEnvContent to remove an optional leading
“export” prefix before extracting each key, and de-duplicate entries by key so
repeated variables produce only one staged environment entry. Preserve the
existing value trimming and quote removal behavior, with the final keys
containing only the variable name.
- Around line 61-83: Update handleFileUpload to clear the file input’s value
after capturing the selected file, ensuring selecting the same file again
triggers a change event while preserving the existing FileReader flow.

In `@apps/web/src/components/project/create/ProjectNameSection.tsx`:
- Around line 21-23: Extract the duplicated project-name normalization into a
shared slugifyProjectName helper, and use it in both ProjectNameSection and
CreateProjectPage. Ensure the helper lowercases names, replaces invalid
characters with hyphens, collapses consecutive hyphens, and trims leading or
trailing hyphens before constructing the domain preview.

In `@apps/web/src/components/project/create/SourceSelectionSection.tsx`:
- Around line 165-168: Update the submit handler in CreateProjectPage to reject
submission when sourceType is "upload" and zipFile is null, before creating the
project or calling uploadSourceZip. Also update the source-type change handling
in SourceSelectionSection to clear incompatible source state, including removing
zipFile when switching away from upload and clearing other source selections
when switching types.

In `@apps/web/src/components/project/create/StepBasics.tsx`:
- Around line 187-191: Update the StepBasics component’s FrameworkSelect
integration to persist the selected preset ID separately from projectType. Add
parent state and pass it through selectedPresetId, then have onSelectPreset
update both the preset ID and preset.projectType so selections such as Nuxt and
Astro remain selected after rerenders.
- Around line 182-194: Refactor StepBasics into focused child components before
adding more controls, moving the Application Framework Preset and related
general-settings UI and logic out of the 656-line component. Group the extracted
components in an appropriate feature folder, preserve the existing projectType
state and FrameworkSelect behavior, and keep StepBasics under 500 lines.

In `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx`:
- Around line 159-194: Add aria-pressed to both project type buttons in the
projectType selector, binding it to whether projectType equals each button’s
value. Preserve the existing click handlers and styling while exposing the
active selection to assistive technology.
- Around line 154-197: Update the project type selector around the Web Service
and Static Site / SPA buttons to hide it when the selected build type is
Compose, and ensure the form’s save payload normalizes Compose projects to
projectType "web" even if the local projectType state is "static".
- Line 169: Replace every unsupported text-zinc-250 class in the
ProjectSettingsTab markup, including the elements near lines 169, 187, 214, and
232, with a supported zinc shade such as text-zinc-200; do not add a custom
Tailwind token.

In `@apps/web/src/components/ui/DatabaseSelect.tsx`:
- Line 141: Update the badge span’s invalid py-0.2 Tailwind class to a valid
spacing utility, preferably py-0.5, or use an equivalent arbitrary value such as
py-[0.2rem] or py-[2px] while preserving the intended padding.

In `@apps/web/src/routes/CreateProjectPage.tsx`:
- Around line 160-175: Update the submission flow around the stagedEnvs
setEnvVar loop so a failed environment-variable write does not leave an
unreported orphaned project. Track which variables were successfully stored and
include that information in the error handling, or delete the newly created
project when any setEnvVar call fails; preserve the existing success navigation
for fully successful submissions.
- Around line 326-334: Update the submission error handling in the function
containing handleSubmit so a failed deployment resets submittingStatus to
'idle', or adjust the launch Button disabled condition to permit retries when
the status is 'error'; preserve the disabled behavior while submitting and when
the project name is empty.
- Around line 115-130: Update handleSubmit to validate the selected source
before setting the submitting state: require a non-empty repoUrl when sourceType
is 'git', and require zipFile when sourceType is 'upload'. Set an appropriate
error message and return for invalid selections, while preserving the existing
name validation and upload flow.
- Around line 140-158: Replace the any annotation on projectPayload in the
CreateProjectPage submission flow with the shared CreateProjectInput type.
Update the createProject web client mutation/request signature to accept that
same API shape, including buildType, installCommand, outputDir, and
composeServices, so the payload is validated consistently and contract changes
are caught by TypeScript.

---

Nitpick comments:
In `@apps/web/src/components/project/create/BuildSettingsSection.tsx`:
- Around line 68-107: Update the Build Command, Output Directory, and Install
Command fields so each label’s htmlFor matches a unique id on its corresponding
Input, enabling accessible label association. Remove the conflicting block
utility from each label while preserving the existing flex alignment classes.
- Around line 65-151: Remove the unused BuildSettingsSection component and its
associated state, imports, and rendering from the create project flow. Keep
BuildStrategySection as the sole owner of the overlapping build, install, output
directory, port, and root directory inputs.

In `@apps/web/src/components/project/create/ProjectNameSection.tsx`:
- Around line 40-54: In ProjectNameSection, replace the static scope block’s
label element with a non-label element such as span or p, since it is not
associated with a form control. Remove the decorative JSX comments identifying
the scope, project name, description, and related sections, while leaving the
rendered content unchanged.

In `@apps/web/src/components/project/create/SourceSelectionSection.tsx`:
- Line 55: Remove the nonessential JSX section comments from
SourceSelectionSection.tsx at lines 55, 102, and 154;
ApplicationPresetSection.tsx at line 32; and BuildStrategySection.tsx at lines
76, 123, 126, 137, 187, and 266. Leave the surrounding JSX and behavior
unchanged.

In `@apps/web/src/components/project/settings/ProjectSettingsTab.tsx`:
- Line 369: Remove the JSX section comments around the Install Command Override
and the corresponding sections near the visible labels in ProjectSettingsTab,
including all three referenced comment markers. Leave the surrounding JSX and
section labels unchanged.
- Around line 45-46: Replace the `any` casts in the project settings state
initialization with direct typed access on `project`, including
`installCommand`, `outputDir`, `buildType`, `composeService`, `composePort`, and
`composeServices`. Ensure the `project` value is typed as `Project` so these
properties are checked against the model and existing fallback behavior is
preserved.

In `@apps/web/src/components/ui/DatabaseSelect.tsx`:
- Around line 60-98: Update the trigger button in DatabaseSelect to include
aria-expanded={isOpen} and aria-haspopup="listbox". Modify the outside-click
useEffect to register its listener only while isOpen, and add Escape-key
handling that calls setIsOpen(false) when the dropdown is open; ensure cleanup
removes any registered listeners.
- Around line 14-45: Update CreateDatabaseDialog’s default-version selection to
derive the matching defaultVersion from the DATABASE_ENGINES catalog instead of
using the duplicated nested ternary. Reuse the database type selected by the
dialog and preserve the existing behavior for supported engines.

In `@apps/web/src/routes/CreateProjectPage.tsx`:
- Around line 167-170: Update the project-creation navigation flow around
setSubmittingStatus and navigate to store the setTimeout handle, then add effect
cleanup that clears the handle when the component unmounts or the pending timer
is replaced. Preserve the existing one-second delay and navigation target.
- Around line 20-46: Remove the decorative section comments throughout
CreateProjectPage, including the state-group labels and JSX block comments
around the source, form, build/runtime, and Docker Compose sections. Leave all
state declarations and JSX behavior unchanged.

In `@apps/web/src/types/index.ts`:
- Around line 30-31: Update the type declaration containing installCommand and
outputDir to remove the optional ? markers, matching the required-but-nullable
declarations of the sibling buildCommand and startCommand fields; keep their
string | null value types unchanged.
🪄 Autofix

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: df1fc480-d8f9-46bf-8515-089b6e464f90

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc969d and 8b7bba7.

📒 Files selected for processing (19)
  • apps/web/src/api/client.ts
  • apps/web/src/components/databases/CreateDatabaseDialog.tsx
  • apps/web/src/components/logos/DatabaseLogos.tsx
  • apps/web/src/components/logos/FrameworkLogos.tsx
  • apps/web/src/components/project/create/ApplicationPresetSection.tsx
  • apps/web/src/components/project/create/BuildSettingsSection.tsx
  • apps/web/src/components/project/create/BuildStrategySection.tsx
  • apps/web/src/components/project/create/EnvVarsSection.tsx
  • apps/web/src/components/project/create/ImportHeaderCard.tsx
  • apps/web/src/components/project/create/ProjectNameSection.tsx
  • apps/web/src/components/project/create/SourceSelectionSection.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/components/ui/DatabaseSelect.tsx
  • apps/web/src/components/ui/FrameworkSelect.tsx
  • apps/web/src/routes/CreateProjectPage.tsx
  • apps/web/src/types/index.ts
  • apps/web/src/utils/presets.ts

Comment thread apps/web/src/api/client.ts Outdated
Comment thread apps/web/src/components/databases/CreateDatabaseDialog.tsx Outdated
Comment on lines +40 to +63
<div
className="flex items-center justify-between cursor-pointer select-none"
onClick={() => setIsExpanded(!isExpanded)}
>
<div>
<h3 className="text-sm font-bold text-zinc-100 flex items-center gap-2">
<Terminal className="h-4 w-4 text-orange-500" />
Build & Output Settings
</h3>
<p className="text-xs text-zinc-400 mt-1">
Pre-configured from preset. Expand to inspect or override build commands.
</p>
</div>
<button
type="button"
className="p-1.5 rounded-lg bg-[#14141a] border border-[#22222c] text-zinc-400 hover:text-white"
>
<ChevronDown
className={`h-4 w-4 transition-transform ${
isExpanded ? 'transform rotate-180 text-orange-400' : ''
}`}
/>
</button>
</div>

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 | 🟠 Major | ⚡ Quick win

Collapsible section headers are not keyboard operable. Both sections place the toggle onClick on a non-focusable div and render an inner button with no handler. Keyboard and screen-reader users cannot expand or collapse either panel.

  • apps/web/src/components/project/create/BuildSettingsSection.tsx#L40-L63: move onClick={() => setIsExpanded(!isExpanded)} from the wrapper div to the chevron button and add aria-expanded={isExpanded}.
  • apps/web/src/components/project/create/EnvVarsSection.tsx#L87-L110: apply the same change to the chevron button in this header.
📍 Affects 2 files
  • apps/web/src/components/project/create/BuildSettingsSection.tsx#L40-L63 (this comment)
  • apps/web/src/components/project/create/EnvVarsSection.tsx#L87-L110
🤖 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/BuildSettingsSection.tsx` around lines
40 - 63, Make both collapsible headers keyboard-operable by removing the toggle
onClick from the wrapper div and placing the existing isExpanded toggle handler
on each chevron button; add aria-expanded={isExpanded} to the buttons in
apps/web/src/components/project/create/BuildSettingsSection.tsx lines 40-63 and
apps/web/src/components/project/create/EnvVarsSection.tsx lines 87-110.

Comment on lines +141 to +183
<button
type="button"
onClick={() => setProjectType('web')}
className={cn(
'p-4 rounded-xl border text-left transition-all space-y-1.5',
projectType === 'web'
? 'bg-orange-500/10 border-orange-500/40 text-orange-400'
: 'bg-[#121215] border-[#22222a] text-zinc-400 hover:border-zinc-700'
)}
>
<div className="flex items-center justify-between">
<Globe className="h-5 w-5 text-orange-500" />
<span className="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">
Dynamic Server
</span>
</div>
<div className="font-bold text-xs text-zinc-100">Web Service</div>
<p className="text-[11px] text-zinc-400">
Node.js, Elysia, Express, Next.js (SSR), Go, Python server container.
</p>
</button>

<button
type="button"
onClick={() => setProjectType('static')}
className={cn(
'p-4 rounded-xl border text-left transition-all space-y-1.5',
projectType === 'static'
? 'bg-emerald-500/10 border-emerald-500/40 text-emerald-400'
: 'bg-[#121215] border-[#22222a] text-zinc-400 hover:border-zinc-700'
)}
>
<div className="flex items-center justify-between">
<FolderCode className="h-5 w-5 text-emerald-500" />
<span className="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded bg-emerald-500/20 text-emerald-300">
Static Site
</span>
</div>
<div className="font-bold text-xs text-zinc-100">Static Site / SPA</div>
<p className="text-[11px] text-zinc-400">
React, Vite, Astro, Vue static export served via lightweight HTTP file server.
</p>
</button>

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

Keep preset state and project type consistent.

These buttons update only projectType. They do not clear or replace selectedPresetId or its commands.

If a user selects a static preset and then selects Web Service, the selector can still show the static preset while submission uses projectType: "web" and its static command settings.

Make preset selection authoritative, or select an explicit custom preset when the user changes project type manually.

🤖 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/BuildStrategySection.tsx` around lines
141 - 183, Update the Web Service and Static Site buttons in the project type
selector so changing projectType also keeps selectedPresetId and its command
settings consistent. Either make the project type selection authoritative by
clearing/replacing the incompatible preset, or select the established explicit
custom preset when users change type manually; preserve preset-driven behavior
for compatible selections.

Comment on lines +37 to +51
const parseEnvContent = (content: string) => {
const lines = content.split(/\r?\n/);
const newEnvs: StagedEnv[] = [];
lines.forEach((line) => {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) return;
const eqIdx = trimmed.indexOf('=');
if (eqIdx !== -1) {
const k = trimmed.slice(0, eqIdx).trim();
const v = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
if (k) newEnvs.push({ key: k, value: v });
}
});
return newEnvs;
};

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

Strip the export prefix and de-duplicate keys.

A .env file commonly contains export KEY=VALUE. The parser produces the key export KEY, which is not a valid variable name. Repeated keys are also appended twice; CreateProjectPage.tsx then posts both, and the second request can fail on a server-side uniqueness constraint.

🐛 Proposed fix
   const parseEnvContent = (content: string) => {
     const lines = content.split(/\r?\n/);
     const newEnvs: StagedEnv[] = [];
+    const seen = new Set<string>();
     lines.forEach((line) => {
-      const trimmed = line.trim();
+      const trimmed = line.trim().replace(/^export\s+/, '');
       if (!trimmed || trimmed.startsWith('#')) return;
       const eqIdx = trimmed.indexOf('=');
       if (eqIdx !== -1) {
         const k = trimmed.slice(0, eqIdx).trim();
         const v = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
-        if (k) newEnvs.push({ key: k, value: v });
+        if (k && !seen.has(k)) {
+          seen.add(k);
+          newEnvs.push({ key: k, value: v });
+        }
       }
     });
     return newEnvs;
   };
📝 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 parseEnvContent = (content: string) => {
const lines = content.split(/\r?\n/);
const newEnvs: StagedEnv[] = [];
lines.forEach((line) => {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) return;
const eqIdx = trimmed.indexOf('=');
if (eqIdx !== -1) {
const k = trimmed.slice(0, eqIdx).trim();
const v = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
if (k) newEnvs.push({ key: k, value: v });
}
});
return newEnvs;
};
const parseEnvContent = (content: string) => {
const lines = content.split(/\r?\n/);
const newEnvs: StagedEnv[] = [];
const seen = new Set<string>();
lines.forEach((line) => {
const trimmed = line.trim().replace(/^export\s+/, '');
if (!trimmed || trimmed.startsWith('#')) return;
const eqIdx = trimmed.indexOf('=');
if (eqIdx !== -1) {
const k = trimmed.slice(0, eqIdx).trim();
const v = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
if (k && !seen.has(k)) {
seen.add(k);
newEnvs.push({ key: k, value: v });
}
}
});
return newEnvs;
};
🤖 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/EnvVarsSection.tsx` around lines 37 -
51, Update parseEnvContent to remove an optional leading “export” prefix before
extracting each key, and de-duplicate entries by key so repeated variables
produce only one staged environment entry. Preserve the existing value trimming
and quote removal behavior, with the final keys containing only the variable
name.

Comment thread apps/web/src/components/ui/DatabaseSelect.tsx Outdated
Comment thread apps/web/src/routes/CreateProjectPage.tsx
Comment thread apps/web/src/routes/CreateProjectPage.tsx Outdated
Comment thread apps/web/src/routes/CreateProjectPage.tsx
Comment thread apps/web/src/routes/CreateProjectPage.tsx
Lftobs added 3 commits August 9, 2026 13:59
and configuration

- Replace `Staticfile` with `dequel-serve.js` for
  all static site deployments
- Automatically generate a root `package.json` for
  static apps to standardize runtime configuration
- Remove build-time environment variable filtering
  to allow full access to deployment environment
  variables
- Update framework presets with correct default
  ports
- Remove unused `env-filter` utility and tests
components

- Refactor `StepBasics` to use
  `StepBasicsGeneralSettings` and
  `StepBasicsSourceSection` for better
  organization.
- Remove redundant preset and build settings
  components.
- Add `slugifyProjectName` helper.
- Update `CreateProjectInput` type definitions.
@Lftobs
Lftobs marked this pull request as ready for review August 11, 2026 09:30

@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: 9

Caution

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

⚠️ Outside diff range comments (1)
apps/api/src/orchestrator/railpack-config-utils.ts (1)

562-572: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not serve source dotfiles.

The handler returns every existing path below staticDir. When staticDir is the source directory, a request for /.env can expose deployment secrets included in the uploaded source. Reject dotfile path segments and verify that the resolved request path remains inside the resolved static root before calling Bun.file.

🤖 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 562 - 572,
Update the static-file handler around filePath and Bun.file to reject any
decodedPathname segment beginning with "." before accessing the filesystem, and
resolve both the requested path and staticDir to verify the request remains
within the resolved static root. Only call Bun.file after these checks,
preserving normal index.html handling for allowed paths.
♻️ Duplicate comments (1)
apps/web/src/routes/CreateProjectPage.tsx (1)

348-356: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The launch button shows "Deploying..." after a failure.

submittingStatus is 'error' after a failed submission, so the label stays "Deploying..." and the button stays disabled. The user must find the retry control in CreationStatusOverlay to reset the state. Treat 'error' as an idle-equivalent state for the button.

🐛 Proposed fix
-              disabled={!name.trim() || submittingStatus !== 'idle'}
+              disabled={!name.trim() || (submittingStatus !== 'idle' && submittingStatus !== 'error')}
               className="w-full bg-gradient-to-r from-orange-600 to-amber-500 hover:from-orange-500 hover:to-amber-400 text-white font-bold h-11 text-xs rounded-xl shadow-lg shadow-orange-500/20 flex items-center justify-center gap-2 mt-4"
             >
               <Rocket className="h-4 w-4" />
-              {submittingStatus === 'idle' ? 'Launch Deployment' : 'Deploying...'}
+              {submittingStatus === 'idle' || submittingStatus === 'error' ? 'Launch Deployment' : 'Deploying...'}
🤖 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/routes/CreateProjectPage.tsx` around lines 348 - 356, Update the
launch Button rendering and disabled logic in CreateProjectPage so
submittingStatus === 'error' is treated like 'idle': re-enable the button when
the name is valid and display “Launch Deployment,” allowing users to retry
directly after a failed submission.
🧹 Nitpick comments (5)
apps/web/src/components/project/create/StepBasicsSourceSection.tsx (2)

346-365: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The "image" branch is unreachable.

sourceOptions at lines 9-28 defines only "git", "upload", and "compose". No control sets sourceType to "image", so this block never renders. Remove it, or add the corresponding source option if container-image deployment is intended.

🤖 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/StepBasicsSourceSection.tsx` around
lines 346 - 365, Remove the unreachable sourceType === "image" rendering branch
from the source selection UI, since sourceOptions only supports "git", "upload",
and "compose" and no control can select "image".

43-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Two props represent one GitHub connection state. StepBasicsSourceSection declares githubConnected: boolean and onGithubConnected: () => boolean, reads only the callback, and the parent supplies both.

  • apps/web/src/components/project/create/StepBasicsSourceSection.tsx#L43-L45: delete the onGithubConnected prop, and set const connected = githubConnected; at line 66.
  • apps/web/src/components/project/create/StepBasics.tsx#L94-L95: pass only githubConnected={onGithubConnected()} and remove the onGithubConnected prop.
🤖 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/StepBasicsSourceSection.tsx` around
lines 43 - 45, Remove the redundant onGithubConnected prop from
StepBasicsSourceSection and set connected directly from githubConnected. In
apps/web/src/components/project/create/StepBasicsSourceSection.tsx lines 43-45,
delete the callback prop and update the connected initialization near line 66;
in apps/web/src/components/project/create/StepBasics.tsx lines 94-95, pass only
githubConnected={onGithubConnected()} and remove the callback prop.
apps/web/src/components/project/create/StepBasicsGeneralSettings.tsx (1)

33-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

handleTypeChange has two identical branches.

Both paths call setProjectType(type). The FRAMEWORK_PRESETS lookup has no effect, and the FRAMEWORK_PRESETS import exists only for it. If the intent is to clear a preset that conflicts with the manually selected type, the component needs a preset-reset callback. Otherwise, reduce the handler to the setter.

♻️ Proposed simplification
-	const handleTypeChange = (type: string) => {
-		const preset = FRAMEWORK_PRESETS.find((p) => p.id === selectedPresetId);
-		if (preset && preset.projectType === type) {
-			setProjectType(type);
-			return;
-		}
-		setProjectType(type);
-	};
-

Then call setProjectType directly at lines 102 and 120, and drop the FRAMEWORK_PRESETS import.

🤖 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/StepBasicsGeneralSettings.tsx` around
lines 33 - 40, Remove the redundant FRAMEWORK_PRESETS lookup and conditional
from handleTypeChange, reducing it to directly call setProjectType(type). Update
the callers around the existing handler usage to invoke setProjectType directly,
then remove the now-unused FRAMEWORK_PRESETS import.
apps/web/src/components/project/create/CreateProjectDialog.tsx (1)

66-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

This file exceeds the 500-line limit.

CreateProjectDialog.tsx is 568 lines and this change adds more state and props. Split the step rendering and the submit flow into separate files under a create/ feature folder.

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
66 - 67, Refactor CreateProjectDialog by moving its step-rendering logic and
submit flow into focused modules under the create/ feature folder, keeping
CreateProjectDialog responsible for orchestration and shared state. Preserve the
existing behavior and props while reducing the file below 500 lines, and keep
the extracted files grouped with the create feature.

Source: Coding guidelines

apps/web/src/components/project/create/ProjectNameSection.tsx (1)

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

Simplify the props type instead of using Omit.

ProjectNameSectionProps still declares baseDomain and setBaseDomain, but no consumer passes them. CreateProjectPage.tsx line 253 passes only name, setName, description, and setDescription. Remove the unused fields from the interface and use the interface directly.

♻️ Proposed refactor
-}: Omit<ProjectNameSectionProps, 'baseDomain' | 'setBaseDomain'>) {
+}: ProjectNameSectionProps) {

Update the interface declaration accordingly to drop baseDomain and setBaseDomain.

🤖 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/ProjectNameSection.tsx` at line 18,
Update ProjectNameSectionProps to remove the unused baseDomain and setBaseDomain
fields, then replace the Omit<ProjectNameSectionProps, 'baseDomain' |
'setBaseDomain'> parameter type in ProjectNameSection with
ProjectNameSectionProps directly.
🤖 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/src/orchestrator/pipeline.ts`:
- Line 446: Update the build-variable loading near environmentVariables to use
the same deployment.environment selection as the runtime variables instead of
always using "production". Ensure non-production deployments receive matching
build-time URLs and credentials.

In `@apps/api/src/orchestrator/railpack-config-utils.ts`:
- Around line 609-631: The files exceed the repository’s 500-line limit and need
feature-based extraction. In apps/api/src/orchestrator/railpack-config-utils.ts
lines 609-631, extract static-server configuration and command-override
generation into dedicated feature-specific modules, preserving the existing
behavior around install, build, and start overrides. In
apps/api/src/orchestrator/pipeline.ts lines 446-449, extract build preparation
and deployment execution responsibilities into appropriate feature-specific
modules; update imports and callers so both original flows remain unchanged.
- Line 519: Update the conditional in the railpack configuration flow so an
explicit projectType of "static" selects bun dequel-serve.js even when
configured is already true from Node detection. Keep the existing detected
build-step behavior unchanged, and retain the index.html checks for non-explicit
project types.
- Line 223: Update the build command in the source-directory branch of the
railpack configuration utility to quote cleanSourceDir and chain the directory
change and package-manager build with &&, ensuring the build only runs after
entering the intended source directory and supports paths containing spaces.

In `@apps/web/src/api/client.ts`:
- Around line 562-563: Resolve the missing upload route by either implementing
and registering the /upload server endpoint expected by uploadSourceZip, or
removing uploadSourceZip and its callers in favor of the supported flow. Ensure
the selected path allows project creation to complete without invoking an
unregistered endpoint.

In `@apps/web/src/components/project/create/CreateProjectDialog.tsx`:
- Around line 122-127: Update handleSelectPreset in CreateProjectDialog to apply
the preset’s build configuration fields—buildCommand, installCommand,
startCommand, outputDir, and defaultPort—in addition to selectedPresetId and
projectType, matching CreateProjectPage behavior.

In `@apps/web/src/components/project/deployments/DeploymentsTab.tsx`:
- Around line 57-58: Split DeploymentsTab.tsx into feature-focused files within
a dedicated deployment feature folder, moving the deployment source form,
webhook logic, and deployment history orchestration into appropriate components
or hooks. Keep DeploymentsTab as the coordinating container and reduce it below
the 500-line limit without scattering related code across the codebase.

In `@apps/web/src/routes/CreateProjectPage.tsx`:
- Around line 361-368: Update the CreateProjectPage rendering around
CreationStatusOverlay so the status panel is visible during submission by
placing it in a fixed-position container or scrolling it into view whenever
submittingStatus is not idle. Remove the obsolete hasDb and dbType props from
this usage and from CreationStatusOverlay’s parameter handling if they are no
longer used elsewhere.
- Around line 184-191: Update the environment-variable error handling in the
submission loop around the envErr catch to retain the variable currently being
processed and use its key in setErrorMessage. Remove the stagedEnvs.find
fallback so failures report the actual variable that caused the error, while
preserving the existing cleanup and error-status behavior.

---

Outside diff comments:
In `@apps/api/src/orchestrator/railpack-config-utils.ts`:
- Around line 562-572: Update the static-file handler around filePath and
Bun.file to reject any decodedPathname segment beginning with "." before
accessing the filesystem, and resolve both the requested path and staticDir to
verify the request remains within the resolved static root. Only call Bun.file
after these checks, preserving normal index.html handling for allowed paths.

---

Duplicate comments:
In `@apps/web/src/routes/CreateProjectPage.tsx`:
- Around line 348-356: Update the launch Button rendering and disabled logic in
CreateProjectPage so submittingStatus === 'error' is treated like 'idle':
re-enable the button when the name is valid and display “Launch Deployment,”
allowing users to retry directly after a failed submission.

---

Nitpick comments:
In `@apps/web/src/components/project/create/CreateProjectDialog.tsx`:
- Around line 66-67: Refactor CreateProjectDialog by moving its step-rendering
logic and submit flow into focused modules under the create/ feature folder,
keeping CreateProjectDialog responsible for orchestration and shared state.
Preserve the existing behavior and props while reducing the file below 500
lines, and keep the extracted files grouped with the create feature.

In `@apps/web/src/components/project/create/ProjectNameSection.tsx`:
- Line 18: Update ProjectNameSectionProps to remove the unused baseDomain and
setBaseDomain fields, then replace the Omit<ProjectNameSectionProps,
'baseDomain' | 'setBaseDomain'> parameter type in ProjectNameSection with
ProjectNameSectionProps directly.

In `@apps/web/src/components/project/create/StepBasicsGeneralSettings.tsx`:
- Around line 33-40: Remove the redundant FRAMEWORK_PRESETS lookup and
conditional from handleTypeChange, reducing it to directly call
setProjectType(type). Update the callers around the existing handler usage to
invoke setProjectType directly, then remove the now-unused FRAMEWORK_PRESETS
import.

In `@apps/web/src/components/project/create/StepBasicsSourceSection.tsx`:
- Around line 346-365: Remove the unreachable sourceType === "image" rendering
branch from the source selection UI, since sourceOptions only supports "git",
"upload", and "compose" and no control can select "image".
- Around line 43-45: Remove the redundant onGithubConnected prop from
StepBasicsSourceSection and set connected directly from githubConnected. In
apps/web/src/components/project/create/StepBasicsSourceSection.tsx lines 43-45,
delete the callback prop and update the connected initialization near line 66;
in apps/web/src/components/project/create/StepBasics.tsx lines 94-95, pass only
githubConnected={onGithubConnected()} and remove the callback prop.
🪄 Autofix

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: e568053b-0a1e-46fa-acf1-cf003e23deb5

📥 Commits

Reviewing files that changed from the base of the PR and between 8b7bba7 and 80a1baa.

📒 Files selected for processing (21)
  • apps/api/src/orchestrator/__tests__/railpack-config.test.ts
  • apps/api/src/orchestrator/pipeline.ts
  • apps/api/src/orchestrator/railpack-config-utils.ts
  • apps/api/src/utils/__tests__/env-filter.test.ts
  • apps/api/src/utils/env-filter.ts
  • apps/web/src/api/client.ts
  • apps/web/src/components/databases/CreateDatabaseDialog.tsx
  • apps/web/src/components/project/create/CreateProjectDialog.tsx
  • apps/web/src/components/project/create/ProjectNameSection.tsx
  • apps/web/src/components/project/create/SourceSelectionSection.tsx
  • apps/web/src/components/project/create/StepBasics.tsx
  • apps/web/src/components/project/create/StepBasicsGeneralSettings.tsx
  • apps/web/src/components/project/create/StepBasicsSourceSection.tsx
  • apps/web/src/components/project/deployments/DeploymentsTab.tsx
  • apps/web/src/components/project/settings/ProjectSettingsTab.tsx
  • apps/web/src/components/ui/DatabaseSelect.tsx
  • apps/web/src/routes/CreateProjectPage.tsx
  • apps/web/src/types/index.ts
  • apps/web/src/utils/presets.ts
  • apps/web/src/utils/slugify.ts
  • docker-compose.yml
💤 Files with no reviewable changes (2)
  • apps/api/src/utils/tests/env-filter.test.ts
  • apps/api/src/utils/env-filter.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/web/src/types/index.ts
  • apps/web/src/components/ui/DatabaseSelect.tsx
  • apps/web/src/utils/presets.ts
  • apps/web/src/components/databases/CreateDatabaseDialog.tsx
  • apps/web/src/components/project/settings/ProjectSettingsTab.tsx

Comment thread apps/api/src/orchestrator/pipeline.ts
Comment thread apps/api/src/orchestrator/railpack-config-utils.ts Outdated
Comment thread apps/api/src/orchestrator/railpack-config-utils.ts Outdated
Comment on lines +609 to +631
if (buildCommandOverride || startCommandOverride || installCommandOverride) {
await onLog("Applying custom build/start/install settings");
if (installCommandOverride) {
const hasCustomInstall = installCommandOverride !== "npm install" && installCommandOverride !== "npm ci" && installCommandOverride !== "pnpm install" && installCommandOverride !== "yarn install" && installCommandOverride !== "bun install";
if (hasCustomInstall) {
config.steps.install = config.steps.install || {};
config.steps.install.commands = [installCommandOverride];
}
}
if (buildCommandOverride) {
config.steps.build = config.steps.build || {};
config.steps.build.commands = [
cleanSourceDir
? `cd ${cleanSourceDir} && ${buildCommandOverride}`
: buildCommandOverride,
];
}
if (startCommandOverride) {
config.deploy.startCommand = cleanSourceDir
? `cd ${cleanSourceDir} && ${startCommandOverride}`
: startCommandOverride;
}
}

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 | 🟠 Major | 🏗️ Heavy lift

Split the TypeScript files that exceed the repository size limit.

  • apps/api/src/orchestrator/railpack-config-utils.ts#L609-L631: extract static-server configuration and command-override generation into feature-specific modules.
  • apps/api/src/orchestrator/pipeline.ts#L446-L449: extract build preparation and deployment execution responsibilities into feature-specific modules.

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

📍 Affects 2 files
  • apps/api/src/orchestrator/railpack-config-utils.ts#L609-L631 (this comment)
  • apps/api/src/orchestrator/pipeline.ts#L446-L449
🤖 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 609 - 631,
The files exceed the repository’s 500-line limit and need feature-based
extraction. In apps/api/src/orchestrator/railpack-config-utils.ts lines 609-631,
extract static-server configuration and command-override generation into
dedicated feature-specific modules, preserving the existing behavior around
install, build, and start overrides. In apps/api/src/orchestrator/pipeline.ts
lines 446-449, extract build preparation and deployment execution
responsibilities into appropriate feature-specific modules; update imports and
callers so both original flows remain unchanged.

Source: Coding guidelines

Comment on lines +562 to +563
export const setEnvVar = (projectId: string, key: string, value: string, environment?: string) =>
createEnvVar(projectId, { key, value, environment });

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 | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Locate the uploadSourceZip client helper and the matching API route.
set -euo pipefail

echo "## Client helper"
rg -n -C6 'uploadSourceZip' apps/web/src

echo "## API upload routes"
rg -n -C6 -g '!apps/web/**' '"/upload"|/upload\b|filePath' apps/api/src | head -80

Repository: Lftobs/dequel

Length of output: 7622


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## Upload-related files and symbols"
git ls-files | grep -Ei '(^|/)(route|router|upload|server|api|index|app)[^/]*\.(ts|tsx|js|jsx)$' | head -200
rg -n -i -C5 'uploadSourceZip|upload|multipart|FormData|filePath|formData|request\.formData|req\.file|file\.path|repoUrl' --glob '*.{ts,tsx,js,jsx}' . | head -300

echo "## API source outline"
if command -v ast-grep >/dev/null 2>&1; then
  ast-grep outline apps/api/src
fi

Repository: Lftobs/dequel

Length of output: 30738


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## API route registration"
wc -l apps/api/src/index.ts apps/api/src/api/index.ts apps/api/src/orchestrator/source.ts
cat -n apps/api/src/index.ts
cat -n apps/api/src/api/index.ts
sed -n '1,130p' apps/api/src/orchestrator/source.ts

echo "## Deterministic endpoint scan"
python3 - <<'PY'
from pathlib import Path
import re

files = [Path(p) for p in __import__("subprocess").check_output(
    ["git", "ls-files", "*.ts", "*.tsx", "*.js", "*.jsx"], text=True
).splitlines()]

route_hits = []
upload_hits = []
file_path_hits = []

for path in files:
    text = path.read_text(errors="replace")
    if re.search(r'(?i)(?:["\'`]\/upload\b|(?:get|post|put|patch|delete)\s*\(\s*["\'`]\/upload\b|route\s*=\s*["\'`]\/upload\b)', text):
        route_hits.append(str(path))
    if re.search(r'(?i)(?:upload|multipart|formdata|request\.formdata|req\.file)', text):
        upload_hits.append(str(path))
    if re.search(r'\bfilePath\b', text):
        file_path_hits.append(str(path))

print("route_matches:", route_hits)
print("upload_related_files:", upload_hits)
print("filePath_files:", file_path_hits)
PY

Repository: Lftobs/dequel

Length of output: 11590


Add the /upload server endpoint or remove uploadSourceZip.

The API registers no upload route. The upload flow therefore fails before project creation.

🤖 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/api/client.ts` around lines 562 - 563, Resolve the missing
upload route by either implementing and registering the /upload server endpoint
expected by uploadSourceZip, or removing uploadSourceZip and its callers in
favor of the supported flow. Ensure the selected path allows project creation to
complete without invoking an unregistered endpoint.

Comment thread apps/web/src/components/project/create/CreateProjectDialog.tsx
Comment on lines +57 to +58
const [clearCache, setClearCache] =
useState(false);

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 | 🟠 Major | 🏗️ Heavy lift

Split DeploymentsTab.tsx before merging.

The file reaches Line 527. Move the deployment source form, webhook logic, and deployment history orchestration into feature-focused components or hooks. Keep DeploymentsTab.tsx below the 500-line limit.

As per coding guidelines, no file should be above 500 lines of code; refactor and split it into smaller files with proper feature grouping in a folder rather than scattering code 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/deployments/DeploymentsTab.tsx` around lines
57 - 58, Split DeploymentsTab.tsx into feature-focused files within a dedicated
deployment feature folder, moving the deployment source form, webhook logic, and
deployment history orchestration into appropriate components or hooks. Keep
DeploymentsTab as the coordinating container and reduce it below the 500-line
limit without scattering related code across the codebase.

Source: Coding guidelines

Comment thread apps/web/src/routes/CreateProjectPage.tsx
Comment on lines +361 to +368
<CreationStatusOverlay
submittingStatus={submittingStatus}
errorMessage={errorMessage}
hasEnvs={stagedEnvs.length > 0}
hasDb={false}
dbType="postgresql"
onRetry={handleRetry}
/>

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

CreationStatusOverlay renders below the form, not over it.

The component returns a plain flow-layout block with no fixed or absolute positioning. During submission the form stays visible above it, and the status panel appears at the bottom of the page. The user may not see the progress or the retry control without scrolling. Wrap the component in a fixed-position container, or scroll it into view when submittingStatus leaves 'idle'.

Also, hasDb={false} and dbType="postgresql" are constants. Database provisioning no longer exists in this flow, so these props are dead parameters.

🤖 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/routes/CreateProjectPage.tsx` around lines 361 - 368, Update the
CreateProjectPage rendering around CreationStatusOverlay so the status panel is
visible during submission by placing it in a fixed-position container or
scrolling it into view whenever submittingStatus is not idle. Remove the
obsolete hasDb and dbType props from this usage and from CreationStatusOverlay’s
parameter handling if they are no longer used elsewhere.

deployment refinements

- Allow custom build, install, and start commands
  in project creation
- Enable environment-aware variable fetching for
  deployments
- Improve directory handling in build scripts
- Add retry logic and improved error tracking for
  project creation
- Remove redundant database provisioning UI
  components
@Lftobs
Lftobs merged commit 7ec5b92 into dev Aug 12, 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: 3

Caution

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

⚠️ Outside diff range comments (2)
apps/web/src/components/project/create/CreateProjectDialog.tsx (2)

130-141: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear stale port state when a preset has no default port.

FrameworkPreset.defaultPort is optional, and the docker and other presets omit it. Line 139 then leaves the previous preset's port in state. Selecting a custom preset after Vite can submit the old Vite port. Use setPort(preset.defaultPort ?? ""), or track user-entered ports separately. (raw.githubusercontent.com)

Proposed fix
-		if (preset.defaultPort) setPort(String(preset.defaultPort));
+		setPort(preset.defaultPort ?? "");
🤖 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
130 - 141, Update handleSelectPreset to always synchronize the port state with
the selected FrameworkPreset by setting it to the default port string when
present and clearing it when defaultPort is absent, preventing stale values from
previously selected presets.

66-67: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep selectedPresetId and projectType consistent.

When a user selects a preset and then changes the project type manually, the selected preset and its commands remain active. The dialog can submit projectType: "static" with web-preset commands. Clear selectedPresetId and all preset-derived fields when the type changes, or route both actions through one state transition. (raw.githubusercontent.com)

Also applies to: 130-141

🤖 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
66 - 67, Update the project type change handling in CreateProjectDialog so
changing the type clears selectedPresetId and every preset-derived field,
preventing stale preset commands from being submitted with the new type. Keep
preset selection and type changes synchronized through the same state transition
where applicable.
🤖 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/web/src/components/project/create/CreateProjectDialog.tsx`:
- Around line 76-83: Expose the stored build settings in CreateProjectDialog by
passing buildCommand, installCommand, startCommand, and outputDir along with
their setters to StepBasics. Update StepBasics to accept these controlled props
and render BuildStrategySection so users can edit custom build settings, while
preserving the existing submission values for docker and other presets.
- Around line 76-83: Refactor CreateProjectDialog by extracting its form state
and submission lifecycle—including the buildCommand, installCommand,
startCommand, and outputDir state—into a dedicated hook or feature module. Keep
the dialog shell and step composition in CreateProjectDialog, preserving
existing behavior while reducing the file below 500 lines and grouping the
extracted logic with the feature.
- Around line 156-160: Update the dialog close/reset logic in
CreateProjectDialog so that when isOpen is false it also resets projectType,
stagedEnvs, submittingStatus, and errorMessage, alongside the existing preset
and command fields. Ensure each new dialog starts with default transient
creation state and no prior status or error.

---

Outside diff comments:
In `@apps/web/src/components/project/create/CreateProjectDialog.tsx`:
- Around line 130-141: Update handleSelectPreset to always synchronize the port
state with the selected FrameworkPreset by setting it to the default port string
when present and clearing it when defaultPort is absent, preventing stale values
from previously selected presets.
- Around line 66-67: Update the project type change handling in
CreateProjectDialog so changing the type clears selectedPresetId and every
preset-derived field, preventing stale preset commands from being submitted with
the new type. Keep preset selection and type changes synchronized through the
same state transition where applicable.
🪄 Autofix

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: 2147431a-c9bf-4bc7-9ca0-52fcdc83c1b6

📥 Commits

Reviewing files that changed from the base of the PR and between 80a1baa and c1667ea.

📒 Files selected for processing (5)
  • apps/api/src/orchestrator/pipeline.ts
  • apps/api/src/orchestrator/railpack-config-utils.ts
  • apps/web/src/components/project/create/CreateProjectDialog.tsx
  • apps/web/src/components/project/create/CreationStatusOverlay.tsx
  • apps/web/src/routes/CreateProjectPage.tsx
💤 Files with no reviewable changes (1)
  • apps/web/src/components/project/create/CreationStatusOverlay.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/api/src/orchestrator/pipeline.ts
  • apps/web/src/routes/CreateProjectPage.tsx
  • apps/api/src/orchestrator/railpack-config-utils.ts

Comment on lines +76 to +83
const [buildCommand, setBuildCommand] =
useState("");
const [installCommand, setInstallCommand] =
useState("");
const [startCommand, setStartCommand] =
useState("");
const [outputDir, setOutputDir] =
useState("");

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 | 🏗️ Heavy lift

Expose the build settings in this dialog.

The dialog stores and submits buildCommand, installCommand, startCommand, and outputDir, but it passes none of those values or setters to StepBasics. StepBasics renders general settings, source settings, and port only. Users cannot enter custom commands in this dialog. The docker and other presets therefore submit empty command fields. Add controlled build props and render BuildStrategySection, or remove these fields from this dialog. (raw.githubusercontent.com)

Suggested wiring
 <StepBasics
+  buildCommand={buildCommand}
+  setBuildCommand={setBuildCommand}
+  installCommand={installCommand}
+  setInstallCommand={setInstallCommand}
+  startCommand={startCommand}
+  setStartCommand={setStartCommand}
+  outputDir={outputDir}
+  setOutputDir={setOutputDir}
 />

Also applies to: 454-458

🤖 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
76 - 83, Expose the stored build settings in CreateProjectDialog by passing
buildCommand, installCommand, startCommand, and outputDir along with their
setters to StepBasics. Update StepBasics to accept these controlled props and
render BuildStrategySection so users can edit custom build settings, while
preserving the existing submission values for docker and other presets.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Split CreateProjectDialog before adding more state.

The file spans 595 lines. Extract the form state and submission lifecycle into a hook or feature module, and keep the dialog shell and step composition below 500 lines.

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
76 - 83, Refactor CreateProjectDialog by extracting its form state and
submission lifecycle—including the buildCommand, installCommand, startCommand,
and outputDir state—into a dedicated hook or feature module. Keep the dialog
shell and step composition in CreateProjectDialog, preserving existing behavior
while reducing the file below 500 lines and grouping the extracted logic with
the feature.

Source: Coding guidelines

Comment on lines +156 to +160
setSelectedPresetId("");
setBuildCommand("");
setInstallCommand("");
setStartCommand("");
setOutputDir("");

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

Reset all transient creation state when the dialog closes.

The close path does not reset projectType, stagedEnvs, submittingStatus, or errorMessage. A later dialog can reopen with the old status overlay, retain a previous static project type, or attach prior environment variables to a new project. Reset these values when isOpen is false.

Proposed reset additions
 			setSelectedPresetId("");
+			setProjectType("web");
 			setBuildCommand("");
 			setInstallCommand("");
 			setStartCommand("");
 			setOutputDir("");
 			setPort("");
 			setZipFile(null);
+			setStagedEnvs([]);
+			setSubmittingStatus("idle");
+			setErrorMessage("");
📝 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
setSelectedPresetId("");
setBuildCommand("");
setInstallCommand("");
setStartCommand("");
setOutputDir("");
setSelectedPresetId("");
setProjectType("web");
setBuildCommand("");
setInstallCommand("");
setStartCommand("");
setOutputDir("");
setPort("");
setZipFile(null);
setStagedEnvs([]);
setSubmittingStatus("idle");
setErrorMessage("");
🤖 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
156 - 160, Update the dialog close/reset logic in CreateProjectDialog so that
when isOpen is false it also resets projectType, stagedEnvs, submittingStatus,
and errorMessage, alongside the existing preset and command fields. Ensure each
new dialog starts with default transient creation state and no prior status or
error.

@Lftobs
Lftobs deleted the chore/ui branch August 24, 2026 12:27
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