remove rust implementation artifacts ยท zzstoatzz/status@3193e82
quickslice rewrite replaces the custom rust backend. ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
https://github.com/zzstoatzz/status/commit/3193e82bcf456d5e36f347bf8b5a582cf65e0c70

(most of this was lockfile / not source code tbh)


a while ago, i forked @baileytownsend.dev's wonderful rusty statusphere repo and added in a whole lotta bufo so it could serve as any atproto identity's personal status page. thanks bailey :D

then, yesterday @chadtmiller.com released quickslice!

My crazy idea to cram all of the AT Protocol into a single deployable container. Works with SQLite, Postgres and potentially more data stores in the future. Steps are literally deploy container -> import your lexicons -> backfill -> build your app with the GraphQL APIs. quickslice.slices.network

quickslice - Introduction

quickslice - Introduction


https://quickslice.slices.network/

and i thought:

hey i should be able to replace the rusty-statusphere-derivative backend for status.zzstoatzz.io with a quickslice instance!

i wasn't yet sure how to write/deploy a UI that consumes the quickslice instance, but i had already ran the quickslice server locally and figured out how to configure the /settings more or less:

  • upload my pre-existing lexicons

    • make a zip like zip -j lexicons.zip lexicons/*.json

    • upload it in Lexicon portion of the settings

  • set a domain authority

    • io.zzstoatzz

  • set supported oauth scopes (no transition:generic allowed!)

    • io.zzstoatzz.status.record

    • io.zzstoatzz.status.preferences

  • register an OAuth client

note previously, preferences were persisted in the sqlite db that my rust backend talked to so font/accent preferences stuck across devices, but during this refactor i realized i could just store them as a record! not sure what the meta for "hey i wanna store just a little somethin non-standard in the quickslice db" is quite yet

the config looks like this in the admin panel of my quickslice instance

backend secrets and config

the quickslice instance needed two secrets for OAuth to work:

fly secrets set SECRET_KEY_BASE="$(openssl rand -base64 64 | tr -d '\n')"
fly secrets set OAUTH_SIGNING_KEY="$(goat key generate -t p256 | tail -1)"

(i think?) the OAUTH_SIGNING_KEY should be just the multibase key (starts with z), not the full output from goat... that's what worked for me anyways, lmk if i am wrong about this!

without EXTERNAL_BASE_URL, quickslice uses 0.0.0.0:8080 in its OAuth client metadata, so go ahead and set it to your public URL:

[env]
  EXTERNAL_BASE_URL = 'https://your-app.fly.dev'

i used this thread to figure this out

going to try and get quickslice set up (tried like 2 weeks ago but failed miserably) ๐Ÿ‘€

so then after a smol bug encounter where quickslice was not returning sub from the token endpoint (causing login to redirect back to a logged out state), i rather expediently had a quickslice instance that could (very quickly!) backfill all the status records! excellent!

now i just needed to rewrite (or have claude rewrite tbh) the UI to consume my new backend in a box!

the UI!

this part turned out to be easier than i thought!

your lexicons are the API! after uploading the lexicons, you can just write GraphQL queries from your front-end to get your data!

const response = await fetch(`https://your-quickslice.com/api/graphql`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: `
      query GetStatuses($did: String!) {
        ioZzstoatzzStatusRecords(
          where: { did: { eq: $did } }
          orderBy: { createdAt: DESC }
          first: 50
        ) {
          nodes { uri did actorHandle emoji text createdAt }
        }
      }
    `,
    variables: { did }
  })
});

i just told claude to broadly replace the calls to my old rust server endpoints in the UI with graphQL calls.... and then i went in the admin panel and clicked "Backfill" (once or twice, since it seemed it didn't totally backfill the first time? not sure).

then quickslice-client-js handles the OAuth flow in the browser:

const client = await QuicksliceClient.create({
  server: 'https://your-quickslice.com',      // your quickslice instance
  clientId: 'client_xxx',                     // from quickslice admin UI
  redirectUri: window.location.origin + '/',  // where OAuth redirects back
});

// start login
await client.signIn(handle);

// after redirect, client.agent is authenticated
const { data } = await client.agent.getProfile({ actor: client.agent.session.did });

the clientId comes from registering an OAuth client in the quickslice admin UI. the redirect URI should match what you registered.

since quickslice serves its own admin UI at the root, we host our frontend separately on cloudflare pages. the frontend is vanilla JS - no framework, just a single app.js file (i do backend by trade! shh)

this is what worked for me as i tried to figure this out! if you have suggestions for improvements, please leave a comment here!

once i had my new backend and cloudflare pages, i switched my CNAME for status.zzstoatzz.io to point at the new cloudflare page.

and i deleted my old rust/fly backend and bob was then my uncle!

the whole thing!

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    cloudflare pages                     โ”‚
โ”‚                  status.zzstoatzz.io                    โ”‚
โ”‚                                                         โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”‚
โ”‚   โ”‚  index.html โ”‚  โ”‚   app.js    โ”‚  โ”‚  styles.css โ”‚     โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           โ”‚
                           โ”‚ GraphQL + OAuth
                           โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                       fly.io                            โ”‚
โ”‚            zzstoatzz-quickslice-status.fly.dev          โ”‚
โ”‚                                                         โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚   โ”‚                  quickslice                     โ”‚   โ”‚
โ”‚   โ”‚  โ€ข OAuth server (PKCE + DPoP)                   โ”‚   โ”‚
โ”‚   โ”‚  โ€ข GraphQL API (auto-generated from lexicons)   โ”‚   โ”‚
โ”‚   โ”‚  โ€ข Jetstream consumer                           โ”‚   โ”‚
โ”‚   โ”‚  โ€ข SQLite database                              โ”‚   โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           โ”‚
                           โ”‚ Jetstream
                           โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    AT Protocol                          โ”‚
โ”‚           (bluesky PDS, jetstream firehose)             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

get sliced!

links!


thanks chad for reviewing a draft of this post!