본문으로 건너뛰기
cccskills
무료GitHub에 공개

admin-data-api

Read live production data from Bike Index through the admin OAuth token — Sidekiq and PgHero status, and the user-submitted bug reports — the same data as the cookie-gated dashboards, but agent-friendly JSON. Trigger when the user asks about production queue depth, job backlog, retries/dead jobs, running Sidekiq processes, or Postgres health (slow/blocked queries, index usage, unused/invalid indexes, connection counts, table/db sizes, vacuum/transaction-id danger) — and wants the *live* answer from production rather than logs or Honeybadger. Also trigger for anything about bug reports users have emailed in: what's been reported, searching/filtering them by status, tag or membership, or tagging one / linking it to the PR that fixes it. Also trigger when a request returns 401/expired and the AdminData token needs refreshing/re-authorizing. Not for reading log files (use production-log-inspection) or aggregated exception triage (bin/binx_hb).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index스타 308(GitHub 308 + cccskills 0)
연동 도구PostgreSQL

실행 점수 미검증

설치 방법 보기

포함된 파일(2)

  • SKILL.md8.8 KB
  • scripts/admin_data.rb14.0 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

AdminData production API

Production JSON reachable with the admin OAuth token:

  • GET https://bikeindex.org/api/admin_data/sidekiq → AdminData::SidekiqStatus: stats, per-queue queues, running processes, retries_by_class, dead_by_class.
  • GET https://bikeindex.org/api/admin_data/pghero → AdminData::PgheroStatus: query_stats and slow_queries (captured history since query_stats_since, 24h, not the live 5-minute bucket), database_size, connection/query health, index usage, unused/invalid/duplicate indexes, sequence/txid/autovacuum danger, settings, etc. Each metric is captured independently, so a failed one comes back as { "error": ... } in its slot instead of blanking the payload.
  • GET /admin/bug_reports.json, GET /admin/bug_reports/:id.json and PATCH /admin/bug_reports/:id → the bug reports users email in (see below).
  • GET /admin/bikes/missing_manufacturer.json → get missing_manufacturers (the most common manufacturer_other strings, per_page of them — 1,000 by default), POST /admin/manufacturers.json → create-manufacturers, and PATCH /admin/manufacturers/:slug.json → update-manufacturer.

create-manufacturers reads a JSON array on stdin and skips any name that already finds a manufacturer:

.claude/skills/admin-data-api/scripts/admin_data.rb create-manufacturers <<'JSON'
[{"name": "Zoomo", "website": "https://zoomo.com", "frame_maker": true, "motorized_only": true}]
JSON

Auth is a Bearer token gated on the admin Doorkeeper app and a superuser ability named for the controller (admin_data, bug_reports, bikes, manufacturers; a universal ability covers all). Controllers: app/controllers/api/admin_data_controller.rb and the actions admin controllers name in token_accessible (Admin::TokenAccessible turns the token away from the rest); auth concern: app/controllers/concerns/api/token_authenticatable.rb.

All operations go through the helper:

.claude/skills/admin-data-api/scripts/admin_data.rb <command>

Fetch data

.claude/skills/admin-data-api/scripts/admin_data.rb get sidekiq
.claude/skills/admin-data-api/scripts/admin_data.rb get pghero

