# Contributing to Beaver Notes First off, thank you for considering contributing to Beaver Notes. It's people like you that make Beaver Notes such a great tool. ## Table of Contents - [Code of Conduct](#code-of-conduct) - [Getting Started](#getting-started) - [Prerequisites](#prerequisites) - [Setup](#setup) - [Environment Variables](#environment-variables) - [Project Overview](#project-overview) - [Tech Stack](#tech-stack) - [Architecture](#architecture) - [Key Directories](#key-directories) - [Development Workflow](#development-workflow) - [Running the App](#running-the-app) - [Linting](#linting) - [Pre-commit Hooks](#pre-commit-hooks) - [Making Changes](#making-changes) - [Branching](#branching) - [Commit Messages](#commit-messages) - [Developer Certificate of Origin](#developer-certificate-of-origin) - [AI-Generated Content](#ai-generated-content) - [Pull Requests](#pull-requests) - [Building](#building) - [Desktop](#desktop) - [Mobile](#mobile) - [Beta Builds](#beta-builds) - [Translations](#translations) - [Release Process](#release-process) - [Reporting Issues](#reporting-issues) - [Security](#security) - [License](#license) ## Code of Conduct This project and everyone participating in it is governed by the [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [danielerolli@beavernotes.com](mailto:danielerolli@beavernotes.com). ## Getting Started ### Prerequisites - **Node.js** >= v18.0.0 - **Yarn 1.x** (Classic): `npm install -g yarn` - **Rust toolchain** >= 1.77.2: install via [rustup](https://rustup.rs/) - **Tauri system dependencies**: see the [Tauri v2 prerequisites guide](https://v2.tauri.app/start/prerequisites/) #### Mobile targets (optional) - **iOS:** Xcode 16+, CocoaPods - **Android:** Android Studio, Android NDK, Java 17+ ### Setup ```bash git clone https://github.com/Beaver-Notes/Beaver-Notes.git cd Beaver-Notes yarn install ``` ### Environment Variables Copy the example environment file: ```bash cp .env.development.example .env.development ``` Fill in the values: | Variable | Description | |----------------------|-------------------------------------------------------| | `VITE_DEV_SERVER_URL` | Dev server URL (default: `http://localhost:5173`) | | `PROJECT_ID` | Project identifier for Traduora | | `CLIENT_ID` | Traduora client ID | | `CLIENT_SECRET` | Traduora client secret | ## Project Overview ### Tech Stack | Layer | Technology | |-------|------------| | **Frontend** | Vue 3 + Vite 5 + Pinia + Vue Router (hash mode) | | **Styling** | Tailwind CSS 3, SCSS, tw-colors themes | | **Editor** | tiptap (ProseMirror-based), KaTeX, Mermaid | | **Desktop** | Tauri 2 (Rust backend) | | **Mobile** | Tauri 2 (iOS + Android) | | **Database** | SQLite via rusqlite (Rust side) | | **Sync** | Yjs (CRDT-based collaboration) | | **Linting** | oxlint | ### Architecture Beaver Notes is a Tauri v2 application: - **`src/`**: Vue 3 frontend (the "web" layer) - **`src-tauri/`**: Rust backend (the "native" layer) - The Rust backend handles file system access, encryption, search, updates, and the SQLite database - The frontend communicates with the backend via Tauri's `invoke` command system ### Key Directories ``` src/ components/ -- Vue components (ui/, app/, note/, home/, onboarding/) composable/ -- Vue composables only (see "Composable convention" below) pages/ -- Route page components store/ -- Pinia stores (app, note, folder, label, i18n, passwd) assets/ -- CSS, fonts, images, SVG, translations (locales/) lib/ -- Core libraries (tiptap extensions, Tauri bridge, storage/settings layers, Yjs infra) utils/ -- Pure utility functions (crypto, sync, import/export, share, ui) src-tauri/ src/ -- Rust source (commands/, lib.rs, main.rs, db.rs, etc.) tauri.conf.json -- Tauri configuration Cargo.toml -- Rust dependencies ``` ## Development Workflow ### Running the App ```bash yarn watch ``` This spawns `tauri dev` with proper process tree cleanup. The Vite dev server runs on `http://localhost:5173`. > **Note:** For the first run, `tauri dev` will compile all Rust crates, which can take a few minutes. ### Linting ```bash yarn lint ``` Runs [oxlint](https://oxc.rs/docs/guide/usage/linter.html) with the Vue plugin over all `.js`, `.ts`, and `.vue` files, then `scripts/check-composables.mjs` which enforces the composable convention below. ### Composable convention A **composable** is a `use*` function that uses Vue reactivity (`ref`, `computed`, `watch`, lifecycle hooks, …). The convention is: - **`src/composable/` contains only composables.** Each file must export a `useXxx` function that uses at least one Vue reactivity API. Anything else (pure logic, data access, platform wrappers, Yjs infrastructure) belongs in `src/utils/` or `src/lib/`: - `src/utils/` — pure logic and helpers (no Vue reactivity). - `src/lib/` — platform/backend bindings and app infrastructure (storage, settings, dialogs, Yjs doc/hydration). - **Pinia stores** are the exception: store factories are named `useXxx` but live in `src/store/`, not `src/composable/`. - **Naming.** `use` + PascalCase (`useNoteStore`). One composable per file. Names must read correctly at the call site with no extra context — prefer `resize(to)` over `resize(to, true)`. - **Cohesion.** One concern per composable. If a composable grows past a few hundred lines, split it into focused composables rather than adding branches. A composable should be readable by someone without asking the author what it does. `scripts/check-composables.mjs` fails the build when a file in `src/composable/` is not a composable, and warns when a `use*` function using Vue reactivity is defined outside `src/composable/` (excluding `src/store/`). ### Pre-commit Hooks Pre-commit hooks are managed via Husky and run `lint-staged`: ```bash # .husky/pre-commit runs: yarn lint-staged # Which lints *.js, *.ts, *.vue files with eslint --cache --fix ``` If a commit is rejected due to linting errors, fix the errors and try again. ## Making Changes ### Branching Use descriptive branch names: - `fix/description` for bug fixes - `feat/description` for new features - `refactor/description` for code refactoring - `docs/description` for documentation changes ### Commit Messages We do not enforce a strict convention, but prefer clear, descriptive commit messages written in the imperative mood. For example: - "fix: Fix crash when deleting a folder with locked notes" - "feat: Add search-as-you-type to the home page" ### Developer Certificate of Origin All commits must include a `Signed-off-by` trailer to certify that you have the right to submit the work under the MIT license. This is the [Developer Certificate of Origin](https://developercertificate.org/) (DCO) v1.1. ```bash git commit -s -m "Your commit message" ``` If you forget `-s`, you can amend: ```bash git commit --amend -s --no-edit ``` See [DCO.md](./DCO.md) for the full text. ### AI-Generated Content If you use AI tools (e.g., ChatGPT, Copilot, Claude) to generate or assist with code, you **must** disclose this in your commit or pull request using one of these commit trailers: - `Assisted-by: ` - `Co-authored-by: ` - `Generated-by: ` You remain fully accountable for any AI-generated code. See [AI_POLICY.md](./AI_POLICY.md) for full details. ## Pull Requests 1. **Create an issue** first if the change is non-trivial (bug, feature, refactor). This avoids duplicate work. 2. **Keep PRs focused** each PR should address a single concern. 3. **Ensure linting passes** run `yarn lint` before submitting. 4. **Update translations** if your change adds or modifies user-facing strings. 5. **Include a clear description** what, why, and how. 6. **Checklist in PR template** fill it out when you open the PR. All PRs are reviewed before merging. Maintainers may request changes. ## Building ### Desktop ```bash yarn build # or equivalently: yarn build:desktop ``` Produces platform-specific bundles: - **macOS:** `.dmg` + universal binary - **Linux:** `.AppImage`, `.deb`, `.rpm`, `.tar.gz` - **Windows:** `.exe` (NSIS installer), `.zip` ### Mobile ```bash # iOS - first time only: yarn mobile:init:ios # Run on iOS simulator: yarn dev:ios "iPhone 16" # Build iOS: yarn build:ios # Android - first time only: yarn mobile:init:android # Run on Android emulator/device: yarn dev:android # Build Android: yarn build:android ``` #### iOS - Simulator Boot Order Before running `yarn dev:ios`, the simulator must be booted first: ```bash xcrun simctl boot "iPhone 16e" open -a Simulator # Wait for the home screen to appear, then: yarn dev:ios "iPhone 16e" ``` #### Android - libsodium Pre-build (one-time setup) The `tauri-plugin-stronghold` dependency requires libsodium for Android ARM64. Build it once per machine: ```bash cd /tmp curl -LO https://download.libsodium.org/libsodium/releases/LATEST.tar.gz tar xzf LATEST.tar.gz cd libsodium-stable export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk/$(ls ~/Library/Android/sdk/ndk | tail -1) export NDK_PLATFORM=android-28 ./dist-build/android-armv8-a.sh mkdir -p ~/.libsodium-android cp -r /tmp/libsodium-stable/libsodium-android-armv8-a+crypto/* ~/.libsodium-android/ ``` Then add to your shell profile: ```bash export SODIUM_LIB_DIR="$HOME/.libsodium-android/lib" ``` Reload and build: ```bash cd src-tauri cargo clean --target aarch64-linux-android cd .. yarn build:android ``` > **Note:** `tauri-plugin-stronghold` is planned for deprecation in Tauri v3. The long-term replacement is platform-native backends: `keyring` (desktop) and `keystore` (mobile). ### Beta Builds ```bash yarn dev:beta # Development with beta config yarn build:beta # Build with beta config ``` ## Translations Translations are stored as JSON files in `src/assets/locales/`. | Language | Code | |----------|------| | Arabic | `ar` | | German | `de` | | English | `en` | | Spanish | `es` | | French | `fr` | | Italian | `it` | | Dutch | `nl` | | Portuguese | `pt` | | Russian | `ru` | | Turkish | `tr` | | Ukrainian | `uk` | | Vietnamese | `vi` | | Chinese | `zh` | **To add a new translation:** 1. Create a new JSON file in `src/assets/locales/` using the language code as filename (e.g., `ja.json`). 2. Translate all keys from the English (`en.json`) file. 3. Open a PR with the new locale. **To update existing translations:** - Edit the relevant JSON file directly, or use the utility scripts: ```bash yarn tran-util # Translation utility yarn tran-update # Update translations from source ``` ## Release Process Releases are automated via GitHub Actions. ### Stable Release 1. Bump the version: ```bash node scripts/bump-version.mjs ``` This syncs `package.json`, `Cargo.toml`, and `tauri.conf.json`. 2. Push a tag matching `v[0-9]+.[0-9]+.[0-9]+` (e.g., `v5.0.0`): ```bash git tag v5.0.0 git push origin v5.0.0 ``` The [release.yml](.github/workflows/release.yml) workflow builds for all platforms and creates a draft release. ### Beta Release 1. Bump the version to a beta pre-release: ```bash node scripts/bump-version.mjs ``` 2. Push a tag matching `v*-beta.*` (e.g., `v5.0.0-beta.1`): ```bash git tag v5.0.0-beta.1 git push origin v5.0.0-beta.1 ``` The [release-beta.yml](.github/workflows/release-beta.yml) workflow builds with the beta Tauri config and creates a prerelease. ## Reporting Issues Use the appropriate issue template: - [Bug Report](https://github.com/Beaver-Notes/Beaver-Notes/issues/new?template=bug_report.md) - for crashes, unexpected behavior, etc. - [Feature Request](https://github.com/Beaver-Notes/Beaver-Notes/issues/new?template=feature_request.md) - for new ideas and enhancements - [Question / Help](https://github.com/Beaver-Notes/Beaver-Notes/issues/new?template=ask-a-question-or-get-help.md) - if you need assistance ## Security Found a security vulnerability? **Do not open a public issue.** Email [danielerolli@beavernotes.com](mailto:danielerolli@beavernotes.com) with details. See [SECURITY.md](./SECURITY.md). ## License Beaver Notes is open source software licensed under the [MIT license](./LICENSE).