Administration
Who can administer a club server?
club uses a role hierarchy (highest first):
| Role | Can do |
|---|---|
owner | Everything, including promoting and demoting admins. Exactly one per server (created during the setup wizard). |
admin | Manage users (except owners), moderate packages, manage publishers. |
member | Publish their own packages; manage packages they own. This is the default for self-signup accounts when SIGNUP_ENABLED=true. (Legacy name: editor — accepted as an alias on parse.) |
viewer | Read-only. |
Administrative API endpoints require both an authenticated user whose role is admin or higher, and (for programmatic access) a personal access token whose scope includes admin.
Administering through the web UI
The web UI is the supported way to administer a club server. Sign in as a user with the owner or admin role and you will see the Admin section in the main navigation.
Common tasks:
- Users: invite new users, change roles, disable accounts.
- Packages: discontinue, undiscontinue, or delete packages; reassign ownership.
- Publishers: create publishers (organizations), add members, assign packages to a publisher.
- Audit log: review a per-event log of user/package/publisher actions.
- Server settings: toggle package scoring on or off and pick the default Dart/Flutter SDK install used for analysis. Everything else (
SIGNUP_ENABLED,TRUST_PROXY, storage backends, etc.) is controlled by environment variables and requires a restart.
Calling the HTTP API directly
If you need to script an administrative action, call the HTTP API directly with curl (or any HTTP client) and a personal access token that includes the admin scope.
Creating an admin token
- Sign in to the web UI as an
adminorowner. - Go to Settings → API keys → Create.
- Select the
adminscope and submit. - Copy the
club_pat_...secret on the confirmation screen — it is shown only once.
Using the token with curl
export CLUB_TOKEN=club_pat_yourSecretHereexport SERVER=https://club.example.com
# List userscurl -H "Authorization: Bearer $CLUB_TOKEN" "$SERVER/api/admin/users"
# Disable a user (admin endpoint — PUT with isActive:false)curl -X PUT \ -H "Authorization: Bearer $CLUB_TOKEN" \ -H "Content-Type: application/json" \ -d '{"isActive": false}' \ "$SERVER/api/admin/users/<user-id>"
# Discontinue a package (package-admin endpoint, not /api/admin/*)curl -X PUT \ -H "Authorization: Bearer $CLUB_TOKEN" \ -H "Content-Type: application/json" \ -d '{"isDiscontinued": true}' \ "$SERVER/api/packages/<name>/options"
# Delete a package (admin only)curl -X DELETE \ -H "Authorization: Bearer $CLUB_TOKEN" \ "$SERVER/api/admin/packages/<name>"See the Admin API reference for the full endpoint catalogue.
Refer to the server’s OpenAPI schema (or the packages/club_server/lib/src/api/admin_api.dart source) for the complete endpoint list. All administrative endpoints live under /api/admin/ and are logged to the audit log.
Using the client SDK
For non-trivial scripting, the club_api Dart SDK wraps the HTTP API with typed methods, including admin endpoints. This is usually easier than hand-rolled curl, and re-uses the same client code the web UI and CLI depend on.
import 'package:club_api/club_api.dart';
final client = ClubClient( serverUrl: Uri.parse('https://club.example.com'), token: Platform.environment['CLUB_TOKEN']!,);
// All admin methods live directly on ClubClient (no sub-clients) and// return Map<String, dynamic> — extract fields by key.final response = await client.listUsers();final users = response['users'] as List;for (final u in users) { print('${u['email']} (${u['role']})');}