Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:25:07 +08:00
commit f613de7a1a
13 changed files with 4333 additions and 0 deletions

552
assets/bad-pr-example.md Normal file
View File

@@ -0,0 +1,552 @@
# Bad PR Example
This example demonstrates common mistakes that annoy maintainers and lead to PR rejection or delays. Learn what NOT to do!
---
## Example: Adding OAuth2 Authentication (Done Wrong)
### PR Title ❌
```
Updated code
```
**Why it's bad:**
- ❌ Too vague
- ❌ Doesn't describe what changed
- ❌ No type prefix (feat/fix/docs)
- ❌ Wrong tense (past instead of imperative)
- ❌ Lowercase (should capitalize)
**Should be:**
```
feat(auth): add OAuth2 support for Google and GitHub providers
```
---
### PR Description ❌
```markdown
## Changes
Added OAuth
## Testing
Works for me
```
**Why it's bad:**
- ❌ No explanation of WHAT was added
- ❌ No explanation of WHY it's needed
- ❌ No explanation of HOW it works
- ❌ No testing instructions for reviewers
- ❌ No issue links
- ❌ No screenshots
- ❌ "Works for me" is not helpful
**Result:** Maintainer has to ask multiple questions before even starting review.
---
### Files Changed (Messy!) ❌
```
.env # ❌ SECRETS COMMITTED!
.vscode/settings.json # ❌ Personal IDE config
SESSION.md # ❌ Personal development notes
planning/oauth-implementation.md # ❌ Planning documents
screenshots/debug-oauth-1.png # ❌ Debug screenshots
screenshots/debug-oauth-2.png # ❌ Debug screenshots
screenshots/test-local.png # ❌ Personal testing screenshots
test-manual.js # ❌ Temporary test file
NOTES.md # ❌ Personal notes
TODO.md # ❌ Personal todo list
node_modules/ # ❌ Dependencies (should be in .gitignore!)
package-lock.json # ❌ Lock file changes (not needed)
src/routes/auth.js # ✅ Actual feature code
src/routes/users.js # ❌ Unrelated changes
src/routes/posts.js # ❌ Unrelated changes
src/components/Header.js # ❌ Unrelated changes
src/utils/formatting.js # ❌ Unrelated refactoring
README.md # ✅ Documentation update
docs/authentication.md # ✅ OAuth documentation
```
**Problems:**
-**28 files changed** (way too many!)
-**Secrets committed** (.env file with API keys)
-**Personal artifacts** (SESSION.md, NOTES.md, planning/)
-**Unrelated changes** (users.js, posts.js, Header.js)
-**Mixed concerns** (feature + refactoring + bug fixes)
**Should be:** 5-8 files, only those directly related to OAuth feature.
---
### Commit History (Terrible!) ❌
```
WIP
fixed stuff
asdf
more changes
fix
actually working now
Final commit
Actually final
OK this one is final
oops forgot something
```
**Why it's bad:**
- ❌ 10 commits for one feature (should squash)
- ❌ Meaningless commit messages
- ❌ "WIP" commits (not production-ready)
- ❌ No explanation of what changed
- ❌ No issue links
- ❌ Commit history shows trial-and-error (should clean up)
**Should be:** 1-2 clean commits with proper messages.
---
### SESSION.md Content (Should Never Be Committed!) ❌
```markdown
# OAuth Implementation Session
## 2025-11-04
Started working on OAuth. Not sure if I should use passport or just implement it myself. Going to try passport first.
## 2025-11-05
Passport is confusing. Spent 3 hours debugging. Finally got it working but the code is messy.
TODO:
- Clean up the callback logic
- Add tests (maybe)
- Figure out how to handle errors
- Ask @maintainer about rate limiting?
NOTES:
- Google OAuth app ID: 123456789-abcdefgh.apps.googleusercontent.com
- Redirect URI: http://localhost:3000/auth/google/callback
- Remember to add to staging: https://staging.myapp.com/auth/google/callback
BUGS FOUND:
- Header component has alignment issue on mobile
- Post creation form doesn't validate correctly
- User profile page crashes when avatar is null
```
**Why this should NEVER be in a PR:**
- ❌ Personal development journal
- ❌ Reveals your confusion/struggle
- ❌ Contains unfinished TODOs
- ❌ Mentions unrelated bugs
- ❌ Unprofessional appearance
- ❌ Pollutes the project
---
### NOTES.md Content (Should Never Be Committed!) ❌
```markdown
# Development Notes
## OAuth Research
Looked at how GitHub and GitLab do OAuth. Their implementations are pretty complex. Mine is simpler.
## Design Decisions
- Using passport because it's easier
- Not implementing token refresh yet (can do later)
- Rate limiting - should probably add this but skipping for now
- Testing - added some tests but not complete coverage
## Things I'm Not Sure About
- Is the error handling good enough?
- Should I use sessions or JWT?
- Do I need to validate the email from OAuth providers?
## Known Issues
- Doesn't work in Safari (CORS issue)
- Memory leak in callback handler (need to fix)
- Missing rate limiting (security risk?)
```
**Why this hurts your PR:**
- ❌ Shows incomplete work
- ❌ Admits to known issues not mentioned in PR
- ❌ Reveals security concerns not addressed
- ❌ Makes maintainer lose confidence
- ❌ Creates more work for maintainer
---
### Communication During Review ❌
**Initial Comment:**
```
Here's my OAuth implementation. Let me know what you think.
```
**Why it's bad:**
- ❌ No context
- ❌ No explanation
- ❌ No testing instructions
- ❌ Sounds careless
---
**Response to Feedback (Poor):**
**Maintainer:** "Could you add tests for the error cases?"
**Bad Response:**
```
Tests are boring. The code works fine without them.
```
**Why it's bad:**
- ❌ Dismissive
- ❌ Unprofessional
- ❌ Doesn't follow project standards
- ❌ Shows lack of respect
---
**Maintainer:** "This PR is too large. Could you split it into smaller PRs?"
**Bad Response:**
```
It's all related though. I don't want to spend time splitting it up.
```
**Why it's bad:**
- ❌ Refuses reasonable request
- ❌ Doesn't consider reviewer's time
- ❌ Makes review harder
- ❌ Likely to be closed
---
**No Response for 2 Weeks**
**Maintainer:** "The tests are failing. Can you fix them?"
**Your response:** [Silence for 2 weeks]
**Why it's bad:**
- ❌ Wastes maintainer's time
- ❌ PR goes stale
- ❌ Likely to be closed
- ❌ Damages your reputation
---
### PR Metrics ❌
**Size:**
- Lines changed: 847
- Files changed: 28
- Commits: 10
**Problems:**
- ❌ Way too large (should be <200 lines)
- ❌ Too many files (includes unrelated changes)
- ❌ Messy commit history
**Timeline:**
- Submitted: Day 1
- Maintainer requests changes: Day 2
- No response: Days 3-16
- PR closed as stale: Day 17
---
## Specific Mistakes Breakdown
### 1. Committed Secrets ❌
**.env file contents:**
```
GOOGLE_CLIENT_ID=123456789-abcdefgh.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-abc123def456 # ❌ SECRET!
GITHUB_CLIENT_ID=Iv1.1234567890abcdef
GITHUB_CLIENT_SECRET=1234567890abcdef1234567890abcdef12345678 # ❌ SECRET!
DATABASE_URL=postgresql://admin:SuperSecret123@localhost/myapp # ❌ PASSWORD!
```
**Impact:**
- 🚨 Security breach!
- 🚨 Must rotate all secrets immediately
- 🚨 Potentially compromises production
- 🚨 Even if removed later, it's in git history
**What you should have done:**
- ✅ Only commit .env.example with placeholder values
- ✅ Add .env to .gitignore
- ✅ Never commit actual secrets
---
### 2. Including Unrelated Changes ❌
**src/routes/users.js:**
```javascript
// OAuth PR includes this "drive-by fix"
exports.getUser = async (req, res) => {
const user = await User.findById(req.params.id);
// Fixed bug where avatar URL was broken
if (user.avatar) {
user.avatar = user.avatar.replace('http://', 'https://');
}
res.json(user);
};
```
**Why it's bad:**
- ❌ Not related to OAuth feature
- ❌ Makes PR harder to review
- ❌ Mixed concerns
- ❌ If PR is reverted, this fix goes too
**What you should have done:**
- ✅ Create separate PR for bug fix
- ✅ Keep OAuth PR focused on OAuth only
---
### 3. Massive PR with No Breakdown ❌
**Includes all at once:**
- OAuth implementation (200 lines)
- Refactoring of existing auth (300 lines)
- Bug fixes in unrelated files (150 lines)
- UI updates (100 lines)
- Test updates (97 lines)
**Total: 847 lines in 28 files**
**Why it's bad:**
- ❌ Takes hours to review
- ❌ Hard to find bugs
- ❌ Difficult to discuss
- ❌ Can't merge incrementally
**What you should have done:**
- ✅ PR #1: Refactor existing auth (300 lines)
- ✅ PR #2: Add OAuth backend (200 lines)
- ✅ PR #3: Add OAuth UI (100 lines)
- ✅ PR #4: Fix related bugs (150 lines)
---
### 4. Poor Testing ❌
**test-manual.js (Committed by mistake!):**
```javascript
// Quick test script - DELETE BEFORE COMMIT!
const axios = require('axios');
async function testOAuth() {
// This only works on my machine
const response = await axios.get('http://localhost:3000/auth/google');
console.log('Works!');
}
testOAuth();
```
**Why it's bad:**
- ❌ Not a proper test
- ❌ Hardcoded localhost
- ❌ No assertions
- ❌ Comment says "DELETE BEFORE COMMIT"
- ❌ Clutters project
**What you should have done:**
- ✅ Delete this file
- ✅ Write proper tests in tests/auth/oauth.test.js
- ✅ Use project's testing framework
- ✅ Include assertions and edge cases
---
### 5. Missing Documentation ❌
**README.md changes:**
```markdown
## Authentication
We now have OAuth.
```
**Why it's bad:**
- ❌ No setup instructions
- ❌ No explanation of how it works
- ❌ No examples
- ❌ Unhelpful to users
**Should be:**
```markdown
## Authentication
### OAuth 2.0 Social Login
Users can sign in with Google or GitHub accounts.
#### Setup
1. Create OAuth apps:
- Google: https://console.cloud.google.com/apis/credentials
- GitHub: https://github.com/settings/developers
2. Add credentials to `.env`:
```
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret
```
3. Restart server
#### Usage
Users will see "Sign in with Google" and "Sign in with GitHub" buttons on the login page.
For detailed implementation, see [docs/authentication.md](docs/authentication.md).
```
---
### 6. Ignoring CI Failures ❌
**CI Status:**
```
❌ Tests: 5 failing
❌ Lint: 23 errors
❌ Build: Failed
```
**Your response:** Submit PR anyway, hope maintainer doesn't notice
**Why it's bad:**
- ❌ Shows you didn't test
- ❌ Wastes CI resources
- ❌ Can't merge with failing CI
- ❌ Unprofessional
**What you should have done:**
- ✅ Fix all CI issues before submitting
- ✅ Run tests locally first: `npm test`
- ✅ Run lint locally: `npm run lint`
- ✅ Only submit when all checks pass
---
## The Result
**Maintainer's Response:**
```
Thanks for the PR, but there are several issues:
1. You've committed secrets in the .env file - this is a security issue
2. The PR includes unrelated changes (users.js, posts.js, Header.js)
3. Personal development files (SESSION.md, NOTES.md, planning/) shouldn't be here
4. The PR is too large - 847 lines across 28 files
5. Tests are failing
6. Missing proper documentation
7. test-manual.js is committed
Please:
- Remove all secrets and rotate them
- Create separate PRs for unrelated changes
- Remove personal development artifacts
- Fix the failing tests
- Add proper documentation
- Keep the PR focused on OAuth only
I'm closing this for now. Please feel free to submit a new PR addressing these issues.
```
**Status:** ❌ PR Closed
---
## Key Lessons
### What Went Wrong
1. **Security**: Committed secrets (.env file)
2. **Scope**: Too large, too many unrelated changes
3. **Artifacts**: Personal files committed (SESSION.md, NOTES.md)
4. **Testing**: Poor testing, CI failures
5. **Documentation**: Inadequate documentation
6. **Communication**: Poor responses to feedback
7. **Quality**: Messy commits, no code review
8. **Professionalism**: Dismissive attitude
### How to Fix It
1. **Security**
- Never commit secrets
- Use .env.example with placeholders
- Run pre-PR check script
2. **Scope**
- Keep PRs small (<200 lines)
- One feature per PR
- No unrelated changes
3. **Artifacts**
- Remove SESSION.md, NOTES.md, TODO.md
- Remove planning/ directory
- Remove debug screenshots
- Use clean-branch script
4. **Testing**
- Write proper tests
- Fix CI before submitting
- Test locally first
5. **Documentation**
- Update README
- Add setup instructions
- Include examples
6. **Communication**
- Be responsive
- Be respectful
- Accept feedback gracefully
7. **Quality**
- Clean commit history
- Proper commit messages
- Review your own code
8. **Professionalism**
- Respect maintainer's time
- Follow project conventions
- Be patient and courteous
---
## Comparison: Bad vs Good
| Aspect | Bad PR ❌ | Good PR ✅ |
|--------|-----------|-----------|
| **Title** | "Updated code" | "feat(auth): add OAuth2 support" |
| **Size** | 847 lines, 28 files | 180 lines, 9 files |
| **Commits** | 10 messy commits | 1 clean commit |
| **Files** | Includes SESSION.md, .env | Only relevant files |
| **Testing** | test-manual.js, CI failing | Proper tests, CI passing |
| **Docs** | "We now have OAuth" | Complete setup guide |
| **Secrets** | Committed .env | Only .env.example |
| **Scope** | OAuth + bugs + refactor | OAuth only |
| **Communication** | Dismissive | Professional |
| **Result** | Closed | Merged in 3 days |
---
**Remember:** Every mistake in this example is based on real PRs that have been rejected. Learn from these errors and follow the good PR example instead!

