doxa-maps/documentation/HOWTO-join-the-table.md
Doxa Maps 1ca78d6d5d A laptop that follows the table says when it needs credentials, and the last main defaults say development
The joining page, DEPLOY and the laptop sync default moved to development in the
commit before this one. This finishes the move and closes what a fresh clone's
friend test found.

- landing-preconditions diffs against origin/development when no landing branch
  is exported, instead of main.
- CLOUD-DEVELOPMENT-ENVIRONMENT, the plugin-designer skill (SKILL.md, workflow,
  glossary) and the shared dev server's notes land on and follow development;
  the skill says never to push to main.
- The sync fetches with the laptop's own credentials. git runs with prompts off,
  so on a clone with no credential helper it failed every interval with a bare
  "fetch-failed / remote: Unauthorized", which read as a broken server. That case
  is now its own state, needs-credentials: the log (once, not every tick) and
  /api/dev-sync say "dev-sync needs git credentials for <remote>". The joining
  page and .env.example say so, and that a fresh clone starts on main and must
  switch to development before the sync can fast-forward it.

Measured in scratch repos: the private remote with no helper gives
needs-credentials and one warning over two ticks; a local remote with no
DX_SYNC_BRANCH follows development and fast-forwards; a missing remote stays
fetch-failed.
2026-09-29 00:59:14 +00:00

216 lines
9.7 KiB
Markdown

