Thank you for taking the time to contribute. All help is welcome — bug reports, feature ideas, documentation fixes, and code changes.
- Fork the repository on GitHub.
- Clone your fork locally:
git clone https://github.com/<your-username>/portfolioforge.git cd portfolioforge
- Install dependencies (pnpm is preferred):
pnpm install
- Set up environment variables:
cp .env.example .env.local # Fill in Firebase, Google AI, and Stripe credentials — see README for details - Start the dev server:
pnpm dev
Open a GitHub issue and include:
- A clear, descriptive title.
- Steps to reproduce the problem.
- Expected vs. actual behaviour.
- Browser / OS / Node version if relevant.
Open a GitHub issue describing:
- What the feature does.
- Why it is valuable to PortfolioForge users.
- Any implementation ideas you have.
- Create a branch from
main:git checkout -b feat/my-feature # or git checkout -b fix/my-bug - Make your changes.
- Run the full check suite before committing:
pnpm lint # ESLint pnpm typecheck # TypeScript (no emit) pnpm test # Vitest unit + component tests
- For end-to-end tests (requires Playwright browsers installed once via
npx playwright install):pnpm test:e2e
- Commit with a meaningful message:
git commit -m "feat: add dark mode toggle to settings page" - Push and open a pull request against
main.
src/
├── ai/
│ ├── flows/ # Genkit AI flows — one file per capability
│ ├── genkit.ts # Shared ai instance; always import z from here
│ └── dev.ts # Genkit dev server entry point
├── app/
│ ├── api/ # Next.js API routes (AI endpoints, Stripe, portfolio-items, contact)
│ ├── dashboard/ # Authenticated app pages
│ ├── portfolio/ # Public portfolio renderer
│ └── … # Public pages (landing, pricing, login, signup, legal)
├── components/
│ ├── ui/ # ShadCN UI primitives (do not edit directly)
│ └── … # Shared layout and feature components
├── firebase/ # Firebase client init, context provider, hooks
├── hooks/ # Custom React hooks
├── lib/ # Utilities, types, theme schema, Stripe helpers, logger
└── telemetry/ # OpenTelemetry server-side init
tests/
├── unit/ # Pure utility function tests (Vitest)
├── frontend/ # Component tests (Vitest + React Testing Library)
├── e2e/ # Browser automation (Playwright)
├── contract/ # API contract tests (placeholder)
└── performance/ # Load / Lighthouse tests (placeholder)
- Style: Follow the existing code style. Run
pnpm lintbefore committing. - TypeScript: All new code must be typed. Run
pnpm typecheckto verify. - Imports: Always import
zfrom@/ai/genkit, never directly fromgenkitorzod. - AI flows: Use
ai.generate()with a Zodoutput.schema— do not useai.definePromptwith Handlebars templates. - Design tokens: Use Tailwind design-system tokens (
bg-background,text-foreground, etc.) — never raw colour classes likebg-gray-100orbg-white. - Hooks: Never call React hooks after an early
return. All hooks must be at the top of the component. - No dummy data: Do not commit hardcoded placeholder data in pages. Use empty states and loading skeletons instead.
- Portfolio item creation: Always route through
POST /api/portfolio-items— never write directly from the client. This enforces the free-plan limit server-side. - Comments: Write self-documenting code. Add comments only where the why is non-obvious.
- Tests: Add tests for new features or bug fixes. Do not remove existing tests.
- Create
src/ai/flows/my-flow.ts:import { ai, z } from '@/ai/genkit'; const InputSchema = z.object({ … }); const OutputSchema = z.object({ … }); export async function myFlow(input: z.infer<typeof InputSchema>) { return myFlowDef(input); } const myFlowDef = ai.defineFlow( { name: 'myFlow', inputSchema: InputSchema, outputSchema: OutputSchema }, async (input) => { const { output } = await ai.generate({ prompt: `…${input.someField}…`, output: { schema: OutputSchema }, }); if (!output) throw new Error('Model returned no output'); return output; } );
- Create the API route at
src/app/api/my-flow/route.ts. - Register the flow in
src/ai/dev.tsif you want it visible in the Genkit dev UI.
-
pnpm lintpasses with no errors -
pnpm typecheckpasses with no errors -
pnpm testpasses - No hardcoded dummy/placeholder data in UI
- Design-system tokens used (no raw gray/white classes)
- Portfolio item creation goes through
/api/portfolio-items - PR description explains what changed and why
We review pull requests as quickly as we can. Thank you for contributing!