Administrator and editor

Reading time 7 min

The optional editor is a separate Node.js writing server. It is not part of a public static upload and it is not running on this showcase. This guide sets it up on loopback for one local administrator, checks a writing session, then explains what changes for a team installation.

Start with a working V2 build from First site. You should be able to preview dist/ before adding account data. Use a fictional page for this exercise rather than confidential material.

Understand the three locations

Layer Contents and update
Source Saved Markdown in content/; changes after a confirmed source edit/save
Runtime Private accounts/settings/links/history; changes after authorized runtime actions
Reader Generated HTML/index/assets in dist/; changes after build/publication

Browser-local drafts form a fourth, separate state. They are not source until Save succeeds and are not a server backup. Remote reader output is a fifth state: it changes only when your hosting/deployment process receives the intended build.

An editor account is permission to write assigned source, not a reader login. Publishing internal content to an unprotected static host exposes it to people who can reach that host.

1. Choose the account store before creating an account

By default, the editor and account commands use .markstack/users.json beside the project. For a local disposable exercise this default is convenient. A service installation should put private runtime data outside the code checkout and public web root so updates do not replace it.

Use the same MARKSTACK_USERS_FILE for account creation, editor startup and administrator recovery. For a Unix shell:

mkdir -p "$HOME/private-markstack"
chmod 700 "$HOME/private-markstack"
export MARKSTACK_USERS_FILE="$HOME/private-markstack/users.json"

For PowerShell:

New-Item -ItemType Directory -Path "$HOME\private-markstack" -Force
$env:MARKSTACK_USERS_FILE = "$HOME\private-markstack\users.json"

The Windows example creates the directory but does not set Windows access-control entries. Restrict access using your own account/organization’s Windows permissions before storing real data. Unix chmod is not a Windows security command.

The selected path must be writable to the editor’s operating-system account. Do not choose static/, dist/, a publicly served directory or a shared folder everyone can read. A wrong path can make a server appear to have no users even when the real account store still exists elsewhere.

2. Create the first administrator

Run in the V2 project directory, with the account-store variable still selected:

npm run editor:create-admin -- --user admin

The example username is admin; choose your own suitable account name. At a terminal the CLI prompts for a password twice without displaying it. Use a unique password that meets the policy; do not put it in the command line, a screenshot, source control or this documentation.

Input Actual rule
Username 2-32 lowercase letters, digits, dot, underscore or dash; first character letter or digit
CLI username --user value is lowercased before account handling
Password 12-256 JavaScript string units, not in the common-password list
Terminal input Hidden prompt, repeated for confirmation
Piped input Reads once to end-of-input; removes one trailing newline

Password policy does not require a particular mix of letters/digits/symbols. Hashing normalizes NFKC; policy length is checked first. Do not publish a reusable sample credential just to illustrate the limits. A cancelled or mismatched terminal prompt fails instead of creating the account.

A successful command prints the administrator name and selected store path. Check the path, not just the success word. If it says the user already exists, stop and confirm whether you are using the intended store. Creation does not overwrite an existing account. Recovery is a different command.

The CLI supports piped password input for controlled automation, but this walkthrough uses the hidden interactive prompt. Plain-text shell variables/files and command history are not appropriate places to keep persistent credentials.

3. Start the local writing server

npm run editor

The default listener is 127.0.0.1 on port 3001. Open http://127.0.0.1:3001 on the same machine and sign in with the account you created. The process stays running until stopped. It does not automatically create an OS service, install a reverse proxy or publish a public URL.

If the port is already occupied, find the existing process before starting another. A deliberate port change uses MARKSTACK_EDITOR_PORT, not the preview variable. Keep loopback binding for this local exercise. Do not bind to all interfaces as a shortcut around a remote connection problem.

Your shell environment belongs to that terminal/process. If you open another terminal, select the same users file again before starting the editor. A future system service needs that selection in its own service configuration too.

4. Complete one writing cycle

Open a synthetic Markdown page. Add a short sentence and a heading, then inspect source preview. Save the page and wait for success. Reload or reopen it to confirm the saved server text contains the change.

As administrator, use Publish Changes and wait for the build result. Open the static reader separately through npm run serve or your chosen reader host. Verify the changed sentence, heading, link and search result there.

These are different checks:

Check Scope of the result
Typed text Browser input exists; no save or other-device recovery proved
Save Sent source text confirmed; reader may still be old
Preview Current input rendered; full reader parity not proved
Publish Saved source built/switched locally; remote upload still separate
Live reader Expected deployed content visible; future edits do not deploy automatically

Publishing includes saved content available to that build, not just one browser’s unsaved changes. Agree a review process before a team starts publishing shared work.

5. Add a section editor only after the admin check

In Admin > Users, create a fictional editor and assign a synthetic top-level section. Save access changes. Use a separate browser profile/session to test what that editor can and cannot open.

Task Admin Editor
Edit root source Yes No
Edit section descendants Any section Assigned only
Rename or delete section root Yes No
Publish Yes No
Manage users, settings and links Yes No
Change own password Yes Yes

An editor can save authorized section content but cannot publish, manage global settings/accounts or edit root content. Do not test permissions only while signed in as the administrator. Check both an allowed page and a denied page. Assignment changes end the affected user’s sessions, so new sign-in may be part of a correct recheck.

Use the detailed Accounts and access and Editor handbook pages for controls and restrictions. Neither role turns the static reader into an authenticated application.

Recovery and common failures

For an existing administrator account, shell recovery is:

npm run editor:reset-admin -- --user admin

Select the correct users file first. Reset asks for a new password, re-enables the existing administrator, clears its pending forced-change flag and raises its access version. The running editor reloads that account state on the next request, which invalidates old sessions without restarting the process. The browser reset action is different: it is for editor accounts and issues a temporary password that must be changed at sign-in. It is an account-changing operation, not a harmless connectivity test. Do not create an unrelated replacement account to work around a runtime-path mistake.

If sign-in fails, check the actual server process, selected store and account state. If secure cookies are enabled while you browse plain HTTP, sign-in can fail because the cookie is not sent over that connection. Use the intended local configuration or properly configured HTTPS; do not disable production protections as a generic fix.

Failure Check and safe response
Existing name Check name/store path; use intended account or recovery, not overwrite
No admin found Check role, lowercase name and store; select the correct existing store
Login rejected Check process, store, account and block state; preserve draft before fixing/retrying
Cookie on HTTP Check address/secure setting; use correct local or properly configured HTTPS
Store locked Check other process/ownership; wait or retry, do not delete a live lock
Port busy Inspect listener; stop intended old process or choose a deliberate port

The account CLIs return exit 2 for missing username usage, exit 1 for failures and exit 0 after successful completion. The generated private user file uses Unix mode 600; verify directory access and the actual existing-file permissions too. A save/build error needs its actual server/browser message. Confirm writable source/output paths, correct Node/dependencies and valid content, then recheck the state that failed. A browser-local draft is not a server backup.

From local exercise to a private team service

A production editor needs a dedicated service account, restricted writable directories, trusted host/proxy configuration, HTTPS, backups and permission checks. Follow Private team editor and the service/proxy guides rather than exposing the local listener directly.

Synthetic local create/login/write/Admin checks were exercised against V2. This walkthrough does not claim a production TLS service, Windows permissions setup or remote restore was deployed. Keep those validation limits explicit when adapting the example.