LaunchKit

A Rails admin panel

A founder console gated by HTTP Basic Auth instead of user accounts, seventeen controllers on their own layout, and a setup wizard that writes the credentials the gate reads. What it costs to build, and where it stops.

Every application grows a back office. Somebody has to read the support tickets, refund the customer who asked twice, flip the feature flag before the demo and find out why that signup never confirmed. The question is not whether you build one, it is what it authenticates against.

What the console has to answer to

The obvious answer is the application's own login, with a role column and an admin? check. It is also the answer that drags the console through every gate the application has: the session, the email confirmation, the onboarding flow a user must finish before reaching anything. Each of those is a place where the founder can get locked out of their own back office, and each is a place where a bug in the user-facing app becomes a bug in the tool you fix it with.

Admin::BaseController takes the other road. It declares allow_unauthenticated_access and allow_unonboarded_access, which switch off both of the application's gates, and then installs one of its own in a before_action. The console stops being a privileged corner of the product and becomes a separate thing that happens to share a database.

The gate itself

HTTP Basic Auth, with the credentials read from the Rails credentials file under admin: rather than from any table. There is no admin user model, no password reset, no session. The browser holds the credentials and sends them on every request.

That is a real trade and the article on gating the console with HTTP Basic Auth is where it gets argued properly: what the comparison has to do to be safe, why the two checks are joined with a single ampersand, and the point at which a growing team makes this the wrong choice.

An unconfigured console returns 404

A fresh clone has no admin credentials, and the wizard that writes them lives inside the console. authenticate_admin resolves that in two directions. In local environments it returns early and lets the founder straight through, so the setup wizard is reachable on a machine where nothing has been configured yet. In production it answers head :not_found.

The 404 is the interesting half. Challenging for a password that does not exist would tell a stranger that a console is there and simply unconfigured, which is an invitation. Answering the way every unused path answers says nothing at all.

Seventeen controllers, one layout

The Rails admin dashboard here is not a generic CRUD scaffold pointed at the schema. Each screen was written because something had to be done by hand: users, leads and comments for the people, support_tickets for the inbox, quiz_answers for content that lives in the database, pricing and features for what the landing page sells, appearance and settings for how it looks, analytics and referrals for what happened, ai and ai_templates for the assistant, and setup for the wizard that got you here.

They all inherit Admin::BaseController and all render layout "admin", so the gate and the chrome are decided once.

Two of them are worth their own page because the decision inside them is not obvious. The first-run setup wizard writes encrypted credentials and is gated to local environments, which is a stranger choice than it sounds until you consider what a deployed secrets form can be read for. And editing the pricing table touches a number that exists in three places at once, only one of which charges anybody.

What this is not

Not ActiveAdmin, not Avo, not a CMS. There is no DSL, no engine mounted in routes.rb, and no generated screen for a model you have not thought about. That is deliberate at this size: a generated back office gives you every table immediately and then resists the first screen that does not look like a table.

It is also not multi-user. One credential pair, shared. A second person with their own login, an audit trail of who deleted what, permissions per screen: none of that is here, and all of it is the reason a growing team eventually moves the gate onto real accounts.

Articles on this topic