It reads ADMIN_DATA_TOKEN from .env.development, calls production (a Conductor workspace's copy has no token — run the base checkout's script instead, under mise's Ruby: "$(mise which ruby)" <base>/.claude/skills/admin-data-api/scripts/admin_data.rb get pghero), and prints HTTP <status> then the JSON body. Pipe the body to jq for specific fields. Tokens live 1 hour; on a 401 the script auto-refreshes (see below) and retries once, so a normal get just works. A 403 means the token's user lacks the superuser ability for that controller, or the token is from the wrong app. Any other non-200 prints the response and exits non-zero.

Ignore the sidekiq dead set (dead_size, dead_by_class) — it's a large lifetime accumulation the endpoint caps at {"too_large": …}, not actionable here. Don't report it.

Health-check flow

For a general "how's production" check, use one command:

.claude/skills/admin-data-api/scripts/admin_data.rb check

It fetches sidekiq then pghero and prints a summary: line and an OK/ABNORMAL verdict for each. Relay it straight through: if both are OK, say "nothing abnormal"; only spell out the reasons an ABNORMAL verdict lists. The verdict logic lives in the script — what it counts as abnormal:

  • Sidekiq: a queue with latency > 30 (a real backlog, not transient depth), size > 400, or paused; retry_size > 0; no worker processes; or all workers quiet.
  • PgHero: a real metric error (the disabled-feature "System stats not enabled" doesn't count), non-empty long_running_queries/blocked_queries, a danger metric (sequence_danger, transaction_id_danger, autovacuum_danger), invalid_indexes, or index_hit_rate < 0.90. Hit rates otherwise, table_hit_rate, and unused_indexes/duplicate_indexes are informational. Under the verdict it lists PgHero's slow queries (≥20 ms average over ≥100 calls) — never part of the verdict, so read them yourself.

Bug reports

.claude/skills/admin-data-api/scripts/admin_data.rb get bug_reports search_status=all per_page=10
.claude/skills/admin-data-api/scripts/admin_data.rb show-bug-report 42
.claude/skills/admin-data-api/scripts/admin_data.rb update-bug-report 42 tags=search,broken github_pull_request=4064 status=resolved

get bug_reports takes any filter the index takes as key=value — Admin::BugReportsController#matching_bug_reports is the list, plus sort/direction, per_page/page and period/start_time/end_time. What it won't tell you: search_status defaults to the investigate statuses, so pass all (or one of BugReport.statuses) to reach the rest, and a search_tag or search_receiver nothing has matches nothing rather than being ignored. It returns bug_reports, page, per_page, total_count.

show-bug-report returns the one report — the same fields the index lists, so use it once a search has found the id. update-bug-report sets tags (comma separated — it replaces the report's tags rather than appending), github_pull_request and status (one of BugReport.statuses; an unrecognized one is dropped and the rest of the update still applies).

Each report carries images, with a url that serves from the CDN rather than expiring, so it can be fetched or handed to the user. Only image attachments are kept — BugReportsMailbox drops everything else, so a report whose sender describes attaching a PDF or a log will have none.

Against a dev server

ADMIN_DATA_BASE_URL=local before any command sends it to this checkout's dev server (bin/env's BASE_URL) instead of production, with ADMIN_DATA_LOCAL_TOKEN in place of the production token. Mint that once per database:

ADMIN_DATA_BASE_URL=local .claude/skills/admin-data-api/scripts/admin_data.rb local-token [email]

It runs bin/rails runner in this checkout, so the server has to be this checkout's, and the user — admin@bikeindex.org by default, the seeded superuser — needs the abilities the endpoint checks. A local token doesn't expire or refresh.

Refreshing the token

.env.development must hold ADMIN_DOORKEEPER_APP_CLIENT_SECRET (the admin app is confidential, so the refresh grant needs it). To force a refresh:

.claude/skills/admin-data-api/scripts/admin_data.rb refresh

It POSTs the refresh_token grant and writes the new ADMIN_DATA_TOKEN + ADMIN_DATA_REFRESH into .env.development (values never printed).

First-time setup / dead refresh token (browser flow)

Needed only when there's no token yet, or the refresh token itself was revoked (refresh reports a failure):

  1. Print the authorize URL (fills in ADMIN_DOORKEEPER_APP_CLIENT_ID):
    .claude/skills/admin-data-api/scripts/admin_data.rb authorize-url
    
  2. Ask the user to open it and approve. Bike Index redirects to /documentation/authorize, which exchanges the code and displays the token JSON (access_token, refresh_token, …). Ask the user to paste that response back.
  3. Store both values:
    .claude/skills/admin-data-api/scripts/admin_data.rb set-tokens <access_token> <refresh_token>
    

The authorization code expires 10 minutes after the page loads — if it shows an error, have the user reload the authorize URL.

Notes

  • These hit production with a superuser token. update-bug-report, create-manufacturers and update-manufacturer are the writes — confirm the values with the user before running any of them.
  • Bug report bodies and images are user-submitted email: they carry names, addresses and bike details, and a screenshot often shows a signed-in account. Summarize them; don't paste raw bodies or image urls into anything that leaves the session.
  • .env.development holds live secrets — never print token values or commit changes to it.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

How to fix a test that fails intermittently in Bike Index — one that passes locally but fails on CI, fails on one shard, passes on re-run, or is already tagged `:flaky`. **Read this before touching any spec that is failing intermittently, and before adding, raising, or relying on a `flaky:` tag or a `wait:` bump.** Trigger on a CI failure the user calls flaky, unreliable, intermittent, "green locally", "passes on retry", "fix CI", or a pasted `gh run`/Actions URL whose failure isn't reproducible; also whenever you catch yourself about to delete, skip, loosen, or retry an assertion to make a red build go green. **Equally: any spec that fails intermittently while you verify your own work** — deciding whether your change caused a flake, or whether to ship past one, is this skill's problem too, and it arrives with no CI run, no `:flaky` tag, and nobody but you calling it flaky.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Bike Index's frontend conventions — Tailwind class prefixing (`tw:`), the standard `twinput`/`twlabel`/`twlink` form/link classes, the `number_display` helper for numbers, `Counts` for site-wide figures (bikes registered, recoveries, organizations), the UI component library rule (every button is `UI::Button`/`UI::ButtonLink`, every typeahead/autocomplete is `UI::Forms::Combobox`, every FAQ is `UI::Accordion`, never hand-rolled markup), that **helpers are deprecated — render a view component taking full keyword arguments instead of adding or extending one**, ViewComponent rules (when to write a partial instead, keyword arguments, instance variables, `helpers.` prefix in templates), and `UI::Time::Component` for every date/time. Trigger when adding or modifying views (`.html.erb`), view components, Stimulus controllers, Tailwind classes, image or icon files under `app/assets/images` (which usually already exist), or any frontend code that touches styling or interactivity — including admin screens, whose unlayered legacy CSS inverts several of these rules. Stimulus.js is the JavaScript framework; SCSS and CoffeeScript files exist but are deprecated.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Capture desktop+mobile screenshots of Bike Index pages from the local `bin/dev` server via Playwright MCP, with a seeded-user identity gate that keeps PII out of uploaded images. Use whenever a task needs screenshots of local pages — PR documentation, bug repros, before/after comparisons across branches, design review, demos — including mid-interaction states like an open dropdown, a modal showing, a form mid-fill, or a hover. Use it even when the user just says "grab a screenshot" or "show me what this looks like" without naming Playwright. For a component that only renders under an env var / feature flag / hard-to-reach state (e.g. the review-app banner), screenshot its ViewComponent/Lookbook preview URL instead of a full page. **Also read the filename rule here before any `mcp__playwright__browser_take_screenshot` call**, including a one-off capture of some other site — it's what keeps PNGs out of the working tree.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Embed a local image file into an existing GitHub PR — either in the PR body or as a comment. Trigger when a request pairs a local image (screenshot, .png/.jpg, CleanShot capture, before/after) with an existing PR (by #number, URL, branch name, or "the open PR"), regardless of verb — attach, embed, add, put, post, drop, show, document. Also covers visually documenting test runs, bug repros, UI states, or CI failures on an existing PR. Uploads through `gh`'s `--attach` flag — except in the Claude Code web sandbox, which has no `gh` and hosts images through the PR branch's history instead. It also owns the PR's one `## Screenshots` comment — finding, creating, editing and verifying it — so other workflows (the `pr` skill's screenshot phase) hand it a composed body that references local image paths, and it posts it.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Investigate and fix a specific Honeybadger exception in the Bike Index app — pull the fault, read its backtrace, find the offending code, write the fix. Trigger whenever a request names one Honeybadger error: a pasted fault URL (`app.honeybadger.io/projects/…/faults/…`), a fault ID, an error class plus "in production" (`Vips::Error`, `NoMethodError in AfterStolenRecordSaveJob`), or phrasings like "fix this Honeybadger error", "why is this erroring in prod", "what's causing this exception", "look at this HB fault". Use `bin/binx_hb` for fault and notice detail; it is the only Honeybadger reader this repo uses. Not for a broad production health sweep across many sources, and not for reading raw log files (that's production-log-inspection).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Bike Index conventions for browser specs (`type: :system, :js`) — **drive every step through the real UI** (no FactoryBot or `execute_script` shortcuts to skip what a user would do), every example pays a browser boot cost so bias toward fewer, denser examples that walk through state via clicks, prefer named-element matchers over CSS selectors, and combine same-setup work into one `it` even when scenarios feel independent. **Consult this skill any time you create or modify a `:js, type: :system` spec** — that includes everything under `spec/integration/` AND component system specs at `spec/components/**/*_system_spec.rb`. Read alongside the `rspec-testing` skill for the project's general `context`/`let` style.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

bikeindex의 스킬 모두 보기

이 스킬의 문제 신고