Skip to content

Latest commit

 

History

History
495 lines (369 loc) · 13.1 KB

File metadata and controls

495 lines (369 loc) · 13.1 KB

Contributing to Sendable

First off, thank you for considering contributing to Sendable! 🎉

The following is a set of guidelines for contributing to this project. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.

Monorepo note: sendable-monorepo is a Turborepo (pnpm workspace) with two apps — apps/web (Next.js + Convex, implemented) and apps/api (FastAPI, planned/empty scaffold). Almost all contributions today target apps/web. See the root README.md for the full repository layout.

Table of Contents


Code of Conduct

This project and everyone participating in it is governed by our commitment to fostering an open and welcoming environment. Please be respectful and professional in all interactions.

Our Standards

  • Be Respectful: Treat everyone with respect and kindness
  • Be Collaborative: Work together towards the common goal
  • Be Patient: Help others learn and grow
  • Accept Feedback: Be open to constructive criticism
  • Focus on What's Best: Prioritize the project and community

Getting Started

Prerequisites

Before you begin, ensure you have:

  • Node.js (v20.x or higher)
  • pnpm v10.17.1 (pinned via the packageManager field — use Corepack to match it automatically: corepack enable && corepack prepare pnpm@10.17.1 --activate)
  • Git
  • A Convex account (Sign up free)
  • A code editor (VS Code recommended)

Initial Setup

  1. Fork the Repository

    # Click the "Fork" button on GitHub
  2. Clone Your Fork

    git clone https://github.com/hasnaintypes/sendable-monorepo.git
    cd sendable-monorepo
  3. Add Upstream Remote

    git remote add upstream https://github.com/hasnaintypes/sendable-monorepo.git
  4. Install Dependencies (run from the repo root — this installs all workspaces)

    pnpm install
  5. Set Up Environment Variables

    cp apps/web/.env.example apps/web/.env.local
    # Edit apps/web/.env.local with your credentials
  6. Start Development Server (run from the repo root)

    pnpm dev

    The first run triggers Convex's predev hook (convex dev --skip-push), which walks you through provisioning your Convex deployment. Set the remaining environment variables on the Convex dashboard (Settings → Environment Variables) as well — Convex actions don't read .env.local.


🔄 Development Workflow

Branching Strategy

We follow a feature-branch workflow:

main (production)
  ↓
develop (staging)
  ↓
feature/your-feature-name (your work)

Creating a Feature Branch

# Update your local main branch
git checkout main
git pull upstream main

# Create and switch to a new branch
git checkout -b feature/your-feature-name

# Or for bug fixes
git checkout -b fix/bug-description

# Or for documentation
git checkout -b docs/what-you-are-documenting

Branch Naming Convention

  • feature/ - New features (e.g., feature/lead-scoring)
  • fix/ - Bug fixes (e.g., fix/email-validation)
  • docs/ - Documentation updates (e.g., docs/api-reference)
  • refactor/ - Code refactoring (e.g., refactor/auth-flow)
  • test/ - Adding tests (e.g., test/campaign-creation)
  • chore/ - Maintenance tasks (e.g., chore/update-dependencies)

Keep Your Branch Updated

# Fetch latest changes from upstream
git fetch upstream

# Rebase your branch onto upstream/main
git rebase upstream/main

# If there are conflicts, resolve them and continue
git add .
git rebase --continue

# Force push to your fork (only for your feature branches!)
git push origin feature/your-feature-name --force

Project Structure

sendable-monorepo/
├── apps/
│   ├── web/                  # Next.js 16 + Convex — the only implemented app
│   │   ├── convex/           # Backend (Convex functions, schema per module)
│   │   ├── src/              # Next.js App Router, components, lib
│   │   └── CONTRIBUTING.md   # (this file lives at the repo root now)
│   └── api/                  # FastAPI agent backend — planned, empty scaffold
├── docs/                     # Canonical architecture & feature reference
└── turbo.json / pnpm-workspace.yaml

For the full, up-to-date directory tree of apps/web (Convex modules, routes, components), see apps/web/README.md rather than duplicating it here — it changes often enough that a second copy would go stale.

Key Files

  • apps/web/convex/schema.ts - Database schema (modify carefully; composes per-module tables from convex/*/schema.ts)
  • apps/web/src/app/layout.tsx - Root layout
  • apps/web/src/lib/auth/client.tsx - Client-side auth
  • apps/web/convex/auth/helpers.ts - Server-side auth (Better Auth instance + plugin config)

Coding Standards

TypeScript

  • Always use TypeScript - No plain JavaScript files
  • Define types explicitly - Avoid any unless absolutely necessary
  • Use interfaces for objects - Prefer interface over type for object shapes
  • Export types - Make types reusable across files
// Good
interface Lead {
  id: string;
  email: string;
  company: string;
  status: "new" | "contacted" | "replied";
}

// Bad
const lead: any = { ... };

React Components

  • Use functional components - No class components
  • Use hooks - Leverage React hooks for state and effects
  • One component per file - Keep files focused
  • Export named components - Avoid default exports for components
// Good
export function LeadCard({ lead }: { lead: Lead }) {
  const [isExpanded, setIsExpanded] = useState(false);
  
  return (
    <Card>
      {/* Component content */}
    </Card>
  );
}

// Bad
export default ({ lead }) => <div>...</div>

Convex Functions

  • Use clear function names - Describe what the function does
  • Validate inputs - Always check arguments
  • Use transactions - For multi-document operations
  • Handle errors gracefully - Return meaningful error messages
// Good — follows the ownership-check pattern used throughout convex/campaigns/
export const create = mutation({
  args: {
    name: v.string(),
    goal: v.string(),
  },
  handler: async (ctx, args) => {
    const user = await authComponent.safeGetAuthUser(ctx);
    if (!user) throw new Error("Not authenticated");

    return await ctx.db.insert("campaigns", {
      userId: user._id,
      ...args,
      createdAt: Date.now(),
      updatedAt: Date.now(),
    });
  },
});

