Skip to content

Contributing to Rotamer

Thank you for making it this far. This file is the path for anyone working on the code: how to start the environment, what must remain true, and how a change becomes a commit.

They are in CLAUDE.md, and apply to everyone, with or without a coding assistant. The most important ones:

  • The deterministic core decides. AI explains. Validity, valence, formula, mass, SMILES, InChIKey, descriptors, aromaticity, stereochemistry, normal-mode frequency, and mission scores always come from RDKit, the force field, or the mission engine. Never from a language model, and never from a homegrown calculation “for a quick fix.” A chemist finding a subtle error loses trust in the entire product.
  • Code in English, text in Portuguese. File, variable, function, type, and data-key names are in English; comments, test names, interface strings, and error messages are in pt-BR. Errors explain the chemistry, not the code: “The C atom has 5 bonds, but supports at most 4.”
  • CPK colors belong to atoms. No button, border, or semantic state uses a CPK color. Every color, spacing, radius, and duration comes from packages/ui/src/tokens.css. Light and dark themes always ship together.
  • An MIT-compatible license. MIT, BSD, Apache-2.0, and ISC are accepted; GPL, LGPL, and AGPL are not. Every new dependency goes into docs/TERCEIROS.md in the same commit.
  • Out-of-scope ideas go in docs/FORA-DE-ESCOPO.md, not in the code. Scope creep is the project’s number-one risk.

Use Node 24, pnpm 11.24.0, and Docker for Postgres. This is the Node version used in Docker and CI; database dependencies require versions newer than the minimum declared at the monorepo root.

corepack enable # or: npm install --global pnpm@11.24.0
pnpm install
docker compose up -d postgres # only the database; the app runs outside the container
cp apps/web/.env.example apps/web/.env # DATABASE_URL already points to this Postgres

If you already configured POSTGRES_PASSWORD in the root .env, set the password in apps/web/.env’s DATABASE_URL to the same value.

With the connection configured, apply migrations and start the app:

pnpm --filter @rotamer/web db:migrate # applies migrations
pnpm dev

http://localhost:3000. predev copies RDKit and the MMFF94 tables from node_modules to apps/web/public/chem/ and generates the Prisma client—do not commit this directory or edit it by hand.

Without DATABASE_URL, the product starts without accounts, classes, or assignments, and the editor works in full. Without GEMINI_API_KEY, the tutor disables itself and says so on screen.

To become a teacher on your development instance after creating an account at /entrar:

cd apps/web && node scripts/promote-teacher.mjs voce@exemplo.br --escola "Escola de teste"

With --administrador at the end, the account also gains the Professores da escola (School teachers) section at /turmas, where a school promotes its own teachers (D-29). Administrators can only be created through this script, and can promote no higher than teacher in the interface.

apps/web Next.js 16 · routes, server actions, accounts, classes, assignments, tutor
packages/core graph · RDKit · geometry, dynamics, and normal modes — runs without a browser
packages/editor2d the 2D canvas: tools, selection, menu, shortcuts, history
packages/viewer3d Three.js · rendering only
packages/quests declarative missions, objective extraction, scoring
packages/ui tokens and components
docs/ architecture, decisions, design system, assignments, installation, guide

Dependency rule: core depends on no one, and no package depends on editor2d. The full map is in docs/ARQUITETURA.md; the reasoning behind each choice is in docs/DECISOES.md.

R-1, §4.5, and similar references. Class code cites rules by number—R-3 in a select, §6.3 in a component. They all live in docs/ROTEIROS.md: §5.1 contains the server-rule table, §6 the screen copy, and §7 the test protecting each rule. Read it first if you work on assignments, teacher missions, or the catalog.

  1. Every change ends with a test that would fail without it. New chemistry needs a case in packages/core/test/, running without a browser, using the value RDKit calculates—never a value from a third-party table. Where RDKit differs from PubChem, RDKit wins, and the screen identifies whose definition is used.

  2. Run what CI runs, before opening the pull request:

    pnpm lint
    pnpm typecheck
    pnpm test # with Postgres running, action tests run; without it, they skip with a warning
    pnpm test:e2e # Playwright, desktop and mobile, against the production build

    test:e2e builds and starts the app on port 3100. Account, class, and assignment tests need Postgres; name-search tests skip when PubChem does not respond; tutor tests cover the behavior your .env allows—with a key, the response; without a key, its disabled state.

  3. Schema changes require additive migrations. pnpm --filter @rotamer/web db:migrate creates the migration in apps/web/prisma/migrations/. Columns are never deleted or rewritten: self-hosters update with docker compose up -d, and the migration runs before the app opens its port.

  4. Screen copy is content. Every sentence the student reads receives the same care as code: pt-BR, no programming jargon, and no claims about things the product does not do—the “Never claim” section of CLAUDE.md.

  5. Documents describe what exists. If a change contradicts a document in docs/, that document changes in the same commit. New or revised decisions go into docs/DECISOES.md, without deleting the previous decision. Comments explain why, not what the line does; test names say what they protect.

  6. Commit messages in Portuguese, in the format tipo: o que mudou (type: what changed)— feat:, fix:, docs:, refactor:, test:, chore:.

This is the most important kind of issue. Provide the SMILES (or attach the molblock), what the screen showed, and what you expected, with its source. If the discrepancy is between RDKit and another tool, identify it: many differences come from definitions (TPSA with perceived aromaticity, rotatable bonds under the strict definition), and the right response is for the screen to identify whose definition it uses—not to adjust the calculation to match the other table.

Nine roles live in .claude/agents/ for people working with a coding assistant—pm, ui-ux, frontend, backend, security, deploy, researcher, marketing, and reviewer. They are optional: they describe how the project approaches each kind of task and are useful reading even for people who do not use any agents.

By contributing, you agree that your contribution is published under the repository’s MIT license (LICENSE).