Contributing
OrangeRails is Apache 2.0 open source. PRs welcome, repo conventions and branch model below so your contribution lands smoothly.
Branch model
Two branches, two URLs. There is no main.
dev ← Lovable + agents + PRs land here; auto-deploys to dev.orangerails.com
prod ← merged from dev when ready; auto-deploys to orangerails.com (live)
Promotion is explicit — a fast-forward merge from dev to prod and a push. Full mental model: Branch flow — dev and prod.
PR conventions
- Open against
devas the base branch (it's the GitHub default — should auto-select). - One commit per logical change is preferred; the maintainer squashes on merge anyway.
- Commit message style:
type(scope): subject— see existinggit log --onelinefor examples. Types we use:feat,fix,chore,docs,ci,copy,refactor,test. - CI must pass before merge (
bun run build, type-check, stress test).
Setting up locally
gh repo clone MorningRevolution/orangerails
cd orangerails
bun install
bun run dev # starts the Vite dev server at localhost:8080
For backend work (edge functions), you'll need a Supabase project. Either:
- Use the hosted dev project (ask a maintainer for read access)
- Run Supabase locally via
supabase start(uses thesupabase/config.tomlin the repo)
Set environment variables in .env:
VITE_SUPABASE_URL=https://gposxxmxenrdvewrprle.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=<your-anon-key>
VITE_SUPABASE_PROJECT_ID=gposxxmxenrdvewrprle
.env.example has the canonical values to copy.
Repo layout
src/
routes/ TanStack Router file-based routes
components/ Reusable UI components
components/landing/ Marketing-page components
hooks/ React hooks
lib/ Pure utilities (encryption, providers fetch, etc.)
integrations/ Supabase client + types
stealth/ Stealth Sync widget (postMessage protocol)
supabase/
functions/ Edge functions (or-providers, or-sync, or-connection-*, etc.)
functions/_shared/ Shared types + adapter framework + sink dispatch
migrations/ Versioned SQL (idempotent guards required)
scripts/
generate-ccxt-manifest.mjs Regenerates _ccxt-manifest.ts from CCXT
stress-test-ccxt.mjs Catches CCXT version drift
prerender-plugin.ts Vite plugin for SEO-friendly static HTML
Adding a feature
Frontend-only
- Branch from
dev:git checkout -b feat/your-feature - Write the code under
src/ - Run
bun run buildto type-check - Open PR against
dev
Backend-only
- Edit edge function under
supabase/functions/<fn>/index.ts - If schema changes, add a migration under
supabase/migrations/<timestamp>_<slug>.sql(use idempotent guards:CREATE TABLE IF NOT EXISTS,DROP POLICY IF EXISTSbefore eachCREATE POLICY, etc.) - Test locally:
supabase functions serve <fn> - Open PR
New source adapter
See the Adapter SDK guide. Short version: implement ProviderAdapter in supabase/functions/_shared/providers/<slug>.ts, register in dispatch.ts, ship.
Code style
- TypeScript everywhere. No
anyunless there's a comment explaining why. - Plain English in user-facing copy. No "rotate", "encrypt", "decrypt", "ciphertext" — say "lock", "open the box", "scrambled bytes" instead.
- No em-dashes in user-facing copy. Commas, periods, parentheses, or restructure.
- No compound-word hyphens in user-facing copy ("customer facing" not "customer-facing"). Hyphens stay in identifiers and slugs.
- ESLint runs in CI but is
continue-on-error: true— fix warnings if you see them but don't let them block.
What we don't accept (yet)
- PRs that break zero-knowledge. The architecture rule is server stores ciphertext only for credentials, transaction details, and Stealth Sync data. PRs that move plaintext server-side will be rejected.
- PRs that add hard dependencies on a non-free service without a self-host fallback.
- PRs that change the public API in breaking ways without a deprecation cycle (additive changes only, per the OpenAPI versioning policy — Phase 1 work).
Discussion
- Feature requests → feedback.orangerails.com (Fider — vote, propose, track)
- Support → support.orangerails.com
- Security issues → [email protected] (PGP key at
/.well-known/security.txtonce Phase 1 ships) - General chat → Telegram + Nostr links in the repo README (Phase 1 work to set up)
License
Apache 2.0. See LICENSE in the repo root. By contributing, you agree your contribution is licensed under Apache 2.0.