Thank you for your interest in contributing to Quackback! This guide will help you get started.
# Clone the repository
git clone https://github.com/quackbackio/quackback.git
cd quackback
# Run setup (installs dependencies, starts Docker, runs migrations, seeds demo data)
bun run setup
# Start development server
bun run devOpen http://localhost:3000 to see the app.
quackback/
├── apps/web/ # TanStack Start application
│ ├── src/
│ │ ├── routes/ # File-based routing (TanStack Router)
│ │ ├── components/ # UI and feature components
│ │ └── lib/ # Business logic, auth config, services
│ └── e2e/ # Playwright E2E tests
├── packages/
│ ├── db/ # Database (Drizzle schema, migrations)
│ ├── ids/ # TypeID system (branded UUIDs)
│ └── email/ # Email service (Resend + React Email)
├── ee/ # Enterprise Edition features (SSO, SCIM, etc.)
└── docker-compose.yml # Local PostgreSQL 18
Quackback uses TanStack Start with TanStack Router for file-based routing and server functions.
Type-safe RPC endpoints using createServerFn:
import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'
export const createPostFn = createServerFn({ method: 'POST' })
.validator(z.object({ title: z.string().min(1) }))
.handler(async ({ data }) => {
const auth = await requireAuth()
return createPost(data, auth.member)
})Business logic with typed error handling:
import { ValidationError } from '@/lib/shared/errors'
export async function createPost(input: CreatePostInput, author: Author) {
if (!input.title?.trim()) {
throw new ValidationError('VALIDATION_ERROR', 'Title is required')
}
// Business logic...
}Always import from @/lib/db, not @quackback/db:
import { db, posts, eq } from '@/lib/db'
const post = await db.query.posts.findFirst({
where: eq(posts.id, postId),
})- Single workspace,
DATABASE_URLsingleton
- Files: kebab-case (
user-profile.tsx) - Components: PascalCase (
UserProfile) - Functions: camelCase (
getUserProfile) - Database tables: snake_case (
post_tags)
# Run all tests
bun run test
# Run specific test file
bun run test path/to/test.ts
# Run E2E tests
bun run test:e2eWe require all contributors to sign our Contributor License Agreement (CLA) before we can accept contributions.
Why a CLA?
The CLA allows Quackback to:
- Offer the software under dual licenses (AGPL-3.0 for open source, commercial for enterprise)
- Defend the project against legal issues
- Ensure clean IP ownership for all contributions
How it works:
- Submit your pull request
- A CLA assistant bot will check if you've signed the CLA
- If not, the bot will prompt you to sign by commenting on the PR
- Once signed, your signature applies to all future contributions
The CLA is based on the Apache Individual Contributor License Agreement and grants Quackback the right to use your contributions under any license terms.
- Fork the repository
- Create a feature branch from
main - Make your changes
- Ensure all tests pass
- Submit a pull request
- Sign the CLA when prompted by the bot
- Keep PRs focused and reasonably sized
- Include tests for new functionality
- Update documentation if needed
- Follow the existing code style
Please use GitHub Issues for:
- Bug reports
- Feature requests
- Questions
When reporting bugs, include:
- Steps to reproduce
- Expected vs actual behavior
- Environment details (OS, browser, etc.)
Quackback core is licensed under AGPL-3.0. See LICENSE for details.