1.3.5 Vitest: project CRUD + identifier uniqueness + gap-free key counter + active-project
Estimate: 14m · Depends on: 1.3.1
Service-layer integration tests against a real Postgres (no DB mocks, per CLAUDE.md), mirroring tests/workspaces-service.test.ts. Can run as soon as 1.3.1 lands — does not wait on the UI (1.3.4).
Coverage: createProject happy path (identifier derived + workspace-unique); identifier collision → numeric-suffix retry; slug + identifier uniqueness within a workspace (same identifier allowed in a DIFFERENT workspace); allocateWorkItemNumber is gap-free and monotonic per project AND independent across projects (PROD counter and ACME counter don't interfere); concurrent allocations don't double-issue a number (sequential calls in the same transaction return 1,2,3…); setActiveProject persists and is per-member; archiveProject sets archivedAt and the project drops out of the active list; cascade — deleting the workspace removes its projects; SetNull — archiving/deleting a project clears members' activeProjectId.
Acceptance criteria
tests/projects-service.test.tscovers all cases above; passes against the real dev Postgres.- The gap-free-counter test proves per-project independence and monotonicity explicitly.
- All quality gates green; total Vitest count grows accordingly; prior suite stays green.
Context refs
tests/workspaces-service.test.ts— the exact service-test pattern (truncate beforeEach, real DB, typed-error assertions)lib/services/projectsService.ts+lib/repositories/projectRepository.tsfrom 1.3.1