Files
chatwoot/AGENTS.md
Vishnu Narayanan 5f21903a7b chore: guard against migration version collisions (#16143)
## Description

Migrations with hand-written, rounded versions (e.g. `20260925000000`)
keep colliding across branches. Git merges two such files cleanly
because the filenames differ, and spec CI stays green because it loads
the schema instead of running migrations. The failure only shows up on a
real `db:migrate`: a `DuplicateMigrationVersionError`, or a database
that already recorded one branch's migration silently skipping the
other.

This adds:
- A `Migration Version Check` workflow on PRs that touch `db/migrate`.
It fails when a migration added or renamed in the PR has a version
ending in `0000`, and when two files in `db/migrate` share a version.
Existing migrations are not flagged.
- An `AGENTS.md` rule to create migrations with `rails g migration`
instead of writing the version by hand.

Linear: https://linear.app/chatwoot/issue/INF-118

## Type of change

CI and contributor guidelines only, no app code changes.

## How Has This Been Tested?

Ran both steps locally against simulated PR merge commits on top of
develop: a generated timestamp passes, `...000000` and `...090000`
versions fail, renaming a migration to a rounded version fails, and a
duplicate of an existing version fails. Develop as-is passes both
checks.

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2026-10-06 14:17:48 -07:00

9.6 KiB
Raw Permalink Blame History

Chatwoot Development Guidelines

Build / Test / Lint

  • Setup: bundle install && pnpm install
  • Run Dev: pnpm dev or overmind start -f ./Procfile.dev
  • Seed Local Test Data: bundle exec rails db:seed (quickly populates minimal data for standard feature verification)
  • Seed Search Test Data: bundle exec rails search:setup_test_data (bulk fixture generation for search/performance/manual load scenarios)
  • Seed Account Sample Data (richer test data): Seeders::AccountSeeder is available as an internal utility and is exposed through Super Admin Accounts#seed, but can be used directly in dev workflows too:
    • UI path: Super Admin → Accounts → Seed (enqueues Internal::SeedAccountJob).
    • CLI path: bundle exec rails runner "Internal::SeedAccountJob.perform_now(Account.find(<id>))" (or call Seeders::AccountSeeder.new(account: Account.find(<id>)).perform! directly).
  • Lint JS/Vue: pnpm eslint / pnpm eslint:fix
  • Lint Ruby: bundle exec rubocop -a
  • Test JS: pnpm test or pnpm test:watch
  • Test Ruby: bundle exec rspec spec/path/to/file_spec.rb
  • Single Test: bundle exec rspec spec/path/to/file_spec.rb:LINE_NUMBER
  • Run Project: overmind start -f Procfile.dev
  • Ruby Version: Manage Ruby via rbenv and install the version listed in .ruby-version (e.g., rbenv install $(cat .ruby-version))
  • rbenv setup: Before running any bundle or rspec commands, init rbenv in your shell (eval "$(rbenv init -)") so the correct Ruby/Bundler versions are used
  • Always prefer bundle exec for Ruby CLI tasks (rspec, rake, rubocop, etc.)

Code Style

  • Ruby: Follow RuboCop rules (150 character max line length)
  • Vue/JS: Use ESLint (Airbnb base + Vue 3 recommended)
  • Vue Components: Use PascalCase
  • Events: Use camelCase
  • I18n: No bare strings in templates; use i18n
  • Error Handling: Use custom exceptions (lib/custom_exceptions/)
  • Models: Validate presence/uniqueness, add proper indexes
  • Type Safety: Use PropTypes in Vue, strong params in Rails
  • Naming: Use clear, descriptive names with consistent casing
  • Vue API: Always use Composition API with <script setup> at the top

Styling

  • Tailwind Only:
    • Do not write custom CSS
    • Do not use scoped CSS
    • Do not use inline styles
    • Always use Tailwind utility classes
  • Colors: Refer to tailwind.config.js for color definitions

General Guidelines

  • Database foreign keys: Prefer Rails associations and callbacks over database foreign-key constraints. Add a database foreign key only when there is a clear need and after checking deletion behavior and production migration/locking risks. Existing foreign keys alone are not a reason to add new ones.
  • Migrations: Create migrations with bundle exec rails g migration <Name> so the version is a real timestamp. Never hand-write or round the version (e.g. 20260925000000); rounded versions collide across branches and break db:migrate.
  • Prefer the smallest production-ready change that solves the current problem.
  • Build for the expected production path first. Do not add speculative guards, fallbacks, retries, or edge-case handling unless the caller can actually hit that case or production has proven it necessary.
  • Enforce eligibility and exclusivity rules at the earliest shared entry point. Do not repeat backup guards across downstream jobs, callbacks, services, or writes unless a proven independent path bypasses that point.
  • Validate request parameters at the controller or request boundary, reusing existing errors so invalid input returns 422 Unprocessable Entity instead of reaching models or Sentry.
  • Accept only the documented type, shape, and value. Do not add compatibility coercions for malformed client values; fix official clients instead.
  • When an impossible or misconfigured state would indicate a setup/deployment bug, let it fail loudly instead of silently skipping behavior.
  • For locked/internal configs that must exist in production, prefer direct reads (find, find_by!, required hash keys) over silent fallbacks.
  • Do not add validation or response checks unless the code uses the result or the check changes behavior meaningfully.
  • Prefer existing repo dependencies/client libraries over hand-rolled protocol code for auth, signing, parsing, or API plumbing.
  • Avoid one-use private helpers unless they hide real complexity or make the main flow meaningfully easier to read.
  • Prefer minimal, readable code over elaborate abstractions; clarity beats cleverness
  • Break down complex tasks into small, testable units
  • Iterate after confirmation
  • Avoid writing specs unless explicitly asked
  • In specs, avoid custom helper methods for setup/data. Prefer let values and direct per-example setup; only add a helper when it removes meaningful repeated complexity.
  • Remove dead/unreachable/unused code
  • Don’t write multiple versions or backups for the same logic — pick the best approach and implement it
  • Prefer with_modified_env (from spec helpers) over stubbing ENV directly in specs
  • Specs in parallel/reloading environments: prefer comparing error.class.name over constant class equality when asserting raised errors

Codex Worktree Workflow

  • Use a separate git worktree + branch per task to keep changes isolated.
  • Keep Codex-specific local setup under .codex/ and use Procfile.worktree for worktree process orchestration.
  • The setup workflow in .codex/environments/environment.toml should dynamically generate per-worktree DB/port values (Rails, Vite, Redis DB index) to avoid collisions.
  • Start each worktree with its own Overmind socket/title so multiple instances can run at the same time.

Commit Messages

  • Prefer Conventional Commits: type(scope): subject (scope optional)
  • Example: feat(auth): add user authentication
  • Don't reference Claude in commit messages

PR Description Format

  • Start with a short, user-facing paragraph describing the product change.
  • Add a Closes section with relevant issue links (GitHub, Linear, etc.).
  • For feature PRs, add How to test from a product/UX standpoint.
  • For bugfix PRs, use How to reproduce when helpful.
  • Optionally add a What changed section for implementation highlights.
  • Do not add a How this was tested section listing specs/commands.

Project-Specific

  • Translations:
    • For product and source-string changes, only update en.yml and en.json; other languages are handled through Crowdin and the community
    • Crowdin-generated translation sync PRs may update non-English locale files; do not flag those changes solely for modifying translated locale files
    • Preserve product and brand names, OAuth scopes, API values, and other machine-readable identifiers unless an official localized form exists
    • When reviewing Crowdin syncs, verify protected terms remain unchanged. Add newly introduced product names, brand names, and machine-readable identifiers to the Crowdin glossary as non-translatable, and keep the glossary current
    • Backend i18n → en.yml, Frontend i18n → en.json
  • Frontend:
    • Use components-next/ for message bubbles (the rest is being deprecated)

Ruby Best Practices

  • Use compact module/class definitions; avoid nested styles

Frontend Conventions

  • Prefer existing design-system utilities and shared composables.
  • Use typography utilities instead of manually recreating font styles.
  • Use logical Tailwind utilities (ms, me, start, end) for direction-aware layouts.
  • Use rem for arbitrary CSS dimensions; preserve native numeric values required by chart/SVG APIs.
  • Extract repeated or domain-specific strings, thresholds, colors, and durations into named constants.
  • Use shared request-cancellation utilities instead of local AbortController logic.

Enterprise Edition Notes

Practical checklist for any change impacting core logic or public APIs

  • Search for related files in both trees before editing (e.g., rg -n "FooService|ControllerName|ModelName" app enterprise).
  • If adding new endpoints, services, or models, consider whether Enterprise needs:
    • An override (e.g., enterprise/app/...), or
    • An extension point (e.g., prepend_mod_with, hooks, configuration) to avoid hard forks.
  • Avoid hardcoding instance- or plan-specific behavior in OSS; prefer configuration, feature flags, or extension points consumed by Enterprise.
  • Keep request/response contracts stable across OSS and Enterprise; update both sets of routes/controllers when introducing new APIs.
  • When renaming/moving shared code, mirror the change in enterprise/ to prevent drift.
  • Tests: Add Enterprise-specific specs under spec/enterprise, mirroring OSS spec layout where applicable.
  • When modifying existing OSS features for Enterprise-only behavior, add an Enterprise module (via prepend_mod_with/include_mod_with) instead of editing OSS files directly—especially for policies, controllers, and services. For Enterprise-exclusive features, place code directly under enterprise/.

Branding / White-labeling note

  • For user-facing strings that currently contain "Chatwoot" but should adapt to branded/self-hosted installs, prefer applying replaceInstallationName from shared/composables/useBranding in the UI layer (for example tooltip and suggestion labels) instead of adding hardcoded brand-specific copy.