Skip to content

Releases: PlexiOSS/Omniplex

v0.2.0

Choose a tag to compare

@CodeMeAPixel CodeMeAPixel released this 16 Aug 06:09
b48eeac

Added

  • Admin Search (/admin/search) now covers every entity type bots,
    servers, packs, teams, and users instead of just bots and servers,
    each with its own Actions menu (backed by Popplio's newly-extended
    SearchEntitys).
  • A /staff knowledge base section (redirects to a new staff KB
    category) covering the real staff hierarchy, the full permissions
    reference, how reports/tickets/applications actually reach staff, and
    staff conduct/transparency all sourced directly from the live
    staff_positions table and Popplio's permission catalogue, not
    guessed. Linked from the footer.
  • Public user profiles (/user/[id]) now show a user's servers and every
    public link they've added, not just Bots and a hardcoded website/GitHub
    pair. New shared TeamCard component (also now used on the dashboard's
    Teams tab, replacing a near-identical inline copy) so Teams can be
    shown too. The "hasn't listed anything" empty state now checks bots,
    servers, packs, and teams together instead of just bots.
  • Report detail (/admin/reports) now shows the actual bot/server/pack/team
    the report is about — icon, name, and a link straight to its listing —
    instead of just the raw target type/id. An "Actions" button next to it
    loads Arcadia's staff RPC methods filtered to whatever that target type
    actually supports (e.g. force-removal for bots) via the new, reusable
    GenericRpcModal, so resolving a report and actually acting on the
    reported content no longer requires leaving the modal.
  • "Platform safety" stats (banned users, vote-banned bots) on the
    Moderation Transparency page (/about/moderation), backed by Popplio's
    extended GET /list/stats. Styled as its own card-grid section,
    matching the existing "Bot review pipeline" section the reports table
    itself is unchanged.
  • A "Support Tickets" check on the Status page (/about/status), backed
    by the public GET /tickets/topics endpoint.

