Skip to main content

Welcome Contributors

Thank you for considering contributing to Pulse Content! This guide will help you understand our development process and coding standards.

Getting Started

1

Fork and clone

git clone <your-fork-url>
cd pulse-content
2

Install dependencies

npm install
3

Set up environment

Create .dev.vars file with required environment variablesSee Setup Guide for details
4

Create a branch

git checkout -b feature/your-feature-name
# or
git checkout -b fix/bug-description
5

Start development

npm run dev

Branch Naming

Use descriptive branch names:
  • Features: feature/add-social-scheduler
  • Bug fixes: fix/editor-crash-on-save
  • Refactoring: refactor/simplify-api-client
  • Documentation: docs/update-deployment-guide
  • Tests: test/add-episode-tests

Coding Standards

TypeScript

Type Safety:
// ✅ Good: Explicit types
interface Episode {
  id: string
  episodeNumber: number
  title: string
}

function getEpisode(id: string): Promise<Episode> {
  // ...
}

// ❌ Bad: Using 'any'
function getEpisode(id: any): Promise<any> {
  // ...
}
Avoid Type Assertions:
// ✅ Good: Type guards
function isEpisode(data: unknown): data is Episode {
  return typeof data === 'object' && data !== null && 'episodeNumber' in data
}

// ❌ Bad: Unsafe assertion
const episode = data as Episode

React Components

Functional Components:
// ✅ Good: Typed props with interface
interface EpisodeCardProps {
  episode: Episode
  onClick?: (id: string) => void
}

export function EpisodeCard({ episode, onClick }: EpisodeCardProps) {
  return (
    <div onClick={() => onClick?.(episode.id)}>
      <h3>{episode.title}</h3>
    </div>
  )
}
Hooks:
// ✅ Good: Custom hooks with proper types
function useEpisode(id: string) {
  const [episode, setEpisode] = useState<Episode | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)
  
  // ... fetch logic
  
  return { episode, loading, error }
}

File Organization

src/
├── components/
│   ├── ui/              # Reusable UI components
│   │   ├── Button.tsx
│   │   └── Card.tsx
│   ├── editor/          # TipTap editor components
│   └── layout/          # Layout components
├── routes/              # Page components
│   ├── index.tsx
│   └── episode/
├── services/            # API clients
│   ├── sanity.ts
│   └── kieai.ts
├── hooks/               # Custom React hooks
├── utils/               # Utility functions
└── types/               # TypeScript type definitions

Import Order

// 1. External dependencies
import { useState, useEffect } from 'react'
import { useQuery } from '@tanstack/react-query'

// 2. Internal modules
import { Button } from '@/components/ui/Button'
import { useEpisode } from '@/hooks/useEpisode'

// 3. Types
import type { Episode } from '@/types'

// 4. Styles
import './styles.css'

Testing Requirements

All new features must include tests. PRs without tests will not be merged.

Test Coverage

Required:
  • Unit tests for utility functions
  • Component tests for UI components
  • Integration tests for API endpoints
Example:
// src/utils/formatDate.test.ts
import { describe, it, expect } from 'vitest'
import { formatDate } from './formatDate'

describe('formatDate', () => {
  it('formats date correctly', () => {
    const date = new Date('2024-03-15')
    expect(formatDate(date)).toBe('March 15, 2024')
  })

  it('handles null', () => {
    expect(formatDate(null)).toBe('Invalid date')
  })

  it('handles invalid dates', () => {
    expect(formatDate(new Date('invalid'))).toBe('Invalid date')
  })
})

Run Tests Before Committing

# Run all tests
npm run test:run

# Type check
npm run typecheck

# Lint
npm run lint

Commit Messages

Format

Follow Conventional Commits:
<type>(<scope>): <description>

[optional body]

[optional footer]

Types

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, no logic change)
  • refactor: Code refactoring
  • test: Adding or updating tests
  • chore: Maintenance tasks

Examples

# Feature
feat(editor): add table support to TipTap editor

# Bug fix
fix(api): prevent duplicate episode creation

# Documentation
docs(readme): update installation instructions

# Refactoring
refactor(services): simplify Sanity client API

# Test
test(episodes): add tests for episode CRUD operations

Pull Request Process

1

Ensure all tests pass

npm run test:run
npm run typecheck
npm run lint
2

Update documentation

  • Update README.md if needed
  • Add/update code comments
  • Update relevant docs pages
3

Create pull request

  • Write clear title and description
  • Reference related issues
  • Add screenshots for UI changes
  • Request review from maintainers
4

Address review feedback

  • Respond to comments
  • Make requested changes
  • Re-request review after updates
5

Merge

Maintainer will merge after approval

PR Template

## Description
Brief description of changes

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Testing
- [ ] Tests added/updated
- [ ] All tests pass
- [ ] Type checking passes

## Screenshots (if applicable)
[Add screenshots for UI changes]

## Related Issues
Closes #123

## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No new warnings

Code Review Guidelines

For Authors

Keep PRs Small

Aim for less than 400 lines changed. Split large features into multiple PRs.

Explain Decisions

Add comments explaining why, not just what.

Test Thoroughly

Test edge cases, error states, and happy paths.

Document Changes

Update docs and README as needed.

For Reviewers

Be Constructive

Suggest improvements, don’t just criticize.

Ask Questions

If something is unclear, ask for clarification.

Check Tests

Ensure adequate test coverage.

Consider Performance

Look for performance implications.

Design Principles

User Experience

  • Speed: Optimize for fast load times and interactions
  • Clarity: Use clear labels and error messages
  • Consistency: Follow YBH design system
  • Accessibility: Support keyboard navigation and screen readers

Code Quality

  • DRY: Don’t Repeat Yourself - extract reusable code
  • SOLID: Follow SOLID principles
  • KISS: Keep It Simple, Stupid - avoid over-engineering
  • YAGNI: You Aren’t Gonna Need It - don’t add unused features

Performance

  • Code Splitting: Lazy load large components
  • Memoization: Use useMemo and useCallback appropriately
  • Debouncing: Debounce expensive operations
  • Caching: Use React Query for API response caching

Common Pitfalls

// ❌ Bad: Direct mutation
episode.title = 'New Title'
setEpisode(episode)

// ✅ Good: Create new object
setEpisode({ ...episode, title: 'New Title' })
// ❌ Bad: No error handling
async function fetchEpisode(id: string) {
  const response = await fetch(`/api/episodes/${id}`)
  return response.json()
}

// ✅ Good: Proper error handling
async function fetchEpisode(id: string) {
  try {
    const response = await fetch(`/api/episodes/${id}`)
    if (!response.ok) throw new Error('Failed to fetch')
    return response.json()
  } catch (error) {
    console.error('Error fetching episode:', error)
    throw error
  }
}
// ❌ Bad: Using @ts-ignore
// @ts-ignore
const result = someFunction()

// ✅ Good: Fix the type issue
const result: ExpectedType = someFunction()

Getting Help

Documentation

Read the full documentation

GitHub Issues

Ask questions in GitHub Issues

Architecture

Understand the system architecture

Bug Workflow

Learn the bug-fixing process

License

Proprietary - You’ve Been Heard By contributing, you agree that your contributions will be licensed under the same license as the project.

Build docs developers (and LLMs) love