doxa-maps/documentation/HOWTO-join-the-table.md
Doxa Maps 3de124209a The joining page's env setup, written from repo's own text
repo answered with the names as they will ship (END-REPO-ENVNAMES) and dx-shepherd caught a path I had
wrongly removed. Both corrected; the doc now states nothing I have not verified.

⚠ MY "THE PATH DOES NOT EXIST" CHECK WAS WRONG, AND WRONG IN AN INSTRUCTIVE WAY. I searched the LAST
COMMIT's file list for pb_migrations and found nothing, then reported the path as unbuilt. `git ls-tree -r
origin/main` shows backend/pocketbase/pb_migrations/.gitkeep — it has been there all along. A file list from
one commit answers "was this touched recently", never "does this exist"; I asked the cheap question and read
it as the expensive one. The real path is restored.

THREE CORRECTIONS FROM repo, each of which would have cost a reader time:
- DX_SYNC_REMOTE is a remote NAME (`origin`), not a URL. My draft said "<the repo URL>", which would have
  failed silently for every joiner who copied it.
- DX_PB_URL IS OUT ENTIRELY. repo was explicit: it points at the shared database, which sits behind the team
  sign-in and does not work from a laptop. Telling a newcomer to set it would have sent them to debug an
  auth wall on their first afternoon. What replaced it is the truth — `bun run dev` downloads and starts a
  local database itself, and there is nothing to configure.
- VITE_MAPBOX_TOKEN is the one credential they must ask for, and my draft never mentioned it. A joiner
  following the old page would have got a working repo and a blank map.

ALSO ADDED, because it is the behaviour that makes the feature safe to recommend: the auto-pull only runs
when you are on that branch, with no unsaved edits and no local commits. Otherwise it does not touch your
files, it says "main is N commits ahead … pull when ready" in the log. That is the difference between a
feature a newcomer trusts and one they turn off after it eats an afternoon's work.

Required set is now stated plainly: DX_SYNC_REMOTE=origin if you want teammates' work to arrive, plus the
Mapbox token. Everything else optional, with its default in a table.
No internal names, re-checked after the rewrite: the only product name left is PocketBase, which a joiner
sees in its own admin UI.
2026-09-27 23:31:54 +00:00

6.5 KiB

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 main, and a shared server shows everyone what landed. 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 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.

bun install
bun run dev

You get the Plugin Studio, 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.

2. main — the truth

When your work is ready, it goes to main. That is the one place everybody agrees on. Nothing is "real" until it is there.

3. The shared dev server — the table

A server watches main and reloads about every 15 seconds. That is where the team sees each other's work without anyone sending anyone a zip file. You do not edit here. You never need to log into it to do your job.

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 main

Three commands, in this order, every time:

git add -A && git commit -m "what you changed"
git pull --rebase origin main
git push origin HEAD:main

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.

DX_SYNC_REMOTE is the remote's NAME, not a URL. For almost everyone that is origin. Leave it unset and the whole feature is off.

Two optional dials, if you want them:

what it does default
DX_SYNC_BRANCH which branch to follow main
DX_SYNC_INTERVAL seconds between checks 15 (minimum 5)

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:

main 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 and you only ever touch one.

Where What is in it Who touches it
Your laptop your own sandbox data you, freely
The shared dev server the team's shared test data the team
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. When the person who publishes runs the publish step, the migrations apply.

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.

You do not have to set up the database at all. The first time you run bun run dev it downloads and starts one for you, on your laptop, with its data in .pb/. You can open its admin screen from the dev server at /api/pb/_/.

The only time you touch this is if the log says port 8090 is already in use — then set DX_PB_PORT to something else in .env.local.


One more thing to set

The maps need a Mapbox token. It is the one credential you have to ask the team for:

VITE_MAPBOX_TOKEN=<ask the team>

That, plus DX_SYNC_REMOTE=origin if you want it, is the whole of .env.local.


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. A rejected push is normal — 95% of them were, and none became conflicts.
  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 main, 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/main -1.
  • The shared server shows an old version of your plugin — you are probably looking at what is on main, not what is on your laptop. Those are different on purpose.