rastrillo / idear Public

Clone
git clone https://amadan.net/rastrillo/idear

Plain git — no account needed to clone.

Download

The example board

A complete app on rastrillo + idear: a shared message board whose roster is idear's. It is the worked reference ../SKILL.md points at, and it is part of the amadan.net/rastrillo/idear module rather than a submodule — a nested module would need a replace directive pointing at its own parent, which is exactly the thing an app must never write.

Run it

BOARD_SEED=1 go run ./example -addr 127.0.0.1:8080 -db /tmp/board.db

Then sign in at <http://127.0.0.1:8080/signin> as one of the seeded accounts, all with the password demo-password:

| Address | Role | What you can do | | ------------------- | ------ | ------------------------------------------------- | | ada@example.test | Owner | everything, including transferring ownership | | kim@example.test | Admin | invite and manage Members only | | sam@example.test | Member | read the roster; post; nothing else |

Three accounts at three roles, because a role gate you cannot click on is a role gate nobody checks. Sign in as Kim and the role selector offers Member and nothing else; sign in as Sam and the members page offers no controls at all.

BOARD_ORIGIN sets the external origin (it decides the CSRF check and the cookie attributes); BOARD_NAME sets the instance's display name on the public invitation page. Both default loudly.

There is no mail server here, so HandlerConfig.Deliver is nil and idear puts the invitation link itself in the flash notice shown to the admin who minted it. Copy it out of the page. A deployed app sets Deliver and keeps the token out of the browser entirely.

What to read

| File | What it shows | | -------------- | ------------------------------------------------------------------- | | app.go | the whole wiring, in the order it has to happen, with the reasons | | models.go | the app's own User, BootSchema, and a seed through the real flows | | render.go | the two idear render callbacks, and idear.TokenFrom in RenderSignup | | handlers.go | idear.From(r), and an app route gated on Admin | | app_test.go | the whole flow through real HTTP — the thing to copy |

Four things in here are load-bearing rather than stylistic, and each has a comment at the site saying so:

  • / is behind Require. Under the password plugin, deactivation is enforced per request by Require, not at sign-in — password.Signin runs Lookup → Verify → mint with no idear involvement. An ungated landing page is a page a removed member can still read.
  • POST /signup is wrapped in rs.CarryToken. Without it the invitation token never reaches admission and every invited signup is refused.
  • One 404 renderer, bound once and handed to both idear.Config.NotFound and chi's own NotFound. Two of them is a membership oracle, and it is the one misconfiguration idear cannot detect at runtime.
  • renderSignup seeds its hidden invite field from idear.TokenFrom(r). password.PageData has nowhere to carry a token, so without this a signup that fails validation re-renders a form with an empty field and the invitee's second attempt is refused. If you rewrite this page — the likeliest thing to do to it — keep that line.