Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 66 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,75 @@
# Contributing to Fluidd

Fluidd exists as an independent client of Moonraker, and by extension - Klipper.
Fluidd is built on VueJS, using TypeScript.
Fluidd is an independent web client for [Klipper](https://github.com/Klipper3d/klipper)
(via [Moonraker](https://github.com/Arksine/moonraker)), built with Vue 2.7 and TypeScript.

- Source should always pass the linting rules defined, with no warnings or type errors.
- A clean develop is preferred. This means squashing, and rebasing your feature branches prior to merge.
- PR's should off a branch other than develop or master.
- Commit messages should follow the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standard, and should have a Signed-off-by line, for example;
Contributions of all kinds are welcome — bug reports, feature requests, code, and
translations. This document covers the process and rules. For setup instructions and a
tour of the codebase, see the
[Development guide](https://docs.fluidd.xyz/development/).

```sh
feat: My feature.
## Before you start

Some description.
- Read the [Development guide](https://docs.fluidd.xyz/development/) — it covers the
Dev Container, running Fluidd locally, and a quick architecture overview.
- After cloning, run `npm ci && npm run bootstrap` to install dependencies and set up
the Git hooks that pre-validate your commits.

Signed-off-by: Your Name <your email address>
## Branching and pull requests

- Create your work on a feature branch from `develop` — for example,
`feat/my-feature` branched from `develop`. Do not open pull requests from
`develop` or `master` directly.
- **Pull request titles must follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)**.
This is enforced by CI.
Comment thread
pedrolamas marked this conversation as resolved.
- Accepted pull requests are squashed and rebased onto `develop` when merged.

## Commits

- Use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for every
commit message. Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`,
`test`, `build`, `ci`, `chore`, `revert`, `types`, `i18n`.
- The commit subject must be **50 characters or fewer** — enforced by the
`commit-msg` Git hook.
- Every commit must include a `Signed-off-by` line. The easiest way is to commit with
`git commit -s`. Signing off acknowledges the
[Developer Certificate of Origin](./developer-certificate-of-origin) and must
contain your real name and a current email address. Example:

```text
feat: my feature

Some description of what changed and why.

Signed-off-by: Your Name <your@email>
```

- By signing off on commits, you acknowledge that you agree to the [developer certificate of origin](/developer-certificate-of-origin).
This must contain your real name and a current email address.
## Code quality

Source must pass linting and type-checking with **zero warnings and zero type errors**.
Before pushing, run:

```bash
npm run lint
npm run type-check
npm run test
```

CI runs the same checks (plus `npm run circular-check` and a production build) on
every pull request.

## Translations

Translations are managed via [Weblate](https://hosted.weblate.org/engage/fluidd/) — do
not edit non-English files in `src/locales/` directly. New strings should be added to
`src/locales/en.yaml`; Weblate handles the rest. See the
[Localization section](https://docs.fluidd.xyz/development/#localization) of the
Development guide for more.

## A note on `CLAUDE.md`

After cloning the repo and running `npm install`, we recommend running `npm run bootstrap` to install a couple of git hooks that will pre-validate all new commits.
The `CLAUDE.md` file in the repository root is an exhaustive reference written for AI
coding assistants (Claude Code, Cursor, and similar tools). It documents architecture,
patterns, and gotchas in detail. Humans are welcome to read it as a deeper second
source, but the canonical onboarding doc for human contributors is the
[Development guide](https://docs.fluidd.xyz/development/).
119 changes: 118 additions & 1 deletion docs/docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,123 @@ Contributions are welcome! Please review the
[CONTRIBUTING.md](https://github.com/fluidd-core/fluidd/blob/develop/CONTRIBUTING.md)
file before submitting a pull request.

## Architecture overview

This section is aimed at developers comfortable with Vue and TypeScript who want a
quick map of the codebase. For an exhaustive reference, see the `CLAUDE.md` file at
the repository root — it was written for AI coding assistants but works as a deep
second source for humans too.

### Stack

- **Vue 2.7** with [Vuetify 2](https://v2.vuetifyjs.com/) for UI components
- **TypeScript** throughout, with class-style components via
[`vue-property-decorator`](https://github.com/kaorun343/vue-property-decorator)
- **Vuex** for state management — namespaced modules mirror Klipper and Moonraker
domains
- **[Vite](https://vitejs.dev/) 8** as the build tool and dev server
- **[Vitest](https://vitest.dev/) 4** with `jsdom` for unit tests
- **Node.js 24** — pinned in `.node-version` (engines: `^22.12.0 || ^24`)

### How it talks to Klipper

Fluidd does not talk to Klipper directly. Instead, the browser keeps a single
WebSocket connection open to Moonraker, which in turn talks to Klipper:

```text
Browser ⇄ WebSocket (JSON-RPC) ⇄ Moonraker ⇄ Klipper
```

All printer commands and live state updates flow through that single socket. The
client lives in `src/api/socketActions.ts` — for printer control and state, call
its methods rather than making direct HTTP requests.

A few features still use HTTP: file upload and download (via `axios` for progress
reporting — `fetch` cannot report upload progress; see `src/mixins/files.ts`),
camera WebRTC signalling, and the initial `config.json` fetch at startup.

### Repository layout

```text
src/
├── api/ WebSocket JSON-RPC client (socketActions.ts)
├── components/
│ ├── common/ Shared dialogs and status components (auto-imported)
│ ├── layout/ App shell: AppBar, AppDrawer, etc. (auto-imported)
│ ├── ui/ Reusable widgets: AppBtn, AppDialog, etc. (auto-imported)
│ ├── settings/ Settings page components
│ └── widgets/ Feature widgets — one folder per feature
├── views/ Page components, lazy-loaded by the router
├── store/ Vuex modules — one per Klipper/Moonraker domain
├── mixins/ Shared component logic (StateMixin, FilesMixin, ...)
├── plugins/ Vue plugins (i18n, socketClient, vuetify, filters)
├── router/ Vue Router (hash mode)
├── locales/ i18n YAML files (managed via Weblate)
├── scss/ Global styles and Vuetify variable overrides
├── util/ Helper functions
├── workers/ Web Workers (G-code parser, MJPEG stream, Monaco language servers)
├── typings/ Global TypeScript declarations (Klipper, Moonraker namespaces)
└── types/ UI-specific TypeScript types
```

### Patterns you'll meet immediately

**Class-style components.** Every component uses decorators — no Options API or
Composition API. Components that need printer state extend a mixin via `Mixins()`:

```typescript
@Component({ components: { /* ... */ } })
export default class PrinterWidget extends Mixins(StateMixin) {
@Prop({ type: String, required: true })
readonly label!: string

get klippyReady (): boolean {
return this.$typedGetters['printer/getKlippyReady']
}
}
```

**Vuex modules** live in `src/store/<name>/` with a standard layout
(`index.ts`, `state.ts`, `getters.ts`, `mutations.ts`, `actions.ts`, `types.ts`).
Use `$typedState` and `$typedGetters` for type-safe access from components.

**WebSocket calls** go through `SocketActions` methods. Pass a `wait` parameter
(constants in `src/globals.ts`) to drive UI loading state — for example,
`wait: Waits.onPrintPause`.

**Auto-imported components.** Anything under `src/components/common`, `layout`, or
`ui` is registered automatically by `unplugin-vue-components` — no manual import
needed. The generated `components.d.ts` at the repo root is regenerated on every
build; do not edit it by hand.

**Cross-component messaging.** Use the Vuex store for shared state, or the
`EventBus` (`src/eventBus.ts`) for ephemeral events such as flash messages.

**Logging.** Use `consola`, not `console.log` (configured in `src/setupConsola.ts`).

### Where to add things

- **A new widget** → create a folder in `src/components/widgets/<name>/` and import
the component where it's used.
- **A new route** → add a lazy import to `src/router/index.ts` and create the page
in `src/views/<Name>.vue`.
- **New store data** → add a module under `src/store/<name>/` with the six
standard files (including the module's `index.ts`), register it in
`src/store/index.ts`, and update `src/store/types.ts` so `RootModules`,
`RootState`, and `RootGetters` pick it up.
- **A new translation key** → edit `src/locales/en.yaml`. Weblate handles the
other languages — do not edit them directly.
- **A new icon** → add an MDI mapping to the `Icons` object in `src/globals.ts`,
then use it as `<v-icon>{{ $globals.Icons.myIcon }}</v-icon>`.

### Going deeper

The repository's `CLAUDE.md` file is an exhaustive reference originally written
for AI coding assistants. It covers topics that are out of scope for this quick
orientation — the auth state machine and token-refresh policy, the full list of
build-toolchain gotchas, every Vuex module, and more. If you've outgrown this
overview, that's the next stop.

## Dev Container in Visual Studio Code

Fluidd includes a Dev Container configuration to easily open with Visual Studio Code
Expand Down Expand Up @@ -82,7 +199,7 @@ npm run test

Follow the instructions from [Python](https://www.python.org/) to install Python 3.

### Install dependencies
### Install Python dependencies

```bash
cd .../path/to/fluidd/docs
Expand Down