168 lines
10 KiB
Markdown
168 lines
10 KiB
Markdown
# hoppscotch-backend-git
|
||
|
||
A self-hosted Hoppscotch-compatible backend that syncs workspace data to a Git repository.
|
||
|
||
Hoppscotch’s 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:
|
||
|
||
- Bruno’s collaboration is **Git collaboration**, not realtime shared sessions. That is intentional; see [Bruno’s 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.
|