Fixed

  • Team/server/bot avatar and banner updates weren't reflecting instantly
    after upload — Next's image optimizer was caching the old asset
    in front of already-correct origin cache headers. Avatar/Banner now
    render with unoptimized, since every source is already our own CDN
    proxy or Discord's hash-versioned CDN.
  • The dashboard's profile editor (EditProfileTab) had its own,
    slightly-different links list (different remove icon, different "Add
    link" button style) instead of the shared LinksEditor component every
    other edit form already uses — now reuses it.

Changed

  • Admin panel nav decluttered: Queue, Applications, Reports, and Tickets
    are now grouped under a single "Moderation" dropdown instead of four
    separate top-level links.
  • Dashboard bot/server cards moved the "Upgrade" and "Shop" actions into
    the existing "..." menu, keeping only View/Edit inline, to cut down on
    how crowded each card had gotten.
  • API Tokens tab (TokenManager) now puts the "Create Token" button and
    count at the top, with the create form appearing directly below it
    instead of at the bottom of the list; button variant matched to the
    secondary convention used by Teams/Packs/Applications.
  • Security tab cards given filled backgrounds and the same heading
    weight/size as the rest of the dashboard, and laid out side-by-side on
    wide screens instead of stacked in a narrow column.
  • Consistency pass across the admin panel: list spacing, card padding, and
    hover treatment brought in line across Applications, Queue, and Tickets;
    removed the deprecated, permanently-zero "Changelogs" stat from the
    admin Overview page; Dashboard Overview's stat tiles restyled to match
    the admin panel's icon+label convention.

v0.1.4

Choose a tag to compare

@CodeMeAPixel CodeMeAPixel released this 15 Aug 23:06
eb04017

Fixed

  • The Exit Panel button was desktop-only (hidden md:block) and, on
    mobile, only reachable by opening the hamburger menu — not a persistent,
    obvious way back to the main site from anywhere in the admin panel.
    Replaced with an always-visible icon button in the header's icon row
    (same treatment as Customize/notifications/theme), on both desktop and
    mobile.

Added

  • /admin/tickets — a staff ticket queue, filterable by open/closed. The
    API and even a working staff-capable thread view already existed
    (/tickets/{id} already grants any staff member with view_tickets
    view/reply access, and manage_tickets for reopening — confirmed by
    reading get_ticket's existing owner-or-staff check), so this just adds
    the missing "find a ticket to act on" step: list view backed by
    Popplio's new GET /staff/tickets, each row linking straight into the
    existing /tickets/{id} page rather than a new detail view.

v0.1.3

Choose a tag to compare

@CodeMeAPixel CodeMeAPixel released this 15 Aug 21:51
14f5127

Added

  • A "Security" tab on the dashboard (src/app/dashboard/SecurityTab.tsx)
    exposing Popplio's data-export/account-deletion pipeline
    (POST /users/{id}/data), which existed server-side with zero frontend
    consumer until now — closes the loop on the Privacy Policy's "Your
    rights" section, which previously only pointed at a support ticket for
    something that can be self-service. Download builds a per-table
    row-count summary plus a client-side JSON download from the completed
    task's output; deletion requires typing your exact username in a modal
    before it's enabled, since it's a real, irreversible
    DELETE FROM users. Both poll GET /users/{id}/tasks/{tid} every 2s
    (task id/key persisted to localStorage so a page refresh mid-poll
    resumes instead of losing the reference), capping at 5 minutes before
    telling the user to check back later rather than erroring.

  • Vanity URL self-management: BotEditModal/ServerEditModal gained a
    "Vanity URL" field wired to PATCH /{target_type}/{target_id}/vanity
    (vanityResource.update), previously a read-only value in the UI
    despite the endpoint existing. Server-side validation errors (taken,
    blacklisted, contains @) are surfaced verbatim rather than
    reimplemented client-side.

  • A "Recent voters" section (src/components/votes/VoterList.tsx) on bot
    and server pages, backed by the public
    GET /{target_type}/{target_id}/votes/user-list endpoint (bare Discord
    snowflakes, no auth needed) which had no frontend consumer before this.
    Resolves the first 12 voters to a username/avatar via users.getUser
    (Promise.allSettled, falls back to the raw ID if resolution fails for
    any one voter) with a "+N more" tail count from a real paginated total.

  • A staff "Applications" review page (/admin/applications) for the 7
    positions registered in Popplio's /apps system (certification,
    partnership, server certification, staff, ban appeals, etc.) — the
    PATCH /staff/apps/{id} approve/deny endpoint had no staff-facing UI
    anywhere before this, not even in Arcadia as far as this workspace can
    tell. Required adding a new Arcadia RPC wrapper,
    arcadia.popplioStaff() (src/lib/arcadia/client.ts), mirroring
    Popplio's own popplioStaff proxy action
    (popplio/arcadia/panel/ops_proxy.go) that relays a request into
    Popplio's legacy-header-gated /staff/* API and returns its status/body
    verbatim — this wasn't hand-ported into Omniplex's Arcadia client until
    now, so nothing could reach /staff/apps* at all despite the backend
    bridge already existing. Approve/deny is otherwise fully
    server-side-driven (grants/unbans happen inside Popplio's own handler);
    the page only submits {approved, reason} and refetches.

  • A self-hosted Legal hub at /legal, replacing the Footer's links out to
    nodebyte.co.uk/legal/*. Four documents written fresh for what Omniplex
    actually does rather than adapted from the parent brand's general-purpose
    pages: Terms of Service, Privacy Policy, Acceptable Use (the single
    authoritative version of conduct rules that were previously scattered
    across a few KB articles), and a Service Agreement covering premium/shop
    purchases and refunds. Same markdown+frontmatter pattern as the
    Knowledge Base (gray-matter, rendered through the existing Markdown
    component), but flat (src/content/legal/*.md/legal/[slug]) since
    there's no category nesting to model. Two KB articles
    (bots/rules.md, servers/listing-rules.md) already linked to
    /legal/terms as if it existed; that link now resolves instead of
    404ing. Added to the sitemap alongside everything else.

  • The Friday-Sunday double-vote weekend bonus is now actually visible:
    VoteButton/ServerVoteButton show a "Double-vote weekend" banner
    above the vote buttons when it's live and the entity isn't premium
    (premium already gets a flat shorter cooldown instead). The bonus check
    now reads UTC (getUTCDay()) rather than the viewer's local day, to
    match Popplio's now-explicit UTC pinning (see Popplio's changelog) —
    previously the local-time check could disagree with the server near a
    day boundary depending on the viewer's timezone. Voting Rules also now
    states the boundary is UTC, not just "Friday through Sunday".

  • Premium and Shop now work for servers, matching bots (backend change,
    see Popplio's changelog for the full breakdown — servers previously had
    a premium field and a "Certified" badge with no way to actually earn
    either):

    • /premium and /shop both gained a Bot/Server toggle; picking Server
      lists servers from your teams instead of your own bots, and every
      checkout/purchase call now sends the target type through.
    • ServerCard, the server detail page, and the dashboard's server
      cards all get the same Supporter badge / Vote Blitz banner / Upgrade
      • Shop buttons bots already had.
    • /apps gained a "Server Certification" position alongside the
      existing bot one.
  • Certification requirements got more lenient and multi-metric instead of
    a strict two-thresholds-at-once bar (see Popplio's changelog) —
    Certification and Partner Requirements in the Knowledge Base rewritten
    to match, and to note certification now covers servers too.

  • Knowledge Base coverage for everything shipped this cycle that had none:
    three new categories — Account (Alerts & Push Notifications, Vote
    Reminders), Premium & Shop (Premium Plans & Checkout, Vote Credits &
    the Shop), Support (Support Tickets) — plus a new How to Apply
    article in Programs covering the /apps mechanics that Certification
    and Partnership used to each describe informally. Also fixed three
    articles that had gone stale from earlier work this cycle:
    Partnership's "How to apply" still pointed at Discord instead of the
    in-app form, Voting Rules' "Vote credits" section predated the Shop and
    called credits opt-in (they're not), and Getting Started's pack step
    only described bot packs, not the server/emoji pack types packs have
    supported for a while.

  • Home page rebalanced toward servers, which previously only got one
    section (Top Servers) against four bot-only ones:

    • The hero headline now rotates through "bots" / "servers" / "packs"
      (RotatingWord, crossfades in place with no layout shift, extra
      words are a one-line addition later) instead of hardcoding "bots".
    • HomeTabs gained a Bots/Servers toggle alongside its existing
      Top Voted/New/Most Viewed tabs, using server index data
      (servers.getIndex()) that was already being fetched but mostly
      unused.
    • Certified and Premium sections (previously bot-only, with servers'
      certified/premium data fetched but never shown) are now a single
      "Spotlight" block using the same toggle, replacing three separate
      sections with one.
    • The standalone "Top Servers" section was removed since the Bots/
      Servers toggle on the main tabs now covers the same ground.
    • The main tabs gained a "Random" tab backed by Popplio's /bots/@random
      and /servers/@random (both existed already; bots.getRandom() was
      even already written but never called anywhere, and there was no
      servers.getRandom() at all until now). Re-rolls client-side on every
      visit to the tab, with a manual shuffle button to draw again.
    • The home page's "Packs" section (renamed from "Bot Packs", since packs
      have supported bot/server/emoji for a while) and the Featured Bots
      section were showing only 6 cards despite Popplio returning up to
      9/12 — now show 9, matching the Top Voted/Certified/Premium tabs,
      which were already at 9 on both ends.
  • Moderation Transparency page now shows a bot review pipeline (Approved /
    Certified / Awaiting Review / Denied) alongside the existing report
    counts. Popplio's /list/stats gained total_pending_bots and
    total_denied_bots to back it — everything else on the page was already
    public data, this just closes the last gap.

  • The "Bots" stat on the home page and the "Listed Bots" / "Total
    Submitted" stats on the About page now consistently read total_bots
    every bot ever submitted, not just the approved ones — so the same
    number shows everywhere instead of quietly differing by page.

  • Applications — staff, dev team, partnerships, and certification have had
    a full submit-and-review pipeline in Popplio that nothing in Omniplex
    ever surfaced. New frontend-only surface:

    • /apps lists open positions pulled live from Popplio (tags, a short
      teaser, closed/open state).
    • /apps/[id] renders each position's full description and a form built
      dynamically from its question set (short answers vs. long-form,
      matching the backend's own length rules so validation errors are rare
      by the time it hits the server).
    • A new "Applications" tab on the dashboard lists everything a user has
      submitted, with state (Pending/Approved/Denied) and any staff feedback
      once reviewed.
  • Premium Popplio's Stripe/PayPal checkout and booster-offer redemption
    have been fully wired backend-side with nothing in Omniplex to start a
    purchase. New:

    • /premium lists the Bronze/Silver/Gold plans, lets you pick one of
      your own approved/certified, not-yet-premium bots, and pay with card
      (Stripe Checkout) or PayPal — both just redirect to the provider's
      hosted checkout, no card data ever touches Omniplex. Server boosters
      get an extra "redeem free" option on the Bronze plan.
    • /payments/success and /payments/cancelled — Popplio's Stripe and
      PayPal flows redirect back to these by hardcoded URL, so they had to
      exist for checkout to complete at all.
    • An "Upgrade" button on eligible bots in the dashboard's Bots tab links
      straight into /premium with the bot preselected.
  • Shop — vote...

Read more

v0.1.2

Choose a tag to compare

@CodeMeAPixel CodeMeAPixel released this 14 Aug 22:11
fc420de

Added

  • Packs now come in three flavors — Bot, Server, and Emoji — instead of
    bots-only. /packs/add gains a pack-type selector as its first step;
    bot/server packs reuse the existing search-and-pick flow restricted to
    one type at a time, while emoji packs get a new upload sub-flow
    (EmojiPackBuilder.tsx, up to 50 emojis, 256KB each, static or animated
    GIF) built on the existing /api/uploads gateway (new pack-emoji kind,
    gated by a new edit_packs permission check against Popplio). Emoji
    images live at a deterministic CDN path (packEmojiUrl(), same
    convention as bannerUrl()) rather than a database-stored URL. Pack
    cards, the pack detail page, and the /packs listing (now filterable by
    ?pack_type=) all show a PackTypeBadge and type-appropriate preview.
  • A "Report this pack" flow (components/reports/ReportModal.tsx, built
    generic over target type so bots/servers can reuse it later) for
    flagging license/ToS violations, spam, or anything else — motivated
    specifically by user-created emoji packs raising real rights questions.
    Reports are reviewed by staff only, at a new /admin/reports page
    (status-filterable queue + detail modal with Resolve/Dismiss and an
    optional note) gated on a new review_reports permission — reporter
    identity is visible there and nowhere else; a pack owner never learns
    who reported them, only that a report exists and its reason category.
  • ReportModal rolled out to bot and server detail pages, not just packs —
    it was already built generic over target type for exactly this.
  • An RSS feed for /changelog (/changelog/rss.xml), hand-built (no
    existing precedent in this repo for a manual XML route — sitemap/robots
    use Next's typed MetadataRoute convention, which has no RSS
    equivalent) from the same getChangelogEntries() the page itself uses,
    same 15-minute cache window. Linked from the changelog page header and
    its metadata (<link rel="alternate" type="application/rss+xml">).
  • A "Trending" sort on /bots and /servers, alongside the existing
    newest-first default — ranks by net votes in the last 7 days (via
    Popplio's new ?sort=trending param) instead of raw vote count, so a
    bot/server picking up votes right now surfaces even if its all-time
    total is small.
  • /about/moderation: a public, anonymized breakdown of content reports
    by reason and status (counts only — no report/target/reporter
    identity), backed by Popplio's new GET /reports/stats. Linked from
    /about and the footer, next to the existing status page link.
  • /emojis: a browse page aggregating custom emojis/stickers across every
    server that's opted in to showing them (show_emojis), grouped by
    source server and reusing the existing EmojiStickerGallery card
    treatment. Backed by Popplio's new GET /servers/@emojis, since the
    regular paginated server listing excludes emoji/sticker data entirely.

Fixed

  • Uploaded images (banners, avatars, pack emojis — anything served through
    /cdn/[...path]) could stay visibly stale for up to a day after a
    re-upload: the fixed per-entity URL never changes, but the response was
    cached max-age=3600, stale-while-revalidate=86400, so a browser (or
    anything in front of it) could keep serving the old bytes long after a
    new upload landed. The route now sets max-age=0, must-revalidate and
    compares the request's If-None-Match against RustFS's own ETag (now
    captured in getObject) — an unchanged image gets a bodyless 304 (cheap,
    effectively instant), a changed one gets the new bytes on the very next
    request instead of waiting out the old cache window.

Security

  • /cdn/avatar-mirror/[targetType]/[id]'s ?src= param was passed
    straight to fetch() with no validation (CodeQL js/request-forgery)
    — since this route is public and unauthenticated, anyone could point
    ?src= at an arbitrary internal URL and make the server fetch it, and
    the response would then get putObject'd into the shared bucket at a
    predictable path, serving whatever the attacker's URL returned to every
    future visitor of that avatar. ?src= is now checked against an
    allow-list of exactly cdn.discordapp.com (the only host dovewing ever
    actually resolves an avatar to) before the fetch happens at all, not
    after.

v0.1.1

Choose a tag to compare

@CodeMeAPixel CodeMeAPixel released this 13 Aug 09:02
45e1235

Added

  • New public /changelog page, replacing the old database-backed changelog
    system (popplio's changelogs table, arcadia/panel/ops_content.go's
    updateChangelog RPC, and the ChangelogAction DTOs) — that system was
    already fully dead: the RPC unconditionally returned 403 "not
    implemented", the panel's "Changelogs" stat was hardcoded to 0, and there
    was no route or admin UI on either side. /changelog instead pulls
    releases directly from GitHub (lib/github/releases.ts) for a
    configurable list of repos (lib/github/config.ts — currently Popplio
    and Omniplex itself), merges them into one reverse-chronological
    timeline with a per-repo filter, and renders each release's body through
    the existing sanitized Markdown component. No new database or admin
    surface — GitHub Releases is the source of truth now, cutting a release
    there is the entire authoring flow. Cached for 15 minutes
    (next: { revalidate: 900 }) to stay off GitHub's unauthenticated rate
    limit without needing a redeploy to pick up a new release; set
    GITHUB_TOKEN (server-only) to raise that limit if it's ever hit.

  • Real image hosting, replacing the informal legacy-CDN-path guessing used
    everywhere so far (bannerUrl/partnerAvatarUrl/teamAvatarUrl
    previously just hoped a file existed at a fixed path, with no way to add
    new ones). The old on-disk cdn.omniplex.gg static files were migrated
    into a private RustFS (S3-compatible) bucket; since it's private, none of
    it is reachable directly, so everything now goes through two new
    same-origin proxy routes that hold the only S3 credentials (server-side
    only, never shipped to the client):

    • /cdn/[...path] — serves uploaded assets (partner logos, team
      avatar/banner, bot/server banner) straight from the bucket.
    • /cdn/avatars/{bots,servers}/[id] — bot/server avatars are Discord's
      own, synced live via dovewing/Infernoplex, not an upload; this mirrors
      a copy into the bucket on first request and re-serves it for 24h
      before quietly re-mirroring, cutting down on repeated live hits to
      Discord's CDN across every card/avatar in the app.
    • A new /api/uploads route backs real upload UI in the admin partner
      editor, team settings (avatar + banner), and the bot/server edit
      modals (banner). Every upload re-verifies identity and the specific
      permission needed server-side before writing a single byte — a staff
      loginToken checked via arcadia.hello for partner logos, or a user
      session token checked via POST /auth/test plus Popplio's entity-perms
      lookup for everything else — since the client-side hasPermString
      checks that gate the upload buttons were only ever a UI hint, not a
      security boundary.
  • The Customize panel is now tabbed (Colors / Fonts / Layout / Content)
    instead of one long stacked list, and grew three new levers:

    • Colors — 5 more accent options (cyan, teal, lime, red, pink), 12 total.
    • Fonts — added Inter and Space Grotesk alongside the existing four.
    • Layout — Compact/Comfortable/Wide page width, applied through a
      --container-max CSS var so it works on server-rendered pages too
      (Container reads the var instead of a fixed max-w-7xl).
    • Content — a "Hide NSFW content" toggle that removes nsfw-flagged
      bots/servers from every browse/search/profile listing site-wide, via a
      data-nsfw attribute on BotCard/ServerCard/PackCard and a plain
      CSS rule ([data-hide-nsfw="true"] [data-nsfw="true"] { display: none })
      — no per-page filtering logic needed. Detail pages are unaffected by
      design (this hides cards from browsing, not a page someone linked
      directly). A "disable cookies" option was requested alongside it but
      skipped: Omniplex doesn't set any analytics/tracking cookies to begin
      with, only the session cookie sign-in itself requires, so there'd be
      nothing for the toggle to actually do. Alongside it, a "Blur NSFW
      thumbnails" toggle (on by default) blurs just the avatar/banner images
      on nsfw-flagged cards via [data-blur-nsfw="true"] [data-nsfw="true"] img { filter: blur(...) }, leaving the title/description legible. It's
      disabled in the UI (and its applied state forced off) whenever "Hide
      NSFW content" is on, since there's nothing left to blur once nsfw cards
      never render at all.
  • Banner images for bots, servers, and teams (BotCard/ServerCard, plus
    the bot/server/team detail pages). Popplio's live API has no banner
    field at all any more — Popplio's own conformance notes confirm the whole
    CDN-upload pipeline it depended on was removed — but a historical
    one-time migration left every existing banner sitting at a fixed CDN path
    keyed by the entity's own ID (banners/{bots,servers,teams}/{id}.webp),
    discovered from that migration script since Popplio's API no longer
    advertises it anywhere. New bannerUrl() builds that URL; new Banner
    component renders it and falls back to a themed gradient (using the
    viewer's own accent color, so it tracks Customize) for anything that 404s
    or never had one uploaded — same idea as the existing partner-avatar CDN
    fallback.

  • Webhook management for bots and servers, from a new "Webhooks" dashboard
    dropdown item on each listing: create/edit/delete webhooks (HMAC, simple
    secret, or legacy auth), pick an event whitelist, send test deliveries
    with dynamically-rendered variable inputs per event type, and browse
    paginated delivery logs. Built entirely on existing Popplio webhook
    routes that had no Omniplex UI before now.

  • A "Change Team" dashboard action for bots, using Popplio's
    PATCH /users/{uid}/bots/{bid}/teams, letting an owner move a bot to any
    other team they have "Add Bots" on. Servers have no equivalent transfer
    endpoint in Popplio, so this is bots-only for now.

  • A public /partners page — the GET /list/partners client and types
    already existed (used on the homepage) but nothing ever linked to a
    dedicated page. Groups partners by partner type, shows their links and
    (if set) a direct link to their bot listing.

  • The main header nav gets the same dropdown-grouping treatment as the admin
    one: Bots/Servers/Packs collapse into "Browse", and Blog/Partners/
    Documentation/About — previously footer-only — collapse into "Community",
    reachable from anywhere now instead of just the footer.

  • Public and admin Search both pre-fill with real content on load instead of
    a blank page: admin search runs an empty query (which matches everything)
    on mount and on target-type switch; public search browses the full
    bot/server listing (real backend pagination via /bots|servers/@all)
    until a query or tag is submitted, at which point it switches to paginated
    search results (client-side, since /list/search has no server-side
    pagination).

  • Three new staff admin sections, backed by Arcadia panel RPC methods that
    already existed in Popplio but had no Omniplex UI at all:

    • Blog (/admin/blog) — full list/create/edit/delete for posts on the
      public /blog section, using the UpdateBlog RPC (manage_blog).
      New posts publish immediately; existing ones can be toggled to draft.
    • Partners (/admin/partners) — full CRUD for featured partners
      (UpdatePartners, manage_partners), including link validation
      (must be https://). Partner types aren't manageable from here yet —
      there's no RPC for creating one, only for assigning an existing type
      to a partner.
    • Disciplinary Types (/admin/staff/disciplinary-types) — full CRUD
      for staff warning/suspension templates (UpdateStaffDisciplinaryType,
      manage_disciplinaries): self-assignable, additory, needs-approval,
      max expiry, and a permission-limit picker reusing ArcadiaPermSelector.

    Two other backend-ready gaps were identified but deferred (larger scope):
    staff application review (GET/PATCH /staff/apps*) and the shop/economy
    admin surface (vote-credit tiers, shop items, item benefits, coupons,
    bot whitelist — five separate CRUD areas under ops_shop.go).

  • A "Test" button on a freshly created token, using Popplio's existing
    POST /auth/test to confirm it actually authorizes before dismissing it —
    disabled for now pending a Popplio deploy (see Popplio's changelog for the
    bug that endpoint needed fixed first).

  • API token management, backed by Popplio's existing (previously unexposed
    on the frontend) generic /{target_type}/{target_id}/sessions endpoints:
    a new "API Tokens" dashboard tab for a user's own personal tokens, and a
    "Tokens" button on bot/server cards (visible to team members with
    view_sessions/manage_sessions) for tokens scoped to that bot or
    server. Supports creating a token with a name, expiry, and an optional
    restricted permission set (via the same PermSelector used for team
    member permissions), and revoking existing ones. A newly created token's
    raw value is shown exactly once, since Popplio never stores or re-serves
    it after creation.

  • Votes now go through Popplio's new self-hosted proof-of-work captcha
    (see Popplio's changelog) automatically, when the bot/server hasn't opted
    out via captcha_opt_out. useVote fetches a challenge, solves it
    client-side with crypto.subtle (lib/captcha/pow.ts), and submits the
    solution alongside the vote; both vote buttons show "Verifying…" while
    that's in progress. No user-facing setup — it's invisible on a successful
    vote and only costs a brief moment of CPU work.

Changed

  • Homepage, bot/server index/listing/detail pages, and blog list/post pages
    now fetch with cache: "no-store" instead of Next's ISR (revalidate)
    — blog posts in particular had crept to a 1-hour window, meaning an edit
    or correction could take up...
Read more

v0.1.0

Choose a tag to compare

@CodeMeAPixel CodeMeAPixel released this 05 Aug 00:47

Added

  • Downvotes: bot and server vote buttons now both show an upvote and a downvote control (bots previously only supported upvoting, both on the API and in the UI — see the matching Popplio change).
  • Statistics: bot and server owners/team members can now view a "Stats" panel from the dashboard, showing votes, page views, invite clicks and (for bots) uptime check results — data the API already returned but the frontend never surfaced.
  • A "Create" menu in the header (Add a Bot/Server/Pack, Create a Team), so those entry points are reachable from anywhere on the site, not just the footer and dashboard.
  • Team management: Add Bot and Add Server now let you choose which of your existing teams (that you have the relevant add_bots/add_servers permission on) should own the new listing, instead of always creating a brand-new team. A new /teams/add page lets you create a team directly, linked from the dashboard's Teams tab and the footer. Since team names aren't unique, the picker shows each team's avatar and member/bot/server counts to tell same-named teams apart, and gains a search box once you have more than a handful of eligible teams.
  • Knowledge base (/kb) section, with guide articles ported from the legacy
    site: Getting Started, Server Listing Rules, Pack Rules, Voting Rules & FAQ,
    and Partner Requirements.
  • Full staff admin panel (/admin), backed by the Arcadia panel API:
    • Discord OAuth2 login with mandatory TOTP MFA.
    • Bot Queue with quick actions (Claim/Unclaim/Approve/Deny), a generic
      dynamic-form modal covering every other RPC action, submission-order
      position numbers, and safe (no-permissions) vs. submitted invite links
      shown side by side.
    • Global entity Search (bots/servers) with the same action modal.
    • Staff Positions and Staff Members management, with hierarchy-aware
      edit/delete locking.
    • A live + hand-maintained permission catalog and selector for granting
      staff permissions.
    • Pagination on the queue, search results, staff members list, and RPC
      audit log.
    • Overview page (/admin) summarizing bot/server/ticket counts, total
      users, and changelog count via Arcadia's BaseAnalytics. The Bot Queue
      moved to /admin/queue.
    • Bot Queue now resolves claimed_by Discord IDs to usernames via
      Arcadia's GetUser, instead of showing the raw ID.
  • Reviews: star ratings and threaded replies on bots and servers, full
    create/edit/delete for the review's author, and a read-only view for staff
    in the admin panel.
  • Packs can now include servers alongside bots, and any existing bot or
    server can be added to a pack regardless of who owns it — packs are
    curated lists, not ownership-restricted.
  • Bot presence indicator (online/idle/dnd/offline) on bot cards and the bot
    detail page, sourced from a bot's self-reported status.
  • /about/status now also monitors Packs, Blog, Search, and the Staff Panel
    API, on top of the existing checks.
  • A reusable multi-link (extra_links) editor, wired into the bot add/edit
    forms and the new server add/edit forms — previously only a single
    synthetic invite link could ever be sent.
  • A working "Add a Server" flow: paste a Discord invite link and the server
    is resolved and listed automatically. The previous version of this page
    called a backend endpoint that didn't exist.
  • A dashboard "Servers" tab and ServerEditModal for managing servers owned
    by a team you belong to.
  • Widget embed system (Markdown/HTML/URL snippets, customizable stats and
    colors) for bots, servers, and packs.
  • The bot and server add forms now link to the relevant Knowledge Base rules
    (Bot Rules, Page Rules, Server Listing Rules) before submission.
  • The staff Member edit modal now shows a member's positions and their full
    resolved permission set (positions + overrides combined), not just the
    override layer being edited.
  • Add Bot and Add Server are now step-based flows, ported from the legacy
    site's pattern and extended with a confirmation step: enter an ID/invite
    and look it up, and a preview card shows the bot's real Discord
    name/avatar/server count/flags (or the server's name/icon/member counts)
    with a "Looks right — continue" / "Change" choice before the rest of the
    form unlocks — instead of blindly trusting whatever the submitter typed.
    Add Bot also carries over the legacy site's already-listed/not-public
    checks and the fallback_bot_id recovery path for when the anti-abuse
    provider is down.
  • Add Bot and Add Server drafts are now persisted to localStorage, scoped
    to the signed-in user (usePersistedFormDraft), so an in-progress
    submission survives not just a refresh but closing the browser entirely.
    Unlike the legacy site's single global draft key, drafts are namespaced
    per user so they can't leak between accounts on a shared browser, and
    they're cleared automatically on a successful submit.
  • Server owners can opt in ("Show this server's emojis & stickers") to
    displaying their server's custom emojis and stickers on its listing page,
    via a new toggle in ServerEditModal. The gallery only renders when the
    owner has opted in and there's actually synced data to show — nothing
    appears while the tracking bot isn't a member of the server.
  • Add Server now warns (without blocking submission) when the tracking bot
    isn't currently a member of the server being added, with a direct invite
    link — several features (emoji/sticker sync, real invite generation, live
    member counts) silently never work otherwise, and previously nothing told
    the owner why.

Changed

  • TagPicker now always shows a listing's actual tags as removable chips,
    even when they fall outside the curated suggestion list, and supports
    adding free-form custom tags — tags were never restricted to an enum on
    the backend, so the old fixed-list picker could silently make existing
    tags disappear from the editor.
  • PermSelector and ArcadiaPermSelector now surface any granted
    permission that isn't in their known catalog instead of hiding it
    entirely, so a permission the UI doesn't recognize is still visible and
    removable.
  • ArcadiaPermSelector checkboxes now reflect a member's fully resolved
    permissions (position grants combined with overrides), not just the raw
    override array — a permission granted through a staff position now shows
    as checked (labeled "via position"), and unchecking it correctly emits an
    explicit per-member revoke (~permission) instead of doing nothing.
  • Admin panel navigation is now part of the site's main header instead of
    running as a separate nav bar — one drawer-style menu across the whole
    site, admin section included, with an automatic "Staff panel" shortcut
    for staff and an "Exit staff panel" action while inside it.
  • Homepage and About page bot totals now include certified bots, not just
    approved ones, so the two pages no longer disagree with each other.

Fixed

  • The entire frontend permission system was still built for Popplio's old
    namespace.action model (dotted strings, * wildcards, ~ negators,
    global.* for "grants everything") after the backend moved to flat,
    self-describing permission names (edit_servers, manage_webhooks,
    owner) with no namespaces, wildcards or negation. Every permission
    check across the team and staff/admin panel UI was comparing against
    names that no longer exist, so team owners (and staff) with correct
    permissions server-side could still be denied client-side, or see broken
    panels:
    • lib/permissions.ts rewritten for flat exact-match, with owner/
      administrator as the two domain "super" permissions that imply
      everything (was reimplementing full namespace/wildcard/negator parsing).
    • Every literal permission string across dashboard, teams/[id],
      teams/[id]/settings, and the /admin staff pages (positions, queue,
      members) updated to its flat equivalent (e.g. team_member.add
      add_team_members, rpc.Claimreview_bots, global.*owner).
    • PermissionData (the shape of GET /teams/meta/permissions and
      GET /staff/meta/permissions) still had the old kittycat fields
      (supported_entities, data_override); the real response is
      {id, name, desc, category, dangerous}. This was the direct cause of
      TypeError: s.supported_entities is not iterable crashing the team
      settings page — something iterated a field that no longer exists.
    • PermSelector and ArcadiaPermSelector rewritten to group by the new
      category field instead of a namespace derived from
      supported_entities, and to toggle flat permission ids directly
      instead of building namespace.perm keys.
    • ArcadiaPermSelector additionally dropped negation support
      (~permission) entirely — the new model's overrides are purely
      additive (nothing subtracts from the union), so revoking a
      position-granted permission from a specific member is no longer
      possible from this editor; it now shows those as read-only ("via
      position") instead of offering a toggle that would silently do nothing.
    • Removed lib/arcadia/permissionCatalog.ts, a hand-maintained list of
      every permission string that existed because standalone Arcadia had no
      live catalog endpoint. Now that Arcadia is merged into Popplio, both
      GET /teams/meta/permissions and GET /staff/meta/permissions are
      real live endpoints (new staff API resource added), so the staff
      panel's permission pickers can't drift out of sync with the server the
      way the static list could.
  • Server avatars showed the initials fallback everywhere (server cards,
    detail pages, widgets, OG images, pack pickers) — IndexServer.avatar was
    still typed and handled as AssetMetadata (the old CDN-asset shape from
    before that sy...
Read more