308
assets/good-pr-example.md Normal file
View File

@@ -0,0 +1,308 @@
# Good PR Example
This example demonstrates a well-structured pull request that follows best practices for open source contributions.
---
## Example: Adding OAuth2 Authentication
### PR Title
```
feat(auth): add OAuth2 support for Google and GitHub providers
```
**Why it's good:**
- ✅ Uses Conventional Commits format (feat)
- ✅ Includes scope (auth)
- ✅ Clear, specific description
- ✅ Under 50 characters
- ✅ Imperative mood
---
### PR Description
```markdown
## What?
Add OAuth2 authentication support for Google and GitHub providers, allowing users to sign in with their social accounts.
## Why?
Multiple users have requested social login to reduce friction during signup (issues #234, #156). This addresses a key pain point: 40% of attempted signups are abandoned at the password creation step according to our analytics.
This implements Key Result 2 of Q4 OKR1: "Reduce signup friction by 30%"
## How?
- Implemented OAuth2 flow using passport.js strategy pattern
- Added provider configuration via environment variables (no hardcoded secrets)
- Created callback routes for each provider:
- `/auth/google/callback`
- `/auth/github/callback`
- Updated user model to link social accounts with existing email-based accounts
- Added middleware to automatically merge accounts if user already exists with same email
- Implemented proper error handling for failed OAuth attempts
## Testing
### Setup
1. Create OAuth apps in developer consoles:
- Google: https://console.cloud.google.com/apis/credentials
- GitHub: https://github.com/settings/developers
2. Add credentials to `.env` file (see `.env.example` for required variables)
3. Run `npm install` to ensure passport dependencies are installed
### Manual Testing Steps
1. Start server: `npm start`
2. Navigate to `http://localhost:3000/login`
3. Click "Login with Google" button
4. Verify OAuth flow redirects to Google consent screen
5. Grant permissions
6. Verify redirect back to app with user logged in
7. Check user profile shows data from Google (name, email, avatar)
8. Repeat steps 3-7 for GitHub provider
### Test Cases Covered
- ✅ New user signup via OAuth
- ✅ Existing user login via OAuth
- ✅ Account merging (same email, different provider)
- ✅ Error handling (user denies permissions)
- ✅ Error handling (OAuth provider timeout)
- ✅ Security: CSRF token validation
### Automated Tests
```bash
npm test -- tests/auth/oauth.test.js
```
All 15 test cases pass, including edge cases.
## Checklist
- [x] Tests added/updated (tests/auth/oauth.test.js)
- [x] Documentation updated:
- [x] README.md (setup instructions)
- [x] docs/authentication.md (OAuth flow documentation)
- [x] .env.example (required environment variables)
- [x] CI passing (all checks green)
- [x] No breaking changes
- [x] Follows existing code style
- [x] Security review completed (no secrets committed)
## Related Issues
Closes #234
Relates to #156 (social login epic)
## Screenshots
### Login Page with OAuth Buttons
![OAuth Login Buttons](./screenshots/oauth-buttons.png)
*New social login buttons integrated into existing login page*
### OAuth Consent Screen (Google)
![Google Consent](./screenshots/google-consent.png)
*User experience during Google OAuth flow*
## Breaking Changes
None - this is additive functionality that doesn't affect existing authentication methods.
## Security Considerations
- OAuth tokens are stored securely using bcrypt hashing
- CSRF protection implemented for all OAuth routes
- State parameter used to prevent CSRF attacks
- No secrets committed to repository (all in .env)
- Rate limiting applied to OAuth endpoints
## Additional Notes
### Design Decisions
- **Chose passport.js** over custom implementation for security, maintenance, and community support
- **Used strategy pattern** to make adding new OAuth providers easier in future
- **Account merging** happens automatically based on email address (primary key)
- **No email verification required** for OAuth signups (providers already verify emails)
### Future Improvements
Consider in follow-up PRs:
- Add more providers (Twitter, LinkedIn, Microsoft)
- Implement OAuth token refresh logic
- Add rate limiting for OAuth endpoints
- Add admin dashboard for managing OAuth apps
### Migration Notes
No migration needed - existing users can continue using password authentication. OAuth is an additional option.
### Dependencies Added
- passport v0.6.0
- passport-google-oauth20 v2.0.0
- passport-github2 v0.1.12
All dependencies are actively maintained and have good security track records.
```
---
### Files Changed (Clean!)
```
.env.example # Environment variable examples (no secrets!)
README.md # Updated setup instructions
docs/authentication.md # OAuth documentation
package.json # Added passport dependencies
src/routes/auth.js # OAuth routes
src/middleware/authenticate.js # OAuth middleware
src/models/user.js # Updated user model
tests/auth/oauth.test.js # OAuth tests
tests/fixtures/users.json # Test fixtures
```
**What's NOT included:**
- ❌ No SESSION.md or notes files
- ❌ No planning/ directory
- ❌ No debug screenshots (only feature demos)
- ❌ No temporary test files
- ❌ No .env file (only .env.example)
- ❌ No personal artifacts
---
### Commit History (Clean!)
```
feat(auth): add OAuth2 support for Google and GitHub
Implemented OAuth2 authentication flow using passport.js.
Users can now sign in with Google or GitHub accounts.
Accounts are automatically merged if email matches existing user.
- Added OAuth routes and callbacks
- Updated user model to support social accounts
- Added comprehensive tests for OAuth flow
- Documented setup and usage
Closes #234
```
**Why it's good:**
- ✅ Single, focused commit
- ✅ Clear commit message
- ✅ Explains what and why
- ✅ Links issue
- ✅ Follows Conventional Commits
---
### Communication During Review
**Initial Comment (When Submitting):**
```
Hi @maintainer! 👋
I've implemented OAuth2 support as discussed in #234. I went with passport.js over a custom implementation because:
1. Battle-tested security
2. Well-maintained by the community
3. Easy to add more providers in future
I've tested this locally for the past week and also deployed to staging for integration testing. All existing auth flows remain unchanged - this is purely additive.
Ready for review when you have time! Happy to make any changes you'd like.
```
**Response to Feedback:**
```
> Could you add rate limiting to these endpoints?
Good idea! I've added rate limiting in commit abc1234:
- Max 5 OAuth attempts per IP per minute
- Returns 429 with Retry-After header
- Uses existing rate limiting middleware
Let me know if you'd prefer different limits!
```
**After Changes:**
```
@maintainer I've addressed all your feedback:
- ✅ Added rate limiting (commit abc1234)
- ✅ Updated docs with security considerations (commit def5678)
- ✅ Refactored callback logic as suggested (commit ghi9012)
Marked all conversations as resolved. Ready for re-review!
Thanks for the thorough feedback - the rate limiting suggestion was spot-on.
```
---
### PR Metrics
**Size:**
- Lines changed: 180
- Files changed: 9
- Commits: 1
**Result:**
- ✅ Ideal size for review
- ✅ Focused on one feature
- ✅ Easy to understand
- ✅ Quick to review
**Timeline:**
- Submitted: Day 1
- First review: Day 2
- Changes made: Day 2
- Approved: Day 3
- Merged: Day 3
**Why it was quick:**
- Clean, focused PR
- Comprehensive testing
- Good documentation
- Responsive to feedback
- No surprises or issues
---
## Key Takeaways
This PR demonstrates:
1. **Clear Communication**
- What/Why/How structure
- Testing instructions
- Design decisions explained
- Security considerations noted
2. **Proper Scope**
- One feature
- ~180 lines changed
- No unrelated changes
- Easy to review
3. **Complete Documentation**
- Updated README
- Added OAuth docs
- Included .env.example
- Comprehensive inline comments
4. **Thorough Testing**
- Automated tests
- Manual test steps
- Edge cases covered
- Deployed to staging first
5. **Professional Artifacts**
- No personal files
- No secrets
- Clean commit history
- Proper branch naming
6. **Excellent Communication**
- Polite and respectful
- Responsive to feedback
- Explains decisions
- Thanks reviewers
7. **Security Conscious**
- No secrets committed
- CSRF protection
- Rate limiting
- Security considerations documented
This is the standard to aim for in your pull requests!