Skip to content

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)
  • git configured 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 lookup
  • fix(notifications): dedup rapid-fire fanout within 30s window
  • docs(plan): API HTTP auth middleware implementation plan — 15 TDD tasks
  • docs(spec): API HTTP auth middleware design — defense in depth for Express
  • feat(db): composite index on (cluster_id, status, last_message_at)

Rules

  1. First line ≤ 72 characters — no period at end
  2. Scope is optional but preferredapi, admin, rag, db, notifications, leads, etc.
  3. Present tense, imperative mood — "add X", not "added X"
  4. Body paragraph(s) for the why — what problem does this solve, what alternative was considered, what gotchas did you hit
  5. Footer: Co-Authored-By: lines for pair-programming or AI assistance (HUPH commits by convention include Co-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:

  1. Write the failing test first. Run it, verify it fails with the expected error message.
  2. Implement the minimum code to make the test pass.
  3. Run the test suite — all tests (not just yours) must pass before commit.
  4. 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:

  1. Brainstorm — use superpowers:brainstorming skill to explore requirements
  2. Write spec to docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md
  3. Write plan to docs/superpowers/plans/YYYY-MM-DD-<topic>.md
  4. Execute plan task-by-task (subagent-driven or inline) with TDD per task
  5. 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:

  1. Edit the .id.md first (source of truth for guide/).
  2. Bump last_synced in the frontmatter.
  3. Update the .en.md mirror, bump its last_synced too.
  4. 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.md needs 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/api and cd apps/rag && pytest
  • [ ] TypeScript clean: cd apps/admin && npx tsc --noEmit
  • [ ] If docs touched: cd /opt/huph && docs-env/bin/mkdocs build --strict passes
  • [ ] 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, not jsonwebtoken.sign/verify. Silently fails otherwise.
  • No --no-verify to 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.

See also