feat(projects): multi-step project creation wizard - #249
Merged
07prajwal2000 merged 1 commit intoAug 14, 2026
Merged
Conversation
Server:
- POST /v1/projects now accepts description, members[] and settings{},
all written in the existing db.transaction so a project can never exist
without the access grants it was created with.
- CREATE_TIME_SETTING_KEYS is the single source shared by the API schema
and the wizard; connection-id keys stay out (they need integration wiring).
- Fix dead duplicate-name check: create/service used checkProjectExist(id)
from routes/create, so it matched name against id and never fired.
- Fix name length: projects.name is varchar(50) but create/update DTOs
allowed 100/255, so long names passed zod then died on the insert.
- Replace the copy-pasted get-all stub spec with real create tests.
Portal:
- New /projects/new wizard route (basics -> members -> config), behind the
existing isSystemAdmin gate. Members step is a two-column transfer panel
with a per-member role dropdown reusing ROLES from RoleSelector.
- Drop the single-field new-project modal from ProjectsTab.
- All styling uses design-system tokens; no hardcoded colors.
AGENT.md: document the never-hardcode-colors rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Replaces the single-field "new project" modal with a dedicated 3-step wizard, and extends the create endpoint to accept what the wizard collects.
Server —
POST /v1/projects{ name, description?, members[], settings{} }. Members and settings are written inside the existingdb.transactionalongside the insert — all three repository functions already took an optionaltx, so this is atomic without new plumbing. A project that exists but is missing the access grants it was created with can only be repaired by a system admin, so partial creation isn't an acceptable state.CREATE_TIME_SETTING_KEYSincreate/dto.tsis the single source shared by the request schema and the wizard. Connection-id keys (AI agent, telemetry) are deliberately excluded — they need the live connection test that onlysettings/keys/upsertperforms. Adding a future non-connection key is a one-line change there.Server — bugs found on the way
create/service.tsimportedcheckProjectExistfromroutes/create/repository, whose signature is(id: string)and which matcheseq(projectsEntity.id, id). It was queryingid = <the project name>, always returned false, and the 409 was dead code — duplicate project names were silently allowed. The correctcheckProjectExists(name)was sitting unused inprojects/create/repository.ts. Now used, and covered by a test asserting it's called with the name.varchar(50)vs zod.projects.nameisvarchar({ length: 50 })butcreate/dto.tsallowedmax(100)andupdate/dto.tsallowedmax(255), so a 51+ character name passed validation and then failed at the DB. Both DTOs now cap at 50.create/tests/create.spec.tswas a copy-pastedget-allstub (it("test 01", () => {})). Replaced with real tests.Portal
/projects/new(_authed/projects.new.tsx), behind the sameisSystemAdmingate as the old modal. Three steps — basics, members, config — split this way so future config keys have a home rather than crowding the name field.ROLESfromRoleSelectorrather than retyping the three roles.ProjectsTabloses the modal and navigates to the wizard.Notes
hiddenis untouched — it's the live archive flag used byget-allandupdate, not something to set at creation.AGENT.mdgains a rule documenting this, after a first pass copied literal hex from a neighbouring file.Testing
bun run lint— clean across all 10 packages (also runs on pre-commit).vite buildsucceeds;routeTree.gen.tspicks up the new route (it's gitignored and generated at build time, so it doesn't appear in the diff).🤖 Generated with Claude Code