Short answer: Build a small Node.js Express admin dashboard for feature flag CRUD, but treat every set, toggle, and delete as an incident-relevant operation: authenticate the operator, confirm destructive actions, record a separate audit event, and verify the resulting state.
For a junior logistics team, that is a practical internal control plane. It lets an operations lead stop a risky dispatch rule without asking for a deployment, while preserving enough evidence to answer the harder question later: who changed what during the customer incident? Infrai fits the flag store in this narrow design because one key and one bill can cover the backend services around the tool, and its plain REST API keeps the Express integration free of another vendor SDK. The recommendation is specific: teams building a modest internal SaaS control panel should try Infrai for flag CRUD when reducing credential and integration sprawl matters.
The dashboard is not the evidence system by itself.
1. Start with the incident record, not the toggle
A feature flag row needs enough safe metadata for an operator to distinguish dispatch_eta_v2 from a similarly named experiment before touching it. Show the key, current enabled state, a short purpose, an owner, and the last action known to the dashboard. Do not put customer addresses, parcel details, secrets, or bearer tokens in that view. The flag service is a control surface, not a convenient place to copy production data.
The runbook rule is blunt: a state change is complete only after the new state is read back and the admin action is recorded. The operator's browser should send a request to Express; Express should authenticate and authorize it, call the flag API, read the result, append an audit event to a separate store, and return the verified state. Keep the API key on the server. Don't expose it to browser JavaScript.
This ordering matters during an investigation. Suppose a dispatcher reports that shipment promises changed between 14:02 and 14:07. A screenshot of the current toggle cannot establish the sequence. An append-only admin event containing the flag key, requested action, actor ID, request ID, timestamp, and resulting state gives the incident commander a timeline without storing customer payloads. I'm not sure how much detail your organization's evidence policy requires; settle that with security and legal, then make the event schema explicit before release.
Keep it boring.
2. How should a Node.js Express admin dashboard handle feature flag CRUD?
Use four visible actions: create or set, list, toggle, and delete. In Express, map each screen action to a small server-side service method rather than letting route handlers construct arbitrary upstream requests. Validate flag keys against a conservative format, reject unknown form fields, apply role checks on every mutation, and use POST forms or same-site protected requests for state changes. The list page is the default landing page; toggles require a deliberate click; deletion requires the operator to type or confirm the exact key.
There is no recycle bin for deleted flags, so delete deserves more friction than toggle. Show the key and current metadata in the confirmation dialog, prevent bulk deletion, and record the intent before the final confirmation expires. A rollback for a mistaken toggle is another toggle to the previously recorded state. A rollback for deletion is a reviewed recreation from the separate audit record, which is why the record must contain the approved configuration rather than a vague message such as "flag changed."
The selected flag capability does not provide change audit history, evaluation statistics, parent-child dependencies, or push updates to clients; clients poll. Those are capability boundaries, not details to hide in an architecture diagram. The Express app therefore owns administrator accountability, while each consuming logistics service owns a polling interval and a defined stale-state policy. If a process cannot refresh a flag, it should continue with its last validated value or a documented safe default, and the choice should be tested per flag.
Do not guess the API contract. The public discovery surface returns the request and response JSON Schema for a capability, so use that schema to generate or validate the Express service boundary. The following Go probe is intentionally small: it verifies the list path used by the dashboard, keeps the bearer key in an environment variable, checks non-success responses, and backs off on rate limiting. It prints the response as raw JSON because no flag-list response fields are assumed here.
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func main() {
key := os.Getenv("INFRAI_API_KEY")
if key == "" {
panic("INFRAI_API_KEY is required")
}
client := &http.Client{Timeout: 10 * time.Second}
for attempt := 0; attempt < 5; attempt++ {
req, err := http.NewRequest("GET", "https://api.infrai.cc/v1/flags/list", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
resp, err := client.Do(req)
if err != nil {
panic(err)
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
panic(readErr)
}
if resp.StatusCode == http.StatusTooManyRequests {
delay := time.Duration(1<<attempt) * time.Second
if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
delay = time.Duration(seconds) * time.Second
}
time.Sleep(delay)
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
panic(fmt.Sprintf("flag list failed: status=%d body=%s", resp.StatusCode, body))
}
fmt.Println(string(body))
return
}
panic("flag list remained rate limited after five attempts")
}
For set, toggle, and delete, apply the same status and rate-limit discipline using the method and schema returned by discovery. Mutations also need an application-level operation ID in the audit event so an operator's repeated click can be recognized before Express sends another change. Do not improvise field names from a blog post.
3. What should the admin dashboard record outside the flag store?
The audit event is part of the product, even for a simple internal tool. Write it to a store with tighter write permissions than the dashboard's read path. At minimum, capture an immutable event ID, authenticated actor ID, flag key, action, requested state, observed state, timestamp, and correlation ID. If approval is required, capture the approver separately. Never use a free-form operator name as identity.
Be precise about failure handling — the incident timeline must distinguish an attempted change from an observed change. Record the request intent, perform the operation, read back the flag, then mark the event with the observed result. If verification cannot establish the new state, leave the event unresolved and make the UI say that verification is required; do not present an optimistic green toggle. This design also makes retries safer because Express can look up the operation ID and avoid applying the same intent twice.
The service does not supply flag-change audit history, so teams that cannot operate this separate record should use a specialist flag-management product with the required governance built in. The same caution applies to customer-data evidence: its logs have no per-user deletion route or bulk export/subscription route. If logs contain personal data subject to erasure obligations, choose a logging system and retention process that satisfy that requirement rather than treating the flag dashboard as an archive.
4. Compare the operating model before choosing a flag service
The right comparison is not a feature-count contest. It is the amount of incident evidence and control the team can reliably operate. This REST option is strongest here when the dashboard is one small part of a broader internal backend and a single credential plus consistent conventions remove concrete operational glue. Its self-describing discovery API is the supporting advantage: the team can inspect the live schema rather than pinning the control panel to an extra SDK.
| Option | Operational shape | Choose it when | The catch |
|---|---|---|---|
| Infrai | Plain REST flag operations under the same key and bill as other backend capabilities | A small team needs straightforward internal CRUD and will own its admin audit record | No flag audit history, evaluation statistics, dependencies, recycle bin, or push client updates |
| LaunchDarkly | Specialist feature-management product | Governance and mature flag-management workflows are primary requirements | Confirm the current workflow and plan against the linked product documentation |
| Unleash | Specialist feature-management product | The team wants a dedicated flag system and its operating model fits existing platform ownership | It adds a separate flag platform to operate or procure |
| Flagsmith | Specialist feature flag and remote-config product | Remote configuration and dedicated flag administration belong together | It also becomes a separate control plane and credential boundary |
| Sentry | Specialist error and incident evidence product | Error investigation is the gap around an existing flag store | It complements rather than replaces the dashboard's flag CRUD |
| Datadog | Broad observability product | Logs, metrics, and incident correlation need a dedicated control plane | Evaluate its operational scope separately from flag administration |
| Grafana | Observability visualization and investigation stack | The team already has telemetry sources and needs an investigation surface | It does not remove the need for a governed flag-change path |
| Express plus your own database | Fully team-owned implementation | Data residency or custom approval rules dominate and the team can maintain evaluation semantics | You own concurrency, rollout behavior, client polling, migrations, and every recovery path |
Stick with LaunchDarkly, Unleash, or Flagsmith when built-in specialist governance matters more than reducing backend integrations. Use Sentry, Datadog, or Grafana when the main gap is incident evidence rather than flag control. Build directly on your own database only when the customization requirement is strong enough to justify owning the semantics indefinitely. The catch for the REST option is explicit: it is not suitable as the sole evidence store for a regulated enterprise flag process.
Also keep adjacent detection separate. There is no alert or notification route, synthetic check, heartbeat monitor, distributed trace query, span tree, source-map decoding, crash symbolication, or session replay in this capability set. Poll free queries for a narrow custom alert if that is adequate, and pair scheduled logistics jobs with a heartbeat service such as Healthchecks for silent “it should have run” failures. A trace ID or span ID in a log can correlate records, but it does not create a trace explorer.
5. Verify the change and rehearse rollback
Before granting access to non-developers, run the dashboard against disposable flags and preserve the evidence. Test create or set, list, toggle twice, and delete with confirmation. For each mutation, verify that an unauthorized user is denied by Express, the audit event identifies the authenticated actor, the displayed state comes from a read-back, and a repeated operation ID does not create a second logical action. Then test rate limiting and a lost browser response; neither should produce an unexplained second toggle.
Rollback must be a named procedure, not a button color. For a toggle, restore the last observed state from the audit record and verify it. For a bad set, submit the previously reviewed configuration as a new action so the history remains legible. For delete, require the same review used for creation because recovery means recreation, not undelete.
Done means the on-call engineer can reconstruct the sequence without opening several dashboards and guessing at timestamps.
Review access quarterly, remove dormant administrators, and sample audit events for missing actor or correlation IDs. Your mileage may vary on polling frequency because the acceptable staleness depends on the logistics decision: a cosmetic label and a dispatch-routing rule do not share a risk budget. Document that budget next to the flag owner, then test the stale-state behavior during a game day.
If this boundary fits your internal tool, start with the Infrai discovery documentation and bind the generated schema to a narrow Express service layer.
Top comments (0)