Guestbook Example

This capsule shows an intentionally shared feed. Guests and signed-in users can post. Everyone who can use the app can read the same entries.

What It Shows

Server Pattern

Use shared feeds when every user can read the same rows:

queries: {
  entries: query(async (ctx) => ctx.db.entries.withIndex("by_creation").order("desc").take(50))
}

Still keep writes server-authoritative:

const author = ctx.auth.requireIdentity();
await ctx.db.entries.insert({
  body: trimmed,
  authorId: author.userId,
  authorName: author.displayName,
  authorPicture: author.picture ?? ""
});

Do not accept authorId, authorName, authorPicture, or other trusted metadata from the client.

Sharing comes from the query's lack of an owner filter. It does not use a shared guest ID or a fake global user. The authorId reference follows a guest to their account on sign-in. authorName and authorPicture are stored snapshots, so reference transfer does not replace them.

To allow only signed-in accounts to post, use ctx.auth.requireSignedIn() in the sign mutation. To require sign-in before reading or writing any app data, set auth: { requireSignIn: true } on the capsule.

Run It

Run the checked-in example:

npx lakebed dev examples/guestbook

Open:

http://localhost:3000

To see shared updates from named local test identities, open:

http://localhost:3000/?lakebed_guest=alice
http://localhost:3000/?lakebed_guest=bob

Named overrides cannot upgrade to accounts. Use the default browser session with no override to test guest upgrades.

Then inspect state:

npx lakebed db dump --port 3000
npx lakebed logs --port 3000