Thanks for contributing to Opencom. This guide covers everything you need to get productive.
- OSS Documentation Hub
- Architecture & Repo Map
- Setup & Deploy
- Testing & Verification
- Security & Operations
- Data Model Reference
- Backend API Reference
- Convex Type Safety Playbook
- Scripts Reference
- Node.js 18+
- PNPM 9+ (
npm install -g pnpm) - Convex account (free at convex.dev)
git clone https://github.com/opencom-org/opencom.git
cd opencom
./scripts/setup.sh
Or manually:
pnpm install
cd packages/convex && npx convex dev
pnpm dev # All apps in parallel
pnpm dev:web # Web dashboard (localhost:3000)
pnpm dev:widget # Widget dev server (localhost:5173)
pnpm dev:convex # Convex backend
pnpm dev:mobile # Expo mobile app
pnpm dev:landing # Landing page (localhost:3001)
opencom/
├── apps/
│ ├── web/ # Next.js admin dashboard (agents/admins)
│ ├── mobile/ # Expo admin app (iOS/Android)
│ ├── widget/ # Embeddable chat widget (Vite, IIFE bundle)
│ └── landing/ # Marketing site (Next.js)
├── packages/
│ ├── convex/ # Convex backend (schema, queries, mutations, HTTP routes)
│ ├── types/ # Shared TypeScript types
│ ├── ui/ # Shared React components (Shadcn)
│ ├── sdk-core/ # Shared SDK logic (sessions, events, conversations)
│ ├── react-native-sdk/ # React Native SDK for customer apps
│ ├── ios-sdk/ # Native iOS SDK (Swift)
│ └── android-sdk/ # Native Android SDK (Kotlin)
├── scripts/ # Build, deploy, security, and utility scripts
├── security/ # CI gate configuration (allowlists, budgets)
└── docs/ # Project documentation
- Package manager: Always use
pnpm, nevernpmoryarn. - Formatting: Prettier handles formatting. Run
pnpm formatbefore committing. - Linting: ESLint configured per-package. Run
pnpm lint. - TypeScript: Strict mode. No
anywithout documented justification. - No comments in code unless the logic is non-obvious.
- All queries and mutations live in
packages/convex/convex/. - Use Convex indexes for all high-traffic lookups (avoid table scans).
- Use
requirePermission()orhasPermission()for auth checks. - Visitor endpoints require
sessionTokenvalidated viaresolveVisitorFromSession(). - System/bot actions use
internalMutationto bypass external auth. - Use
v.any()sparingly and document insecurity/convex-v-any-arg-exceptions.json. - Follow
docs/convex-type-safety-playbook.mdfor all new Convex boundaries. - Default backend-to-backend calls to generated
api/internalrefs. - If a call site hits
TS2589, keep the workaround local:- shallow
ctx.runQuery/ctx.runMutation/ctx.runAction/runAfterhelper first - fixed typed
makeFunctionReference("module:function")only if the generated ref still fails
- shallow
- Do not add new generic
get*Ref(name: string)factories or broadunsafeApi/unsafeInternalaliases.
- Next.js App Router.
- Tailwind CSS + Shadcn UI components from
@opencom/ui. - React context for auth (
AuthContext) and backend connection (BackendContext). - Use local Convex wrapper hooks and adapters for data fetching.
- Do not import
convex/reactdirectly into feature/runtime UI modules.
- Vite-built IIFE bundle. Target: <50KB gzipped.
- No external dependencies beyond Convex client.
- All visitor calls thread
sessionToken. - Use
apps/widget/src/lib/convex/hooks.tsplus feature-local wrappers instead of directconvex/reactimports in runtime files.
- Expo / React Native.
- Same auth patterns as web (Convex Auth + BackendContext).
- New mobile Convex usage should follow the same local-wrapper pattern as web/widget instead of adding new direct screen/context-level hook usage.
Run focused checks first for touched surfaces, then broaden as needed.
pnpm lint
pnpm typecheck
pnpm test:convex
pnpm test:unit
pnpm --filter @opencom/convex typecheck
pnpm --filter @opencom/convex test -- --run tests/<file>.test.ts
pnpm --filter @opencom/web typecheck
pnpm --filter @opencom/web test
pnpm --filter @opencom/widget typecheck
pnpm --filter @opencom/widget test
Build widget assets first, then run Playwright:
bash scripts/build-widget-for-tests.sh
pnpm playwright test apps/web/e2e/<spec>.ts --project=chromium
pnpm security:convex-auth-guard
pnpm security:convex-any-args-gate
pnpm security:secret-scan
pnpm security:headers-check
Before pushing any branch, run pnpm security:secret-scan locally at minimum.
If you need to allowlist a non-secret false positive, add a narrowly scoped entry in
security/secret-scan-exceptions.json with explicit owner, reason, and expiry date.
For workflow changes, pin third-party GitHub Actions to immutable commit SHAs and update adjacent traceability comments when changing pins.
Test against a dedicated Convex deployment. Use the test helpers:
import { describe, it, expect, beforeAll, afterAll } from "vitest";
describe("myFeature", () => {
let client: ConvexClient;
let testWorkspaceId: Id<"workspaces">;
beforeAll(async () => {
client = new ConvexClient(process.env.CONVEX_URL!);
const workspace = await client.mutation(api.testing.helpers.createTestWorkspace, {});
testWorkspaceId = workspace.workspaceId;
});
afterAll(async () => {
if (testWorkspaceId) {
await client.mutation(api.testing.helpers.cleanupTestData, {
workspaceId: testWorkspaceId,
});
}
await client.close();
});
it("should do something", async () => {
// test code
});
});
Available helpers: createTestWorkspace, createTestUser, createTestVisitor, createTestSessionToken, createTestConversation, createTestMessage, cleanupTestData.
import { render, screen } from "@testing-library/react";
describe("MyComponent", () => {
it("renders correctly", () => {
render(<MyComponent />);
expect(screen.getByText("Hello")).toBeInTheDocument();
});
});
import { test, expect } from "@playwright/test";
test("should work", async ({ page }) => {
await page.goto("/");
await expect(page.getByRole("heading")).toBeVisible();
});
- Read and agree to the Contributor License Agreement before opening a pull request.
- Add this line to your PR description:
I have read and agree to the CLA. - Keep PRs focused and scoped to one logical change.
- Add or update tests for behavioral changes.
- Never commit secrets or environment-specific credentials.
- Update docs when command/env/workflow behavior changes.
- Run
pnpm lint && pnpm typecheckbefore pushing.
For changes affecting auth, origin validation, webhooks, CORS, or data access controls:
- Include explicit negative-path tests (unauthorized, cross-workspace, expired tokens).
- Describe threat model assumptions in PR notes.
- Prefer fail-closed behavior.
- Run all security gates before requesting review.
- Update
docs/security.mdif authorization model changes.