# How to join the table
You want to build a map. Someone told you there is a repo, a dev server, and a thing called PocketBase, and
now you are staring at three of them wondering which one you are supposed to touch.
Short answer: **you work on your laptop, you land your work on `development`, and a shared server shows
everyone what landed. `main` is production:** it moves only when a maintainer publishes, and it is what the
public sites and every partner embed load. That is the whole shape. The rest of this page is what each of
those three is for, and the five commands you actually type.
> **This page is about working alongside other people.** If you want to know how to build a plugin itself —
> the files, the build, getting it live — read
> [develop-a-plugin-and-see-it-live.md](./develop-a-plugin-and-see-it-live.md) first and come back here when
> you are ready to share your work.
---
## The three places
### 1. Your laptop — the workshop
This is where you build. Everything is local and fast, and nothing you do here can affect anyone else.
```bash
bun install
bun run dev
```
That is the whole setup. **Nothing to configure**, no server to reach, no Docker. You get the Plugin
Studio, dictation, hot reload on your own edits, and a local database with your own test data. Break it,
reset it, fill it with nonsense — it is yours.
If your coding agent runs on a server rather than on your laptop, there is a second way to work —
see [CLOUD-DEVELOPMENT-ENVIRONMENT.md](./CLOUD-DEVELOPMENT-ENVIRONMENT.md). Most people do not need it.
### 2. `development` — the table
When your work is ready, it goes to `development`. That is the one branch the whole team lands on, all day.
A shared dev server follows it and reloads about every 15 seconds, so the team sees each other's work
without anyone sending anyone a zip file. You do not edit on that server. You never need to log into it to
do your job.
### 3. `main` — production
`main` is what the public sees: the public build (`/cdn`), the websites that embed the maps, and every
partner's copy-paste snippet all load it. **You never push to `main`.** A maintainer publishes by merging
`development` into it once the team's work is checked, and the public build follows within a few minutes.
> **The rule that makes this work:** one plugin folder per person. You edit `plugin-designs/<your-plugin>/`
> and nobody else does. Everything below depends on that.
---
## Getting your work onto the table
Three commands, in this order, every time:
```bash
git add -A && git commit -m "what you changed"
git pull --rebase origin development
git push origin HEAD:development
```
If the push is rejected, someone landed first. Run the middle command again and push again. That is not an
error — it is the normal case, and it is worth knowing how normal.
**We measured it.** In a ten-writer stress test at a far faster edit rate than a human works at:
| | |
|---|---|
| pushes rejected, then retried | **95%** |
| merge conflicts | **0** |
| retries needed per edit | 1.1 average, 3 at worst |
Nearly every push got rejected. **Not one caused a conflict.** That is the one-folder-each rule paying off:
you are all pushing to the same branch, so you collide on *who goes first* — but never on the same lines of
code, because you are never in the same file. A rejected push costs you one extra command. It does not cost
you an afternoon untangling someone else's work.
If you *do* hit a real conflict, it means two people edited one file. Stop and talk to the other person;
that is a coordination problem, not a git problem.
---
## Seeing your teammates' work on your laptop (optional)
By default your laptop only reloads on *your* edits. If you want teammates' landed work to arrive
automatically while `bun run dev` is running, copy `.env.example` to `.env.local` at the repo root and set:
```
DX_SYNC_REMOTE=origin
```
That is the only line you need. `.env.local` is never committed, so it stays yours.
Two things it needs from you, once:
- **Be on `development`.** It only fast-forwards the branch it follows, and a fresh clone starts on `main`,
so run `git switch development` (or clone with `-b development`).
- **Read access to the repo.** It fetches with your laptop's own git credentials: a credential helper, or an
SSH remote your key can read. Without them nothing is pulled, and the log (and `/api/dev-sync`) says
`dev-sync needs git credentials for <remote>` rather than failing quietly.
> **Either a remote name or a full repo URL works.** `origin` is what almost everyone wants. A URL —
> `https://…/your-repo.git` — works too and saves you a `git remote add`; if the repo is private it uses
> the git credentials your laptop already has. Leave it unset and the whole feature is off.
>
> If you do put a token in the URL (`https://user:token@…`), it is never written to the log or shown at
> `/api/dev-sync`.
Two optional dials, if you want them:
| | what it does | default |
|---|---|---|
| `DX_SYNC_BRANCH` | which branch to follow | `development` (the table) |
| `DX_SYNC_INTERVAL` | seconds between checks | `5` (minimum 2) |
**It only pulls when it is completely safe to.** All three must be true: you are on that branch, you have no
unsaved edits, and you have no local commits. If any one of them is not, it does not touch your files —
it tells you instead, in the dev server log:
```
development is 3 commits ahead … pull when ready
```
So it cannot surprise you mid-thought. You can also check that any time at `/api/dev-sync`.
---
## The database, and the one thing that surprises people
There are three databases. You work against one of the first two — never the third.
| Where | What is in it | Who touches it |
|---|---|---|
| Your laptop | your own sandbox data | you, freely — **this is the default** |
| The team's shared one | the team's shared test data | the team — opt-in, see below |
| Production | what the public sees | nobody directly |
**You never publish a database.** Not yours, not anyone's. What travels is the *shape* — the tables and
fields — as migration files committed to the repo, in `backend/pocketbase/pb_migrations/`.
So adding a field is a normal change: you edit, you commit the migration, you push it like any other file,
and it goes through review with everything else. A server applies new migrations when it restarts.
**Make schema on your laptop, never in the shared server's database screen.** PocketBase writes a migration
file for every change made in its admin screen. On your laptop that file lands in your checkout, and you
commit it. On the shared server it lands in a copy of the repo that is thrown away at the next restart, so
the table's database and the repo drift apart.
This is deliberate. A database rule that opens something to the public arrives as **a commit someone can
read** rather than as a setting somebody clicked at midnight. If you have ever inherited a system where the
live config did not match the repo, you already know why.
### Which one your laptop talks to
**By default, your own.** You do not configure anything. The first time you run `bun run dev` it starts a
database on your laptop, keeps its data in `.pb/`, and gives you an admin screen at `/api/pb/_/`. A fresh
clone plus `bun run dev` is the whole setup — no remote server, no Docker, nothing to sign into.
If your team wants everyone working against the *same* test data instead, that is opt-in. Add one line to
`.env.local`:
```
DX_PB_URL=https://<your team's dev server>/pb
```
You sign in with the same team account you use for everything else — there is no separate password. Ask
whoever set up your team for the address. Leave the line out and you stay on your own local one, which is
the right place to be while you are finding your feet.
The only other thing here is `DX_PB_PORT`, which you set only if the log says port 8090 is already in use.
> **New collections start locked.** Your plugin's data is not readable until a migration opens it —
> deliberately, so nothing is public by accident. That migration is a commit like any other.
---
## One more thing to set
Copy `.env.example` to `.env.local`. **Every line in it is optional** — empty means the default, which is
the all-local setup described above. You can start with none of them filled in.
The one you will probably want is a Mapbox token, which is the single credential you have to ask the team
for:
```
VITE_MAPBOX_TOKEN=<ask the team>
```
Leave it empty and the Mapbox-backed maps will not draw; you can also work with the keyless MapLibre
provider instead.
---
## The five things to remember
1. **Build on your laptop.** It is fast and it is yours.
2. **One plugin folder per person.** This is what keeps ten people out of each other's way.
3. **`pull --rebase`, then push to `development`.** A rejected push is normal — 95% of them were, and none
became conflicts. Never push to `main`: that is production.
4. **The shared server is for looking, not editing.**
5. **Schema is a commit, never a click.** You never publish a database.
---
## When something is wrong
- **"Your push was rejected"** — normal. `git pull --rebase origin development`, push again.
- **A real merge conflict** — two people edited one file. Talk to them; the one-folder rule slipped.
- **Your change is not on the shared server** — it reloads about every 15 seconds, not instantly. Check your
push actually landed: `git log origin/development -1`.
- **The shared server shows an old version of your plugin** — you are probably looking at what is on
`development`, not what is on your laptop. Those are different on purpose.
- **The public site does not show your change** — it shows `main` (production), which moves only when a
maintainer publishes. After a publish, a browser can keep the old maps for up to 5 minutes.