Your First PR
Purpose
A walkthrough of the HUPH contribution workflow — how we branch, commit, test, and merge. Follow this page for your first change (and every change after) so your PR lands smoothly with the rest of the team.
Prerequisites
- Local environment working (see setup)
gitconfigured with your identity- Repo access (you should already be able to push to
github.com/wabiwabo/huph)
Overview of the workflow
main (protected)
│
├─ spec → plan → branch → TDD loop → PR → review → merge
│
└─ Every feature follows this rhythm
Big features follow a spec → plan → implement flow with
documents in docs/superpowers/specs/ and docs/superpowers/plans/.
Small fixes (1-2 file changes, clear scope) can skip straight to a
branch + PR.
Branch naming
| Prefix | Use for | Example |
|---|---|---|
feat/ |
New functionality | feat/lead-capture-phase2a |
fix/ |
Bug fixes | fix/notifications-dedup |
docs/ |
Documentation changes | docs/revamp-pass-1 |
refactor/ |
Non-behavior-changing code reorganization | refactor/extract-jwt-verifier |
chore/ |
Deps, CI, tooling | chore/bump-mkdocs-material |
Create from current main:
git checkout main
git pull origin main
git checkout -b feat/<short-descriptive-name>
Commit message style (Conventional Commits)
All commits follow Conventional Commits with an optional scope. Examples from recent history:
feat(db): composite index on notifications dedup lookupfix(notifications): dedup rapid-fire fanout within 30s windowdocs(plan): API HTTP auth middleware implementation plan — 15 TDD tasksdocs(spec): API HTTP auth middleware design — defense in depth for Expressfeat(db): composite index on (cluster_id, status, last_message_at)
Rules
- First line ≤ 72 characters — no period at end
- Scope is optional but preferred —
api,admin,rag,db,notifications,leads, etc. - Present tense, imperative mood — "add X", not "added X"
- Body paragraph(s) for the why — what problem does this solve, what alternative was considered, what gotchas did you hit
- Footer:
Co-Authored-By:lines for pair-programming or AI assistance (HUPH commits by convention includeCo-Authored-By: Claude Opus 4.6 (1M context)when Claude was involved)
Example
feat(leads): atomic phone-merge in Lead Capture Phase 2A
The leadStore.upsert uses INSERT ... ON CONFLICT with a CASE clause
that recomputes status inline from COALESCE'd values. Without the
inline recompute, concurrent writers can race and a stale
'incomplete' status overwrites a row that should be 'new'. Uses the
`xmax = 0` postgres trick to distinguish INSERT vs UPDATE in the
RETURNING clause.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TDD expectations
For apps/api and apps/rag:
- Write the failing test first. Run it, verify it fails with the expected error message.
- Implement the minimum code to make the test pass.
- Run the test suite — all tests (not just yours) must pass before commit.
- Commit test + implementation together or as two adjacent commits in the same PR.
For apps/admin: no TDD (no test infra). Verify via
npx tsc --noEmit, npm run build, and browser smoke. See
running-tests.en.md.
Spec → plan → implement pattern
For any feature touching more than 2-3 files or affecting a cross- cutting concern (auth, realtime, DB schema, external integration), follow the structured flow:
- Brainstorm — use
superpowers:brainstormingskill to explore requirements - Write spec to
docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md - Write plan to
docs/superpowers/plans/YYYY-MM-DD-<topic>.md - Execute plan task-by-task (subagent-driven or inline) with TDD per task
- Open PR referencing both spec and plan in the description
Specs and plans are commit-reviewable — don't skip them for anything
non-trivial. See existing docs/superpowers/plans/ for reference.
Bilingual documentation sync rule
If you edit a file in docs/guide/ (non-dev, Bahasa Indonesia is
source of truth), you must also update the English mirror file in
the same commit. Rules:
- Edit the
.id.mdfirst (source of truth for guide/). - Bump
last_syncedin the frontmatter. - Update the
.en.mdmirror, bump itslast_syncedtoo. - Commit both files together.
If you can't update the mirror in the same commit (e.g. you don't speak Indonesian), explicitly flag it in the PR body:
TODO: EN mirror for
guide/operators/inbox.en.mdneeds update after ID changes — flagging for follow-up.
The reviewer will catch it. No CI enforcement yet — manual discipline.
For dev/ docs (EN source), ID mirrors are not required in Pass 1.
Pre-PR checklist
Before opening a PR:
- [ ] Tests pass:
npm run test -w apps/apiandcd apps/rag && pytest - [ ] TypeScript clean:
cd apps/admin && npx tsc --noEmit - [ ] If docs touched:
cd /opt/huph && docs-env/bin/mkdocs build --strictpasses - [ ] Commit messages follow conventional commits
- [ ] No secrets in the diff (
git diff | grep -iE "api[_-]?key|secret|password") - [ ] Branch rebased on latest
main
Open the PR
git push -u origin feat/<branch-name>
gh pr create --title "feat(scope): short summary" --body "<see below>"
PR body template:
## Summary
One-paragraph overview. Why this change? What does it enable?
## Changes
- Bullet list of key files/subsystems touched
- Keep it scannable
## Test plan
- [ ] `npm run test -w apps/api` passes (<N> tests)
- [ ] `cd apps/rag && pytest` passes (<M> tests)
- [ ] Manual smoke: log in → Conversations → send test message → verify
- [ ] (if docs) `mkdocs build --strict` passes
## Spec / Plan
- Spec: docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md
- Plan: docs/superpowers/plans/YYYY-MM-DD-<topic>.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Code review
- A teammate reviews your PR
- Address feedback via new commits (do not force-push during review unless the reviewer asks)
- Once approved, merge to main (squash or merge commit — team has preferred squash merge recently for clean history)
- Delete the feature branch after merge
Gotchas
- NextAuth uses JWE, not signed JWT. Any code touching session
tokens MUST use
next-auth/jwt encode/decode, notjsonwebtoken.sign/verify. Silently fails otherwise. - No
--no-verifyto skip pre-commit hooks unless the reviewer explicitly asks. If a hook fails, fix the underlying issue. - Don't modify
docs/superpowers/specs|plans/of other people's ongoing work. Only touch your own. uph-codebase/is off-limits — legacy Laravel reference only.