hoppscotch-backend-git/README.md
tlemesle 0cc7276c23 Auto-generate secrets in per-user state directory
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 16:24:27 +02:00

168 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# hoppscotch-backend-git
A self-hosted Hoppscotch-compatible backend that syncs workspace data to a Git repository.
Hoppscotchs official backend keeps collections, environments, and related data in a database. Bruno keeps them as files in Git, but collaboration is async (pull / push / PR) and several team-oriented Git features sit behind a paid plan. This project aims at the gap between those models: **live multi-client sync** with **Git as the durable, reviewable source of truth**.
> **Status:** early / work in progress. Phase A (Git store + REST + CLI) and Phase B (auth + personal GraphQL) are implemented. Upstream Hoppscotch is vendored as a Git submodule at [`hoppscotch-upstream`](./hoppscotch-upstream) ([hoppscotch/hoppscotch](https://github.com/hoppscotch/hoppscotch)).
## Why
Teams often want:
1. A shared API client workspace that updates for everyone without manual export/import
2. Collections and environments versioned in Git (diff, review, branch, audit)
3. Self-hosting without a proprietary cloud sync service or per-seat Git UI fees
Exporting Hoppscotch collections into a repo works for occasional backup, not continuous team sync. Bruno solves Git-native storage well, but deliberately has no live sync and gates private remotes / full in-app Git workflows on paid tiers.
`hoppscotch-backend-git` keeps a Hoppscotch-style backend API while persisting (and syncing) data to Git.
## How collaboration works
Each teammate runs **this backend on their own machine** and points Hoppscotch (Desktop / CLI) at `localhost`. Identity comes from the local OS account. The **shared Git workspace repository** is what syncs collections and environments between people — not a central Hoppscotch server.
```text
User A machine User B machine
┌─────────────────────┐ ┌─────────────────────┐
│ Hoppscotch Desktop │ │ Hoppscotch Desktop │
│ │ │ │ │ │
│ hoppscotch-backend │ │ hoppscotch-backend │
│ (local :3200) │ │ (local :3200) │
│ │ │ │ │ │
│ GIT_REPO_PATH ────────── push/pull ──────── GIT_REPO_PATH │
└─────────────────────┘ ▲ └─────────────────────┘
shared Git remote
(collections / environments)
```
Local-only state (PATs, auto-generated secrets, signing keys, `meta.json`) lives under a per-user state directory on each machine and is **not** part of the workspace Git repo:
| OS | Default state directory |
|-------|------------------------------------------------------------|
| macOS | `~/Library/Application Support/hoppscotch-backend-git/` |
| Linux | `${XDG_DATA_HOME:-~/.local/share}/hoppscotch-backend-git/` |
Override with `HOPP_STATE_DIR` if needed.
## Feature comparison
| Feature | Hoppscotch (cloud / self-host) | Bruno | Hoppscotch + hoppscotch-backend-git |
|------------------------------------------|:-------------------------------------------:|:----------------------------------------------:|:-------------------------------------:|
| Live multi-client sync | :white_check_mark: | :x: | :white_check_mark: (goal) |
| Git as primary storage | :x: (database) | :white_check_mark: | :white_check_mark: (goal) |
| Reviewable diffs / PRs for collections | :warning: via export only | :white_check_mark: | :white_check_mark: (goal) |
| Offline-first | :warning: partial (local / desktop) | :white_check_mark: | :white_check_mark: with local backend |
| Collaboration model | Shared backend | Git (async) | Local backends + shared Git workspace |
| Private Git remotes without paid client | N/A | :x: (Pro+ for in-app private remotes) | :white_check_mark: (your Git hosting) |
| In-app commit / push / branch / merge UI | N/A | :x: (Pro+ for advanced Git UI) | :white_check_mark: (goal) |
| Self-hosted, you control the data plane | :white_check_mark: (Community / Enterprise) | :white_check_mark: (local files) | :white_check_mark: (goal) |
Notes:
- Brunos collaboration is **Git collaboration**, not realtime shared sessions. That is intentional; see [Brunos pricing](https://www.usebruno.com/pricing) and product FAQ.
- Official Hoppscotch self-hosting stores data in a database, not a Git repo.
- Rows marked “(goal)” describe the intended behavior of this project and are not all implemented yet.
## Architecture (intended)
```text
Hoppscotch clients (web / desktop / CLI) on each user's machine
hoppscotch-backend-git (local) ←── Hoppscotch-compatible API
├── serve that user's Desktop / CLI session
└── commit / push / pull workspace state to the shared Git repository
```
Git is the team sync plane and review surface. Each local backend is what that user's clients talk to.
## Repository layout
| Path | Role |
|-------------------------------------------------|------------------------------------------------|
| [`hoppscotch-upstream/`](./hoppscotch-upstream) | Git submodule of official Hoppscotch |
| [`src/`](./src) | Bun + TypeScript backend (REST, auth, GraphQL) |
| [`tests/`](./tests) | axios + Hoppscotch CLI integration tests |
| [`fixtures/`](./fixtures) | Sample collection / environment helpers |
## Development
Clone with submodules:
```bash
git clone --recurse-submodules ssh://git@git.kaki87.net:3021/KaKi87/hoppscotch-backend-git.git
cd hoppscotch-backend-git
```
If you already cloned without submodules:
```bash
git submodule update --init --recursive
```
Install and run:
```bash
bun install
bun run prepare:webapp # extracts official selfhost-web UI + points it at this backend
export GIT_REPO_PATH=./.data/workspace-git # clone of the shared workspace repo
bun run start
```
On first start, JWT / webapp signing secrets are generated under the state directory (`secrets.json`). Optional env overrides still work for tests and special setups.
Type-check and test:
```bash
bun run typecheck
bun test
```
### Configuration
| Variable | Required | Description |
|----------------------------------|----------|---------------------------------------------------------------------------------------------------------------------|
| `GIT_REPO_PATH` | yes | Local checkout of the **shared** Git repo storing `collections/` and `environments/` |
| `HOPP_STATE_DIR` | no | Local state root for `meta.json`, `secrets.json`, `signing.key` (see defaults above) |
| `META_PATH` | no | Override path for users / PATs (default `$HOPP_STATE_DIR/meta.json`) |
| `JWT_SECRET` | no | Override JWT/PAT pepper (default: auto-generated in `$HOPP_STATE_DIR/secrets.json`) |
| `PORT` | no | Listen port (default `3200`) |
| `GIT_AUTO_PUSH` | no | `true` to `git push` after each commit (default `false`) |
| `WEBAPP_FRONTEND_PATH` | no | Frontend files bundled for Hoppscotch Desktop (default `./webapp-frontend`) |
| `WEBAPP_SERVER_SIGNING_SECRET` | no | Override ed25519 seed for desktop bundle signatures (default: auto-generated in `secrets.json`) |
| `WEBAPP_SERVER_SIGNING_KEY_FILE` | no | Override signing key path (default `$HOPP_STATE_DIR/signing.key`) |
| `DEV_USER_OVERRIDE` | no | Dev-only JSON `{ "email", "displayName", "uid"? }` to override local identity (ignored/rejected in compiled builds) |
Each user runs their own server. Authentication is the local macOS account via `dscl` (`RecordName`, `EMailAddress`, `RealName`), unless `DEV_USER_OVERRIDE` is set. Hoppscotch-compatible `/v1/auth/*` routes remain as stubs (empty providers, desktop token exchange).
### Git workspace layout
```text
$GIT_REPO_PATH/
collections/<id>.json # Hoppscotch HoppCollection (v12)
environments/<id>.json # Hoppscotch Environment (v2)
```
### Useful endpoints
- `GET /health`
- Desktop instance: `GET /api/v1/key`, `/api/v1/manifest`, `/api/v1/bundle`
- REST CRUD: `/v1/collections`, `/v1/environments`
- CLI: `GET /v1/access-tokens/collection/:id`, `GET /v1/access-tokens/environment/:id` (Bearer `pat-…`)
- Auth: `/v1/auth/providers`, `/signin`, `/verify`, `/refresh`, `/logout`, `/verify-token`
- GraphQL: `POST /graphql` (personal workspace ops + subscriptions)
Example CLI run against a local server:
```bash
hopp test <collection-id> --token pat-… --server http://127.0.0.1:3200
```
## License
This project is licensed under the [MIT License](LICENSE), the same as [Hoppscotch](https://github.com/hoppscotch/hoppscotch/blob/main/LICENSE).
Upstream Hoppscotch code under `hoppscotch-upstream/` retains its own MIT license and copyright.