Users and roles
Flexweg CMS has two roles — admin and editor — plus a special bootstrap admin convention for the very first login. Authentication is delegated to Firebase Authentication; user records (display name, role, locale preferences) live in the Firestore users/{uid} collection.
Roles
admin
Full access:
- Read + write all posts, pages, terms, media
- Manage other users (create, change roles, delete)
- Edit site settings (title, theme, plugins, menus)
- Install / enable / disable / uninstall plugins and themes
- Read / write the
config/flexwegdocument (Flexweg API key)
editor
Content-focused:
- Read + write all posts, pages, terms, media
- Cannot manage other users
- Cannot edit site settings, install plugins, or read the Flexweg API key
The role is stored as users/{uid}.role. New users are created with role: "editor" by default.
The bootstrap admin
The first time you deploy the admin, no users/ documents exist yet. Without special-casing this, no one would be able to log in (since the role check would fail) and no one would be able to create the first user (since that requires admin role).
Solution: the admin pins a single email — set via the VITE_ADMIN_EMAIL environment variable (or via the SetupForm on first run) — that's treated as admin even without a Firestore user record. So:
- You set up Firebase Auth, create a user with that email + password
- You log in via the admin's standard login form
- The admin recognises the email match and gives you admin access immediately
- On first action,
ensureSelfUserRecordwrites theusers/{uid}doc withrole: "admin",adminLocale: "en"(or browser-detected) - From then on you appear as a standard admin user — bootstrap doesn't matter anymore
The bootstrap email lives in users/_meta (or via the VITE_ADMIN_EMAIL baked into the bundle) so Firestore rules can mirror it. Don't lose access to the bootstrap email — recovery requires editing Firestore rules manually.
Creating users
Via the admin
Users sidebar entry (admin-only) → Create user → email + password + display name + role.
This:
- Creates the Firebase Auth user via
createUserWithEmailAndPassword(requires the admin's session — Firebase doesn't have a "create as admin" flow without a separate backend, so the new user is briefly "logged in" as the admin, the user record is written, then the admin re-authenticates). - Writes
users/{uid}with the chosen role and the new user's display name.
Via the Firebase Console
For air-gapped setups or password-reset flows:
- Firebase Console → Authentication → Users → Add user
- Then Firestore → users collection → New document with
{ email, displayName, role: "editor" }(oradmin)
Changing roles
Admin only. Users → click a user → Role dropdown → Save.
Demotion of the last admin (you'd lock yourself out) is blocked client-side. The bootstrap admin email is always treated as admin even if you accidentally set its role to editor.
Deleting users
Admin only. Users → click a user → Delete user.
This:
- Deletes the Firebase Auth user (server-side — irreversible)
- Deletes the Firestore
users/{uid}document
Posts authored by the deleted user keep their authorId reference. The post's author display name falls back to "Deleted user" or similar in templates that handle missing authors.
Password resets
The CMS doesn't ship a "forgot password" flow because Firebase's built-in flow is enough:
Self-service (when configured)
- Firebase Console → Authentication → Templates → enable Password reset email
- The login form's "Forgot password?" link triggers
sendPasswordResetEmail→ user gets an email → clicks the link → enters new password
Admin reset
- Firebase Console → Authentication → Users → ⋮ → Reset password
- The user gets the reset email
Direct password change in console
Firebase Console → Authentication → Users → ⋮ → Change password — sets a new password directly without emailing the user. Useful for one-off resets when the user's email is unreliable.
2FA / MFA
Firebase supports MFA (TOTP authenticator apps, SMS) via Identity Platform. Configure in Firebase Console → Authentication → Settings → Multi-factor authentication.
Once enabled, users see an MFA enrollment prompt after their next login. The admin's login form handles MFA challenges through Firebase's standard SDK flow — no per-CMS work.
For a single-admin setup, MFA via TOTP is recommended. The admin SPA itself doesn't add anything beyond what Firebase provides.
Per-user preferences
Stored at users/{uid}.preferences:
adminLocale— language for the admin UI (en/fr/de/es/nl/pt/ko). Set via the LocaleSwitcher in the topbar; persists across devices since it's in Firestore.
The user record has room for more fields (display photo, signature, etc.) — the schema is loose enough that custom plugins can extend it.
Firestore rules
Security in Flexweg CMS is rules-driven, not application-driven. Even if a malicious admin user found a bug in the admin code, they couldn't read documents the rules forbid. The shipped rules:
posts,terms,media— readable byadminoreditor; writable by bothusers— readable by all signed-in users (so the admin can show author names); writable by admin only (with the bootstrap exception)settings/site— readable by all signed-in users; writable by admin onlyconfig/flexweg— readable + writable by admin only (so editors never see the API key)
See Operations: Firestore rules for the actual rule code and customisation.