Skip to content

Administration

Seed the first admin, grant superadmin, control registration, manage users and groups with storage quotas, and inspect the database.

Seed the first admin

On every startup the server calls an idempotent seedAdmin routine using auth.adminUsername and auth.adminPassword:

KeyEnv fallbackDefaultBehavior
auth.adminUsernameKALENDEE_ADMIN_USERNAMEadminUsername to create or promote.
auth.adminPasswordKALENDEE_ADMIN_PASSWORD(blank)When blank, seeding is skipped entirely.
auth.superadminUsernameKALENDEE_SUPERADMIN_USERNAME(blank)Existing user to grant superadmin (see below).

The routine:

  • creates the user as an admin if it does not exist;
  • changes its password if the configured value no longer matches;
  • promotes it to admin if it exists without admin rights.

Because it runs on every startup, it is also the supported way to reset the admin password: set auth.adminPassword to a new value, restart, then remove the value from the environment if you do not want it retained.

The username must match Kalendee’s account rules (3–32 characters, start with a letter or digit, letters/digits/./_/-, stored lowercase), and the password must be 8–128 characters. An invalid value aborts startup with an Invalid error.

If you never set an admin password, the first user to register becomes an admin (see Registration policy). See Accounts and security for the user-facing model.

Superadmin

A superadmin is an admin who cannot be demoted by other admins. Set auth.superadminUsername (env KALENDEE_SUPERADMIN_USERNAME) to an existing username; at startup the server sets both is_admin and is_superadmin on that user. The user must already exist — the module promotes, it does not create.

Authorization rules enforced by the server:

  • Only a superadmin can demote another admin, delete a superadmin, or modify a superadmin’s account.
  • A superadmin cannot be demoted, including by another superadmin.
  • No admin can remove their own admin rights.
  • Admins are members of the system admin group automatically.

Keep the superadmin username out of the general config if possible; it is a privileged identity. All admins can manage users, calendars, and groups through the API; the superadmin difference is only about demotion/deletion.

Registration policy

auth.registration (env KALENDEE_AUTH_REGISTRATION) accepts:

ValueMeaning
first-user (default)Public registration is open only while the user table is empty. Seeding an admin closes it.
openAnyone may register.
closedRegistration is disabled; admins create accounts.

Admins can override the configured policy at runtime from the admin UI (/admin), which writes an app_settings row (key registration, oauth_registration, or the email-verification policy). The database override wins over the HOCON value. To return to the file-based policy, clear the corresponding app_settings row.

Related settings:

KeyValuesDefaultEffect
auth.emailVerificationrequired, optional, offoptionalWhether new accounts must verify an email address.
auth.emailVerificationTtlHoursinteger hours24Verification link lifetime.
auth.oauthRegistrationtrue / falsefalseWhether OAuth sign-ins may create accounts. Still gated by the registration policy.

required means an email address must be supplied and verified before the account can be used; this needs working mail. See Email.

Users and invitations

There is no separate invite system. To let someone in, either open registration temporarily, ask them to register and then close it, or create the account for them.

Admins manage users in the admin UI at /admin or through the JSON API:

ActionAPI
List usersGET /api/v1/admin/users
Edit a user (display name, email, password, admin flag)PATCH /api/v1/admin/users/{id}
Delete a userDELETE /api/v1/admin/users/{id}
List all calendarsGET /api/v1/admin/calendars
Delete any calendarDELETE /api/v1/admin/calendars/{id}
Toggle a calendar’s public linkPATCH /api/v1/admin/calendars/{id}

Editing an email address clears its verified flag and sends a new verification mail. Deleting a user cascades to their sessions, calendars, events, shares, and connections. An admin cannot delete themselves.

Groups and storage quotas

Kalendee has two system groups and any number of custom groups:

GroupMembershipNotes
defaultEvery user, implicitlyCannot be deleted or renamed. Its quota applies to everyone as a baseline.
adminEvery admin, kept in sync with the admin flagCannot be renamed or edited as a normal group.
Custom groupsAssigned by an adminName up to 64 characters (A–Z, 0–9, space, ., _, -).

Quotas are storage quotas, and today they cover avatar bytes only (users.avatar_bytes). The effective quota for a user is the minimum of the default group’s quota and every explicit group quota that has a value; a NULL quota means “no limit from this group”. Admins and superadmins are exempt and always unlimited.

  • A quota of NULL (unset) on default and all groups means unlimited storage.
  • Set a quota on default to cap every non-admin by default.
  • A smaller quota on a specific group tightens the cap for its members.

Manage groups via the admin UI or the API:

ActionAPI
List groupsGET /api/v1/admin/groups
Create a groupPOST /api/v1/admin/groups with { "name": "...", "storageQuotaBytes": 104857600 }
Update name/quotaPATCH /api/v1/admin/groups/{id} (clearQuota: true removes the limit)
Delete a groupDELETE /api/v1/admin/groups/{id}
List membersGET /api/v1/admin/groups/{id}/members
Replace membersPUT /api/v1/admin/groups/{id}/members with { "userIds": ["..."] }

storageQuotaBytes is a byte count; 104857600 is 100 MiB. Uploading an avatar that would exceed the effective quota returns 403 storage quota exceeded.

Inspecting the database

Use the database directly for diagnostics, not for routine administration. With Compose:

docker compose exec postgres \
    psql -U "${POSTGRES_USER:-kalendee}" -d "${POSTGRES_DB:-kalendee}"

Useful queries:

-- Users, admin/superadmin flags, verified email, avatar usage.
SELECT username, display_name, is_admin, is_superadmin, email_verified, avatar_bytes
FROM users ORDER BY created_at;

-- Runtime setting overrides written by the admin UI.
SELECT key, value FROM app_settings;

-- Applied migrations.
SELECT version, description, success, installed_on
FROM flyway_schema_history ORDER BY installed_rank;

-- Groups and quotas (NULL = unlimited).
SELECT name, is_system, storage_quota_bytes FROM user_groups ORDER BY name;

-- Members of a group.
SELECT u.username FROM users u
JOIN user_group_members m ON m.user_id = u.id
JOIN user_groups g ON g.id = m.group_id
WHERE g.name = 'staff';

Granting admin or superadmin directly in SQL bypasses startup logic; prefer the environment variables and a restart so the in-process group sync runs:

UPDATE users SET is_admin = TRUE WHERE username = 'alice';
UPDATE users SET is_admin = TRUE, is_superadmin = TRUE WHERE username = 'root';

Common tasks

TaskHow
Reset the admin passwordSet KALENDEE_ADMIN_PASSWORD to the new value and restart.
Create another adminAdmin UI → edit the user → admin; or set the target’s is_admin.
Close registrationAdmin UI toggle, or set auth.registration = "closed".
Cap storage for everyoneSet a quota on the default group.
Re-open a locked-out accountReset the password via the admin UI.
Recover from a lost KALENDEE_SECRET_KEYNot possible for existing tokens; users must re-link external calendars.

Edit this page on GitHub