Skip to content

Contributing

Getting a dev environment

You need Node.js 20.19 or newer (the project is developed on 24) and pnpm. A Rust toolchain (rustup) is only needed if you work on the desktop or mobile shells.

pnpm install
pnpm dev        # API on :3000 + web app on :5173, with hot reload
pnpm seed       # optional: demo courses and study fixtures

If you use Nix, run nix develop for the whole toolchain, pinned and matching the CI: Node, pnpm, Rust, and on Linux the Tauri webkit2gtk libraries. With direnv it activates on its own through the checked-in .envrc. See flake.nix.

For the desktop shell:

cd apps/shell
pnpm tauri dev

Repo layout

apps/web        Svelte 5 SPA, where all the study features live
apps/api        NestJS API: auth, files, AI proxy, sync log
apps/shell      Tauri shell (desktop and mobile) with the LAN sync plumbing (Rust)
packages/ai-core        provider-agnostic AI calls
packages/design-system  UI components and tokens
docs            this documentation (mkdocs)

Read the architecture page before touching the data layer. The local-first model, with the CRDT documents as the source of truth and the server as an optional peer, shapes almost every design decision here, and the "where to start reading" table on that page maps the important files.

Quality gates

All of the following must pass before a change lands. CI runs the same set.

pnpm lint                              # eslint across the monorepo
pnpm --filter @synapse/web check       # svelte-check + i18n compile
pnpm --filter @synapse/web test        # vitest (unit)
pnpm --filter @synapse/api test        # jest (unit + integration)
pnpm --filter @synapse/web test:e2e    # playwright, seeds its own db
cd apps/shell/src-tauri && cargo test

The e2e suite boots the API on a fresh, migrated and seeded database on every run, and drives the app through its real repositories rather than test-only routes. The accessibility spec runs axe WCAG scans on every main page.

Conventions

  • Commits follow Conventional Commits: type(scope): summary, where type is one of feat, fix, docs, style, refactor, perf, test, build, ci, chore or revert, and scope is optional (web, api, shell, design-system). Keep the summary short, lowercase and imperative.

  • User-facing strings go through Paraglide (inlang). The catalogs are apps/web/messages/en.json, fr.json and pt-BR.json; add every new message to all three. Paraglide compiles them into typed functions under src/paraglide/ (this runs automatically with check, test and the dev server), and components call them as m.your_message_key(). A key missing from a locale fails the compile, so forgetting a translation is caught early.

  • E2E selectors are role-based (getByRole) rather than CSS classes.
  • The web app never reads study data over HTTP. Pages call the repositories in apps/web/src/lib/data/repos/. If a feature seems to need a new server endpoint, check the architecture first, because it usually needs a document field instead.
  • Errors surface as neverthrow results on the client, and unhandled rejections are treated as bugs.
  • Documentation lives in docs/. When you change behaviour, update the page that covers it. Install the tooling once with pip install -r docs/requirements.txt, then preview the site with pnpm docs:serve (and build it with pnpm docs:build). These wrap mkdocs and first build the in-browser demo into docs/try/app, so the "Try it" page works; a bare mkdocs serve skips that step and the demo will 404.

AI assistance

AI tools were used to help build this project, and they are welcome for contributions too, under the same discipline the codebase was built with: plan first, then generate, then review. Concretely, AI here automates boilerplate and test scaffolding after a carefully crafted plan, and every produced result is read, questioned and tested by a person before it lands, with quality, security and accessibility in mind. The decisions that shape the project, such as the data model, the security model, the dependencies and the UX, are made by humans. Nothing is merged blindly.