Skip to content

Contributing Guide

Contentrain Studio welcomes community contributions to the AGPL core. This guide covers everything you need to set up a development environment, follow project conventions, and submit quality pull requests.

What We Accept

AcceptedNot Accepted
Bug fixesProprietary ee/ contributions (unless coordinated with maintainers)
TestsChanges that violate architecture rules
DocumentationHardcoded strings (use Contentrain dictionary)
Developer tooling improvementsSupabase imports outside server/providers/
Accessibility and UX improvementsRaw Tailwind colors (use semantic palette)
Performance and maintainabilityBreaking changes without discussion

Development Setup

Prerequisites

ToolVersionPurpose
Node.js22+Runtime
pnpm10+Package manager
Supabase CLILatestLocal database
GitLatestVersion control

Local Setup

bash
git clone https://github.com/Contentrain/studio.git
cd studio
pnpm install
cp .env.example .env
pnpm db:start
pnpm db:migrate
npx contentrain generate
pnpm dev

The app starts at http://localhost:3000.

Available Commands

bash
# Development
pnpm dev                  # Start dev server

# Code Quality
pnpm lint                 # Run ESLint
pnpm lint:fix             # Auto-fix ESLint issues
pnpm typecheck            # TypeScript type checking

# Testing
pnpm test:unit            # Pure logic and route handler tests
pnpm test:integration     # Route integration and server wiring
pnpm test:nuxt            # Composables and Nuxt runtime behavior
pnpm test:rls             # Row-Level Security behavior
pnpm test:e2e             # Browser and user-flow regressions
pnpm test:ci              # Full CI test suite

# Build
pnpm build                # Production build

# Release
pnpm release:check        # Pre-release validation (lint + typecheck + build)
pnpm release              # Full release gate + changelog + version + tag

Code Style

ESLint + Stylistic

Studio uses @nuxt/eslint with Stylistic rules. There is no Prettier -- ESLint handles both linting and formatting.

bash
pnpm lint:fix  # Always run before committing

Key Style Rules

  • No semicolons (Stylistic enforced)
  • Single quotes for strings
  • 2-space indentation
  • Trailing commas in multi-line
  • No as any type assertions -- fix the actual type issue
  • No @deprecated markers -- the project is in active development, remove things directly

Architecture Rules

These are non-negotiable -- PRs that violate them will not be merged.

Provider Pattern

NEVER import @supabase/supabase-js outside server/providers/
NEVER use provider-specific composables in routes, pages, or components
NEVER leak vendor details into application logic
NEVER hardcode plan checks -- use hasFeature()

All application code depends on provider interfaces and factories in server/utils/providers.ts.

UI and Design

  • Use the semantic color system (primary-*, secondary-*, success-*, warning-*, danger-*, info-*), never raw Tailwind colors (gray-*, red-*, etc.)
  • Follow atomic component structure: atoms, molecules, organisms
  • Use NuxtImg for all images (not <img>)
  • All <button> elements must have explicit type attribute
  • All interactive elements must have focus-visible styles

No Hardcoded Strings

All user-facing text comes from Contentrain dictionaries:

ts
const { t } = useContent()
t('auth.sign_in_title')  // => "Sign in to your account"

When adding new UI text:

  1. Add the key/value to the relevant dictionary model
  2. Run npx contentrain generate
  3. Use useContent().t('key') in the component

Enterprise Boundary

  • Never copy enterprise-only behavior into core
  • Never make core depend on ee/ implementation details
  • Core must work without ee/ present
  • Graceful degradation: features become unavailable, not broken

Workspace Scoping

Every database query MUST scope by workspace_id, not just project_id. This prevents cross-workspace data leaks.

Conventional Commits

Commits must follow the Conventional Commits specification. This is enforced by commitlint + husky.

Format

type(scope): description

[optional body]
[optional footer]

Types

TypeWhen to Use
featNew feature
fixBug fix
docsDocumentation only
styleFormatting, no code change
refactorCode change that neither fixes nor adds
perfPerformance improvement
testAdding or updating tests
choreBuild process, tooling, dependencies
ciCI configuration

Examples

bash
feat(chat): add context pin system for media assets
fix(auth): handle expired refresh token gracefully
docs(api): document CDN delivery endpoint
test(rls): add workspace member isolation tests
chore(deps): update @contentrain/types to v0.3.0

Developer Certificate of Origin

Studio uses the DCO (not a CLA). Sign off each commit:

bash
git commit -s -m "feat(chat): add context pin system"

This appends Signed-off-by: Your Name <[email protected]> to the commit message.

Testing Expectations

Choose the smallest relevant test set, but always cover behavioral changes:

Test SuiteWhen to Run
test:unitChanged pure logic, utilities, route handlers
test:integrationChanged route wiring, middleware, provider interaction
test:nuxtChanged composables, Nuxt runtime behavior
test:rlsChanged auth, permissions, database queries
test:e2eChanged user-facing workflows, UI components

Before opening a PR:

bash
pnpm lint
pnpm typecheck
pnpm test:ci

Also run pnpm test:rls and pnpm test:e2e when your change touches auth, permissions, delivery, forms, media, or end-user workflows.

Pull Request Process

Before Opening

  • [ ] Link the relevant issue or discussion
  • [ ] Run pnpm lint && pnpm typecheck && pnpm test:ci
  • [ ] Run pnpm test:rls and pnpm test:e2e if applicable
  • [ ] Update documentation when behavior or contracts change

PR Description

  • Explain the change and the user-facing impact
  • Add or update tests for regressions
  • Keep architectural boundaries intact
  • Keep changes focused -- do not mix refactors, docs, and features in one PR

Large Changes

Large or risky changes should start as an issue or discussion before implementation. This avoids wasted effort on approaches that do not align with the project direction.

Reporting Issues

  • Bugs: Use GitHub issue templates with reproduction steps
  • Features: Use GitHub issue templates with concrete proposals
  • Questions: Use GitHub Discussions
  • Security: Report privately to [email protected]

WARNING

Security vulnerabilities must be reported privately, not through public issues.

Released under the AGPL-3.0 License.