Contributors Guide
This guide explains how to work on Unwrap: the conventions, the PR process, and the standards your changes will be evaluated against.
NOTE
These guidelines are set to change and must be updated once agreed upon with team and other relevant stakeholders. If you haven't run the project yet, start with Get Started.
Project context
Unwrap is a group student project submitted for assessment. The frontend is owned and maintained separately from the backend.
Frontend scope includes:
- Everything under
src/ - All test infrastructure (
src/__tests__/,src/test/,src/mocks/) - CI configuration (
.github/workflows/) - All documentation (
docs/,README.md)
Branching
The project uses trunk-based development with short-lived feature branches. The main branch is protected and no direct pushes are allowed. Every change goes through a pull request.
Branch naming
<type>/<short-description>Where <type> is one of:
| Prefix | Use for |
|---|---|
feat/ | New user-facing or developer-facing functionality |
fix/ | Bug fixes |
chore/ | Tooling, dependencies, config, non-code maintenance |
docs/ | Documentation only |
test/ | Adding or improving tests |
refactor/ | Internal restructuring without behaviour change |
Examples: feat/top-albums-card, fix/upload-zip-validation, docs/architecture-page.
Branch lifetime
Keep branches short-lived, ideally less than a few days. Long-lived branches accumulate merge conflicts and review burden. If a feature is large, split it into multiple PRs.
Commits
Commits are based on the Conventional Commits spec.
<type>(<scope>): <subject>| Element | Notes |
|---|---|
| type | Same set as branch prefixes: feat, fix, chore, docs, test, refactor |
| scope | Optional. The area of the codebase, e.g. dashboard, upload, ci |
| subject | Imperative present tense, lowercase. No trailing period. |
Good:
feat(dashboard): add Top Albums stat cardBad:
update stuffCommits should be atomic
One logical change per commit. If you can describe two things your commit does using "and", split it.
The PR process
1. Open the PR
Push your branch and open a pull request against main. Include:
- A clear title following commit conventions above
- Add an optional body that says: what changed, why, and any context a reviewer needs
2. CI runs automatically
Every PR triggers GitHub Actions, which run on a Node 24 environment:
| Job | What it checks |
|---|---|
| unit (+integration) tests | npm run test:run (full Vitest suite) |
| e2e-tests | npx playwright test |
CI must pass before the PR can be merged. If a job fails, fix the issue locally and push again.
3. Review
Self-review your own PR first: read the diff as if you were reviewing someone else's change. Catch obvious issues before a human does.
For larger changes or anything architectural, request a review where possible. Address feedback in new commits. Don't force-push during review.
4. Merge
PRs are merged into main via Merge pull request. Merge commits go onto main.
After merge, the feature branch is deleted automatically.
Code conventions
File and folder layout
- Components:
src/components/<Name>/<Name>.tsx+<Name>.module.css - Pages:
src/pages/<Name>.tsx(routes are top-level) - Tests: mirror the source path under
src/__tests__/
TypeScript
anyis forbidden by ESLint. Useunknownand narrow, or define an interface.- API response shapes live in
src/types/api.ts— keep them aligned with the backend. - Prefer interfaces over type aliases for object shapes.
React
- Default exports for components. One component per file.
- Hooks go in
src/hooks/and start withuse. - No inline
fetchcalls. All data fetching goes through a service → hook.
CSS
- CSS Modules only. Import as
import styles from './X.module.css'. - Use the design token CSS variables (
--color-surface,--radius, etc.) — don't hardcode colours. - Component-scoped class names; no global styles outside
src/index.css.
Testing standards
- Every new component should have at least one integration test.
- Every new service or util should have unit tests.
- Tests should describe behaviour, not implementation.
it('shows an error when the request fails'), notit('renders the .error className'). - Use the shared
renderWithProvidersandserverfromsrc/test/. Don't roll your own setup.
For patterns, see How to write a test.
Pre-commit hooks
Husky runs lint-staged on every commit:
- ESLint with auto-fix on staged
.ts,.tsxfiles - Prettier on staged
.ts,.tsx,.css,.mdfiles
If a hook fails, the commit is rejected. Fix the reported issues and commit again. Don't bypass with --no-verify unless you have a clear reason because CI will catch the same issues anyway.
What "ready for review" means
Before requesting review, your PR should:
- ✅ Pass CI (all green)
- ✅ Have no
console.logor commented-out code - ✅ Have tests for new behaviour
- ✅ Update docs if you changed something documented
Questions
If something here is unclear or contradicts what you see in the code, that's a documentation bug, open an issue or a docs PR.