--- import Base from '../layouts/Base.astro'; import PageHeader from '../components/PageHeader.astro'; import NotBuilt from '../components/NotBuilt.astro'; import platform from '../data/platform.json'; /** * `/integrations/` — PLAN.md §13 phase 4. * * §10 gives it Discord, mobile and push, SSO, "with an explicit 'not built' list". The * explicit list is the reason this page is worth writing carefully: an integrations page is * the one a reader scans for the name of the thing they already use, and the honest answer * for several of those names is no. §2 calls the absent-features list as load-bearing as the * rest, and `NotBuilt` at the foot of this page is where that lands. * * --------------------------------------------------------------------------------------- * THE TRADE-OFFS ARE ON THE PAGE * --------------------------------------------------------------------------------------- * Each integration carries a `caveat` — the thing you would find out in week two. Discord * voice channels make Team membership visible on a member's Discord profile, because they * are granted by role; the mobile app has no server of ours to point at; SSO will not create * an account. None of those is a defect and all three change whether someone wants the * feature, so leaving them for the documentation would be the dishonest kind of brevity. * That is D8's "understated honesty" doing something other than adjusting adjectives. * * No version numbers are typed here. The app version and the platform's own numbers come * from `platform.json` (§12), which `checkFacts.mjs` re-reads from each repository's * authority on every build. */ const title = 'Integrations'; const description = 'What Runic Gateway connects to — Discord, mobile push, single sign-on — and what it ' + 'deliberately does not.'; const integrations = [ { id: 'discord', name: 'Discord', summary: 'A bot for the server your community is already sitting in, doing three separate jobs.', points: [ { title: 'Slash commands', body: 'Commands registered with your guild that answer from your site — so the thing ' + 'somebody wants to look up is available where the conversation is happening, ' + 'rather than one tab away.', }, { title: 'Notifications into channels', body: 'News and Team activity bridged into the channels you choose, with a per-Team ' + 'override so one group can route its own notifications somewhere else. Delivery ' + 'is best-effort and one-shot: a Discord outage never backs anything up on your ' + 'site.', }, { title: 'A voice channel per Team', body: 'A Team can be granted its own voice channel, with membership maintained by the ' + 'bot rather than by whoever is online. The bot creates the category, and the ' + 'panel reports how many roles your guild has left before Discord’s own limit.', }, ], caveat: 'Voice access is granted with a Discord role, and roles are visible on a member’s ' + 'profile — so a Team with a voice channel is a Team anyone in your guild can see the ' + 'membership of. That was a deliberate trade for a limit that counts per guild rather ' + 'than per channel, and it is the right one for most communities, but it is not private.', }, { id: 'mobile', name: 'Mobile and push', summary: 'A native Android app against the same documented API the website uses, with push ' + 'through a server you run.', points: [ { title: 'The same API, not a second one', body: 'The app is a client of the API your deployment already publishes, authenticated ' + 'with short-lived tokens and rotated, revocable refresh tokens. There is no ' + 'mobile-only backend to keep in step.', }, { title: 'Push through your own ntfy', body: 'Notifications are delivered by a self-hosted ntfy server rather than a vendor in ' + 'the middle. Each person chooses which streams reach them; push arrives by ' + 'default and can be switched off entirely.', }, { title: 'Trusted devices and two-factor', body: 'The app shares the site’s account model, including time-based two-factor ' + 'codes, recovery codes, and devices you can mark as trusted and revoke later.', }, ], caveat: 'The app points at no server of ours: the person installing it types the address of ' + 'the deployment they belong to. That is what makes one app work for every community ' + 'running this software, and it means the app is useless until somebody gives them a ' + 'URL — which is a thing worth putting in your welcome message.', }, { id: 'sso', name: 'Single sign-on', summary: 'OAuth2 and OIDC, against Google, Discord, or any provider you already run.', points: [ { title: 'Any OIDC provider', body: 'Google and Discord are configured by name; anything else that speaks OIDC is ' + 'configured generically. Client secrets are encrypted at rest and never returned ' + 'to any client.', }, { title: 'It signs people in, not up', body: 'An external identity has to be linked to an account that already exists on your ' + 'site. Signing in with a provider never creates a user — which means the way ' + 'someone joins your community stays a decision you make, not one Google makes.', }, { title: 'It respects the rest of the login rules', body: 'Two-factor, trusted devices and bans all still apply. An identity provider ' + 'proves who someone is; it does not decide whether they may come in.', }, ], caveat: 'Link-only is a policy, not a limitation to be worked around. If you were expecting ' + 'to open registration by turning on Google sign-in, this will not do that, and it is ' + 'not configurable.', }, ]; ---

Three integrations exist and are in use. Each one below says what it does, and then the thing you would otherwise discover in week two — because an integrations page that only lists the good half is how somebody ends up rebuilding their community around an assumption.

Everything here is configured on your own deployment, against services you already run or already have an account with. Nothing routes through us; there is no us to route through.

{ integrations.map((integration) => (

{integration.name}

{integration.summary}

Worth knowing first

{integration.caveat}

)) }

Email, deliberately quiet

Your deployment can send email — Team notifications and newsletters, through an account you connect — and it only ever sends to someone who asked for it. Email is the one channel that is opt-in rather than opt-out, because an unwanted push notification is an annoyance and an unwanted email is a complaint to somebody’s provider.

This website is a separate matter: runicgateway.com sends no email at all, has no mailbox behind it and no account to make. The address in the footer is a human being.

If you need another one

The API is the integration point

The whole backend is described by an OpenAPI 3.0 specification that ships with the server, and an installed module merges its own routes into it — so whatever you build against is documented by the thing that is actually running, at {' '}Module API {platform.moduleApi}. The bridge to a game server is a documented wire protocol on the same principle, currently protocol {platform.protocol}.