Styling

  • Use Tailwind CSS - Utility-first approach
  • Follow shadcn/ui patterns - For consistent component styling
  • Mobile-first - Design for mobile, enhance for desktop
  • Dark mode support - Use theme-aware classes
// Good
<div className="flex flex-col gap-4 p-6 md:flex-row md:gap-6 md:p-8">
  <button className="bg-primary text-primary-foreground hover:bg-primary/90">
    Click me
  </button>
</div>

// Bad
<div style={{ display: "flex", padding: "24px" }}>
  <button style={{ background: "#007bff" }}>Click me</button>
</div>

File Naming

  • React components: PascalCase (e.g., LeadCard.tsx)
  • Utilities/hooks: camelCase (e.g., useLeadFilter.ts)
  • Convex functions: camelCase (e.g., mutations.ts, queries.ts)
  • Pages: lowercase with hyphens (e.g., forget-password/page.tsx)

Commit Guidelines

We follow Conventional Commits for clear commit history.

Commit Message Format

<type>(<scope>): <subject>

<body>

<footer>

Types

  • feat: - New feature
  • fix: - Bug fix
  • docs: - Documentation changes
  • style: - Code style changes (formatting, no logic change)
  • refactor: - Code refactoring
  • perf: - Performance improvements
  • test: - Adding or updating tests
  • chore: - Maintenance tasks
  • ci: - CI/CD changes

Examples

# Feature
git commit -m "feat(leads): add CSV import functionality"

# Bug fix
git commit -m "fix(auth): correct redirect after password reset"

# Documentation
git commit -m "docs(readme): update installation instructions"

# Refactor
git commit -m "refactor(campaigns): simplify email generation logic"

# Multiple paragraphs
git commit -m "feat(analytics): add campaign performance dashboard

- Add funnel visualization
- Implement reply rate tracking
- Add sentiment analysis chart

Closes #123"

Commit Best Practices

  • Atomic commits - Each commit should be a single logical change
  • Present tense - "Add feature" not "Added feature"
  • Imperative mood - "Fix bug" not "Fixes bug"
  • Be descriptive - Explain what and why, not just what
  • Reference issues - Use "Closes #123" or "Fixes #456"

🔀 Pull Request Process

Before Submitting

  1. Update your branch with the latest main
  2. Run all checks locally, from the repo root:
    pnpm lint
    pnpm typecheck
    pnpm format:check
    pnpm build
  3. Test your changes thoroughly (manually — there's no automated suite yet, see Testing)
  4. Update documentation if needed

Creating a Pull Request

  1. Push your branch to your fork

    git push origin feature/your-feature-name
  2. Open a PR on GitHub

    • Use a clear, descriptive title
    • Reference related issues
    • Fill out the PR template completely
  3. PR Title Format

    feat(leads): add bulk delete functionality
    fix(auth): resolve email verification bug
    docs(contributing): improve setup instructions
    

PR Template

When you open a PR, include:

## Description
Brief description of what this PR does.

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

## Related Issues
Closes #123

## Changes Made
- Added X functionality
- Fixed Y bug
- Updated Z documentation

## Testing Done
- [ ] Tested locally
- [ ] Added unit tests
- [ ] Tested on multiple browsers
- [ ] Tested mobile responsiveness

## Screenshots (if applicable)
[Add screenshots here]

## Checklist
- [ ] My code follows the project's coding standards
- [ ] I have added tests that prove my fix/feature works
- [ ] I have updated the documentation
- [ ] My changes generate no new warnings
- [ ] I have checked my code and corrected any misspellings

Review Process

  1. Automated checks must pass (linting, type checking, build)
  2. At least one approval from a maintainer required
  3. Address feedback promptly and professionally
  4. Resolve conflicts if any arise
  5. Squash commits may be required before merge

After Merge

  1. Delete your branch (both local and remote)

    git branch -d feature/your-feature-name
    git push origin --delete feature/your-feature-name
  2. Update your main branch

    git checkout main
    git pull upstream main

Testing

There is currently no automated test suite in this repo. pnpm typecheck and pnpm lint (both run from the repo root, enforced in CI) are the primary correctness gates today:

pnpm typecheck    # Type-checks apps/web's src/ and convex/ separately
pnpm lint         # ESLint over src/ and convex/
pnpm format:check # Prettier check

If you're adding a test runner or writing the first tests for a feature, open an issue first to agree on the approach (framework, scope) before sinking time into it — this is a meaningful, repo-wide decision, not a per-PR one.


Documentation

Code Documentation

  • Add JSDoc comments for complex functions
  • Explain "why" not "what" - Code shows what, comments explain why
  • Keep comments updated - Outdated comments are worse than none
/**
 * Calculates lead score based on engagement metrics
 * 
 * Uses a weighted algorithm that prioritizes recent activity:
 * - Email opens: 1 point
 * - Email clicks: 3 points
 * - Replies: 5 points
 * - Positive sentiment: 2x multiplier
 * 
 * @param lead - The lead to score
 * @returns Score between 0-100
 */
export function calculateLeadScore(lead: Lead): number {
  // Implementation
}

Documentation Files

When updating docs:

  • Keep README.md current - Reflect actual functionality
  • Update CHANGELOG.md - Document notable changes
  • Add inline examples - Show usage in comments
  • Create guides - For complex features

Questions?

If you have questions:

  1. Check existing Issues
  2. Search Discussions
  3. Open a new issue with the question label

Thank You!

Your contributions make Sendable better for everyone. We appreciate your time and effort!


Happy Coding!