ProtoPulse follows a vertical-slice development model — every feature is implemented top-to-bottom across all layers before it is considered done. This keeps each change self-contained, testable end-to-end, and easy to review. The slice for any feature flows in a fixed order:Documentation Index
Fetch the complete documentation index at: https://mintlify.com/wtyler2505/ProtoPulse/llms.txt
Use this file to discover all available pages before exploring further.
Prerequisites
Before contributing, make sure you have:- Node.js 20+ — the dev server and build scripts require it
- PostgreSQL 14+ — the app stores all data in PostgreSQL via Drizzle ORM
- Familiarity with TypeScript — the entire codebase (client, server, shared) is TypeScript 5.6 with
strict: true - Familiarity with React — the frontend is React 19 with TanStack React Query for all server state
Both
npm run dev and the Vite dev server run on port 5000. The Express backend serves the Vite HMR proxy, so you only need to open one URL: http://localhost:5000. There is no separate client port to configure.Development workflow
Create a feature branch
Always work from a dedicated branch. Use a descriptive name that reflects the change:
Install dependencies and set up the database
Install all npm dependencies, then push the Drizzle schema to your PostgreSQL instance:Create a Push the schema:Start the development server:The app will be available at
.env file with your database connection string:http://localhost:5000 with Vite HMR active.Make changes following the vertical slice model
Implement your feature in the following order — do not skip layers:
shared/schema.ts— Add or modify the Drizzle ORM table definition and Zod insert schemaserver/storage.ts— Add methods toIStorageand implement them inDatabaseStorageserver/routes/— Add the API route withasyncHandler, Zod body validation, andIStoragecallsclient/src/lib/project-context.tsx— Add the React QueryuseQueryoruseMutationhookclient/src/components/— Build the UI component, addingdata-testidto every interactive element
Write tests — npm test must pass with zero failures
Every new feature requires tests. Add them in the If any test fails, fix the code — not the test. Tests reveal bugs.
__tests__/ subdirectory co-located with the source file you changed. Server tests live in server/__tests__/, client tests live next to the source under client/src/.Run the full test suite to confirm nothing is broken:Run type checking — npm run check must pass with zero errors
TypeScript strict mode is enforced with no exceptions. After your changes, verify the type check is clean:Never dismiss a pre-existing error as “not your fault” — if it was already there, it is still a bug. Fix it or open a separate issue.
Run linting and formatting
ESLint enforces strict TypeScript rules including ESLint should report zero errors. Prettier rewrites files in place — commit the formatted output.
no-explicit-any and consistent import type usage. Prettier enforces formatting. Run both before committing:Submit a pull request
Push your branch and open a pull request against
main. In the PR description, explain:- What the change does and why
- Which vertical slice layers were touched
- How you tested it
Test requirements
All contributions must meet these testing standards before a PR can be merged:| Requirement | Command | Standard |
|---|---|---|
| All tests pass | npm test | Zero failures across all 54 test files |
| Type check passes | npm run check | Zero TypeScript errors |
| New features have tests | — | Tests added in the appropriate __tests__/ directory |
- Add
data-testidto every interactive UI element (buttons, inputs, dropdowns, canvas targets). This is an explicit convention, not optional. - Use
@testing-library/reactfor component behavior tests — test what users see and do, not implementation details. - Use descriptive test names in the pattern:
"should [action] when [condition]". - Run only the tests relevant to your change during development:
npx vitest run path/to/file.test.ts.
PR requirements
A pull request will not be merged unless it satisfies all of the following:- Zero TypeScript errors —
npm run checkis clean - Zero test failures —
npm testis clean - Zod validation on every request body — use
schema.safeParse(req.body)in every route handler that accepts a body; Zod schemas live inshared/schema.ts ErrorBoundaryper view — any new view component added toProjectWorkspacemust be wrapped in anErrorBoundary
What not to do
- No
import X from '...'for type-only imports. The ESLintimport-xplugin enforcesimport typefor all imports that are used only as types. A violation will fail the lint step. - No
as any. Use proper type narrowing, discriminated unions, or generics instead.@typescript-eslint/no-explicit-anyis configured as an error. - No UUID generation with
Date.now(). Always usecrypto.randomUUID(). - No direct database queries in route handlers. All data access goes through
IStorage— never import the Drizzledbobject directly in a route file.