Per the owner's spec: each social connection gets publishGovernance in its fields — unset = manual publish (today), auto = dispatch on approval, admin1/admin_majority/admin_consensus = a publish-phase chatgov poll (subject draft_publish, its own open-poll slot, no collision with review gates). Dispatch holds until the publish poll passes (E3 pre-dispatch check); auto dispatches on approval. Includes migration 033, the PATCH /connections/:id/publish-governance route (chatgov.manage), and 19+31 new tests. Implementation by the branding-panel process (claude/opus), lint and integration fixes here.
13 KiB
Chat sign-in restyle and deployment report
Repo implementation only; no production connection, deployment, or git commit
was made. The server-owned /opt/occ-element/config.json is not in this repo.
The supplied patch merges into that file rather than replacing its configuration.
Signed-out visitors opening chat.occupymedia.cc will see a small Hub mark and
wordmark in the top-left, a centered card containing Sign in, username and
password fields, and a red submit button. Password recovery and account creation
remain available as quiet links. Registration uses the same compact card. The
background is #060403, the card is #0F0A09, and the font is system-ui. The
mark is capped at 32px; there is no logo sidebar, background artwork, or hero.
Long forms and errors scroll on small screens rather than overlapping the brand.
Element's footer remains small and muted.
Verified Element Web 1.12.30 behavior
No Element source or config template was found in the repository or its installed
dependencies. Research used the official v1.12.30 source archive and the
matching ghcr.io/element-hq/element-web:v1.12.30 image, in temporary local files.
| Configuration | Effect in 1.12.30 |
|---|---|
branding.auth_header_logo_url |
Image source in login/registration headers and the default welcome component. This is nested under branding, not a top-level key. |
branding.logo_link_url |
Link destination where Element actually renders a linked logo, such as default welcome. |
auth_header_logo_click_url |
Does not exist in this release. The login/registration header renders an unlinked image; a config option cannot make that header clickable. |
brand |
App name used in translated text; does not change the header's layout or image. |
branding.welcome_background_url |
Background artwork across auth pages. The injected CSS replaces the inline background with a solid color. |
embedded_pages.login_for_welcome |
Uses the login form for the signed-out landing page, bypassing default/custom welcome content. |
default_server_config |
Selects the homeserver and identity-server connection details; does not control branding or layout. Left intact. |
disable_custom_urls |
Removes server editing. The CSS hides the redundant server label only when the edit control is absent. |
disable_3pid_login |
Removes the username/email/phone selector, leaving username/password. |
disable_login_language_selector |
Removes the language dropdown from the auth header. |
See the pinned configuration docs, AuthHeaderLogo source, and DefaultWelcome source.
The structure is .mx_AuthPage → .mx_AuthPage_modal →
main.mx_AuthPage_modalContent, with .mx_AuthHeader and .mx_AuthBody as
siblings. The large logo comes from .mx_AuthHeaderLogo > img inside a 206px
sidebar; the original body is 500px wide. The wrapper also renders a blur layer
and .mx_AuthFooter. See AuthPage
and upstream auth CSS.
There is no .mx_AuthPage_logo in this release's auth structure.
setting_defaults.custom_themes accepts theme colors, fonts and Compound token
overrides, not an arbitrary CSS stylesheet URL. source_url records a theme
JSON's origin, not a CSS file. The injected link intentionally has no
data-mx-theme, so Element's theme switching will not disable it. See the
theming docs
and theme loader/types.
On first visits from iOS/Android, Element redirects a bare / to
/mobile_guide/ before loading config. Both chat vhosts redirect that
app-download page to /#/login, which bypasses the mobile redirect. Disabling
mobile_guide_toast also removes the later mobile-app prompt. See the pinned
startup source.
Files changed
| File | Purpose |
|---|---|
| ../edge/hub-chat-auth.css | Scoped auth overrides: corner branding, compact responsive card, warm colors, focus styles and red primary actions. Uses stable mx_* classes, structural selectors and Compound data-kind, with no hashed class selectors. |
| ../edge/nginx.conf | Both HTTP tunnel and HTTPS chat vhosts serve /hub-chat-auth.css and inject its link once before </head> in HTML. Clears upstream Accept-Encoding so sub_filter can read HTML. Routes the mobile guide to login. Matrix API and SSO helper keep their own locations. |
| ../edge/docker-compose.edge.yml | Read-only bind mount for the stylesheet. |
| auth-branding.patch.json | Hub logo URL, supported logo-link setting, direct login landing and removal of extra login selectors. |
| apply-auth-branding.py | Merge/preview utility. Preserves unrelated settings and writes in place to retain Docker's single-file bind mount. |
| ../edge/README.md | Links this report and corrects the documented chat routing. |
| AUTH-RESTYLE.md | This research and deployment report. |
The stylesheet is downloaded with the SPA shell; nginx cannot see hash routes.
It applies only within .mx_AuthPage, including recovery/auth verification
screens using that wrapper. Signed-in room UI keeps the existing custom theme.
The element.occupymedia.cc alias vhost is not changed.
Exact deployment steps (operator runs these; not executed here)
Use the existing CT 150 checkout at /opt/anarchoposter. Run server commands
with permission to edit /opt/occ-element/config.json and manage Docker.
-
On the server, before copying files, back up the config and edge files. Keep this shell open so
occ_auth_backupremains available for later steps.occ_auth_backup="/opt/occ-element/backups/hub-auth-$(date -u +%Y%m%dT%H%M%SZ)" mkdir -p "$occ_auth_backup" cp -p /opt/occ-element/config.json "$occ_auth_backup/config.json" cp -p /opt/anarchoposter/infra/occupymedia/edge/nginx.conf "$occ_auth_backup/nginx.conf" cp -p /opt/anarchoposter/infra/occupymedia/edge/docker-compose.edge.yml "$occ_auth_backup/docker-compose.edge.yml" if test -f /opt/anarchoposter/infra/occupymedia/edge/hub-chat-auth.css; then cp -p /opt/anarchoposter/infra/occupymedia/edge/hub-chat-auth.css "$occ_auth_backup/hub-chat-auth.css" fi printf 'Backup: %s\n' "$occ_auth_backup" -
From this workstation's repo root, copy only the reviewed infra files. Set
OCC_EDGE_SSHto your existing SSH destination for CT 150; no hostname or credentials are assumed here.OCC_EDGE_SSH='YOUR_EXISTING_CT_150_SSH_DESTINATION' rsync -aR -- \ infra/occupymedia/edge/nginx.conf \ infra/occupymedia/edge/docker-compose.edge.yml \ infra/occupymedia/edge/hub-chat-auth.css \ infra/occupymedia/edge/README.md \ infra/occupymedia/element/ \ "$OCC_EDGE_SSH:/opt/anarchoposter/" -
On the server, validate the candidate edge config with the new mounts, then merge the auth patch and recreate only the edge service:
cd /opt/anarchoposter/infra/occupymedia/edge docker compose -f docker-compose.edge.yml config --quiet docker compose -f docker-compose.edge.yml run --rm --no-deps edge nginx -t python3 ../element/apply-auth-branding.py /opt/occ-element/config.json > "$occ_auth_backup/config.preview.json" diff -u "$occ_auth_backup/config.json" "$occ_auth_backup/config.preview.json" python3 ../element/apply-auth-branding.py /opt/occ-element/config.json --write docker compose -f docker-compose.edge.yml up -d --no-deps --force-recreate edge docker exec occ-edge-1 nginx -tRun each command only if the preceding validation succeeded;
diffexits 1 for the expected changes. Recreating the edge is required for the new CSS mount and ensures it sees copied files even if their inodes changed. Element needs no restart: the merge utility retains the config inode. Its existingsetting_defaults.custom_themes, Compound tokens,default_theme, anddefault_server_configremain intact. Do not replace config.json with the patch JSON or try to register this CSS as a custom theme. -
On the server, verify the public HTML, stylesheet and served config:
curl -fsS --compressed https://chat.occupymedia.cc/ -o "$occ_auth_backup/index.served.html" curl -fsS 'https://chat.occupymedia.cc/hub-chat-auth.css?v=1' -o "$occ_auth_backup/auth.served.css" curl -fsS https://chat.occupymedia.cc/config.json -o "$occ_auth_backup/config.served.json" cmp hub-chat-auth.css "$occ_auth_backup/auth.served.css" python3 - "$occ_auth_backup" <<'PY' import json, sys from pathlib import Path backup = Path(sys.argv[1]) html = (backup / "index.served.html").read_text() assert html.count('href="/hub-chat-auth.css?v=1"') == 1 old = json.loads((backup / "config.json").read_text()) served = json.loads((backup / "config.served.json").read_text()) for key in ("setting_defaults", "default_theme", "default_server_config", "default_server_name"): assert served.get(key) == old.get(key), key assert served["branding"]["auth_header_logo_url"] == "https://app.occupymedia.cc/brand/logo.svg" assert served["branding"]["logo_link_url"] == "https://app.occupymedia.cc" assert served["embedded_pages"]["login_for_welcome"] is True assert served["disable_3pid_login"] is True assert served["disable_custom_urls"] is True print("Public HTML injection, stylesheet and preserved theme verified") PYIf a CDN serves an older HTML/config response, purge those URLs and retry. In a fresh signed-out browser, open
/,/#/loginand/#/register, and check the page on a phone as well. Check password errors, keyboard focus, recovery and an existing signed-in room. Browser reloads load the new config. Element also supports domain-specific config files; if this installation starts serving a successful/config.chat.occupymedia.cc.json, apply the same merge to its mounted source because it takes precedence over config.json.
Rollback using the printed backup directory: restore the old nginx and compose files, restore the old config in place, then recreate the edge service with the old compose file:
cp -p "$occ_auth_backup/nginx.conf" /opt/anarchoposter/infra/occupymedia/edge/nginx.conf
cp -p "$occ_auth_backup/docker-compose.edge.yml" /opt/anarchoposter/infra/occupymedia/edge/docker-compose.edge.yml
if test -f "$occ_auth_backup/hub-chat-auth.css"; then
cp -p "$occ_auth_backup/hub-chat-auth.css" /opt/anarchoposter/infra/occupymedia/edge/hub-chat-auth.css
fi
python3 - "$occ_auth_backup/config.json" /opt/occ-element/config.json <<'PY'
from pathlib import Path
import sys
data = Path(sys.argv[1]).read_bytes()
with Path(sys.argv[2]).open("r+b") as target:
target.write(data)
target.truncate()
PY
cd /opt/anarchoposter/infra/occupymedia/edge
docker compose -f docker-compose.edge.yml run --rm --no-deps edge nginx -t
docker compose -f docker-compose.edge.yml up -d --no-deps --force-recreate edge
Local validation
- Real Element v1.12.30 and nginx:1.27-alpine ran on an isolated local Docker network with temporary certificates and loopback ports; Matrix responses and the Hub asset request were mocked. No live accounts or production services were accessed.
- Full repo nginx config passed
nginx -t; compose configuration parsed. Nginx emits an existing duplicatetext/htmlMIME warning in the unrelated files sign-in location; it does not prevent validation. - Both chat HTTP/HTTPS vhosts injected exactly one stylesheet link despite the client advertising gzip. JSON and the SSO helper were unchanged; CSS content and content type matched the repo file.
- Chromium checked bare
/→ login, 420px desktop card, 32px corner logo, system-ui, warm background, red submit, two login inputs, mock failed login, visible errors, and registration. Checked widths 320/390/844px including landscape: no horizontal overflow or brand/form overlap. A fresh iPhone user agent reached the form through the mobile-guide redirect. - The injected link remained enabled after custom-theme loading. A room DOM without the auth wrapper retained its original button color.
- Config merge checks confirmed preservation of theme, Compound tokens, homeserver and sibling keys, idempotence, and the original file inode.
Real successful authentication and production cache/routing behavior still need
the operator's post-deployment checks. Existing unrelated workspace changes were
left alone; no files in apps/api were edited by this task.