Chatroom
========

Chatroom adds role-controlled chat rooms to Drupal. Drupal remains responsible
for permissions, message storage and history. It works on shared hosting through
JavaScript polling, and can optionally use Node.js / Socket.IO or the Live
Update module for live delivery.

Five-minute setup
-----------------

1. Enable Chatroom:

       vendor/bin/drush en chatroom -y
       vendor/bin/drush updb -y
       vendor/bin/drush cr

2. Create a room at `/chatroom/add`.
3. Grant the appropriate roles `view chatrooms` and `post to chatrooms` at
   `/admin/people/permissions`, then select permitted view/post roles on the
   room form.
   Existing rooms are unlisted in the public directory by default. Enable
   `List in public directory` only when visitors should be able to discover
   the room; this setting does not grant view or post access. The directory is
   available at `/chatrooms`. Eligible signed-in users can request to join a
   listed membership-required room; only owner/moderator approval grants
   membership or message access.
4. Open the room in two browser sessions and send a message. JavaScript
   polling works immediately; configure an optional push provider below for
   lower-latency delivery.

Room discovery and account-bound membership are part of Chatroom. Membership
is opt-in per room; existing rooms retain their role-based access unless a
manager enables the membership requirement. Enable the optional
`chatroom_moderation` submodule separately when the site needs private room or
message reports and moderator review. Enabling the submodule does not change
the access policy of existing rooms.

Room owners, active moderators, and membership administrators can review the
append-only membership audit at `/chatroom/{chatroom}/members/history` or
`/admin/content/chatroom-participant-history`. It records changes from the
time the history update is installed; existing memberships are not backfilled.
Records have no automatic expiry and remain after participant, user, or room
deletion. Define an appropriate retention policy for the site before enabling
this history on a production site.

Configuration
-------------

`/admin/config/user-interface/chatroom` configures message date formatting,
command prefix, anonymous display names, avatars and message delivery.
Room-level view and post roles are configured on each Chatroom entity; this is
intentionally separate so one room cannot accidentally inherit another room's
privacy settings.

Enable `Show user avatars` on that configuration page to show profile
pictures next to messages. Users without a profile picture, and anonymous
visitors, receive an initial instead. The included CSS uses variables such as
`--chatroom-accent`, `--chatroom-avatar-size` and `--chatroom-radius`, so a
theme can adjust the interface without replacing the base stylesheet.

Message delivery
----------------

At `/admin/config/user-interface/chatroom`, enable the installed delivery
methods and drag rows into priority order.

* JavaScript polling is built in and works without another module.
* Node.js / Socket.IO is offered when the `nodejs` module is installed.
* Live Update is offered when the `liveupdate` module is installed. It works
  through its shared event API. The optional `liveupdate_sse` transport
  (experimental) and `liveupdate_go` submodule integrate without adding
  Chatroom dependencies.

Enable polling alongside other providers for fallback.

The selected methods are active together: push methods provide low latency,
while polling reads any missed messages and prevents a gateway outage from
stopping the conversation. Duplicate deliveries are ignored by message ID.

Provider authors should implement
`hook_chatroom_liveupdate_providers()` and
`hook_chatroom_liveupdate_publish()`. Their browser library dispatches a
`chatroom:message` event containing only `cid` and `cmid`; Chatroom fetches the
rendered content from Drupal so current access checks remain authoritative. See
`chatroom.api.php` for the complete contract.

Block placement
---------------

Enable the core Block module, then go to `/admin/structure/block` and place a
`Chatroom` block in any theme region. Select the room in the block form. The
block renders the same live update chat interface as the room page and enforces
that room's view and post roles for every visitor. This makes a room suitable
for a support or community channel without adding a menu link.

The browser shows connection status, reconnects automatically, supports more
than one room on a page, retrieves older messages while scrolling, and does not
render the same message twice.

Manual smoke test
-----------------

* With polling enabled, confirm a message appears in a second browser session
  within the configured interval.
* When Node.js is enabled, start the gateway and verify its authenticated
  health endpoint.
* Open a permitted room in normal and private browser windows.
* Confirm each session sees the other message.
* Reload one session; its history should be ordered and no duplicate should
  appear.
* With Node.js enabled, stop the gateway; the page should report a disconnected
  status while polling continues. Restart it and verify that it reconnects.
* Try the room URL and POST endpoint as a user without permission; access must
  be denied. Invalid JSON, missing CSRF token and messages over 1000 characters
  must be rejected.
* For a listed membership-required room, verify an eligible signed-in user can
  submit one join request, that a pending request does not grant room/history/
  transport access, and that only the room owner or an active moderator can
  approve or reject it.
* As the room owner or active moderator, open the participant list and verify
  membership history records requests, approvals/rejections, invitations,
  acceptance/decline, role changes, leaving, revocation, and record deletion.
  Verify unrelated accounts cannot view room history and the global collection
  remains restricted to membership administrators.
* When the optional Chatroom Moderation module is enabled, open
  `/admin/content/chatroom-sanctions` as a room owner or active moderator.
  Create a room-scoped ban for a test account and verify that account cannot
  view or manage the room, its history, or its messages, and cannot post or
  request/accept membership. Verify the account remains able to use a different
  room. As a sanction administrator, create a site-wide ban and verify it
  applies across rooms. Sanction records and reasons must remain visible only
  to authorized moderators and administrators.
* With a screen reader and keyboard only, open a room and verify the message
  log is announced as “Messages in [room title]”, can receive focus without
  trapping it, and announces each new message politely without moving focus.
  Submit a message and verify the composer instructions and send result are
  announced. Trigger a connection change and an online-user count change; each
  status should be announced once, without exposing messages from a room the
  account cannot access. Record the screen reader, browser, and any failures.

Development
-----------

The repository root includes an Antigravity/VS Code workspace configuration.
PHP format-on-save uses PHP_CodeSniffer's PHPCBF with `phpcs.xml.dist`
(Drupal and DrupalPractice standards); JavaScript format-on-save uses
Prettier with Drupal Core's formatting options, and ESLint uses the Core rules.
Install the recommended workspace extensions when prompted.

    (cd web/modules/contrib/chatroom && ../../../../vendor/bin/phpcs)
    node web/core/node_modules/eslint/bin/eslint.js --resolve-plugins-relative-to web/core web/modules/contrib/chatroom/js/chatroom.js
    node web/core/node_modules/prettier/bin/prettier.cjs --check web/modules/contrib/chatroom/js/chatroom.js
    node --check web/modules/contrib/chatroom/js/chatroom.js
    node --test web/modules/contrib/chatroom/tests/js/chatroom.test.cjs
    export SIMPLETEST_BASE_URL='http://contrib.local'
    SIMPLETEST_DB='mysql://USER:PASSWORD@localhost/TEST_DATABASE' \
      vendor/bin/phpunit -c web/core/phpunit.xml.dist \
      web/modules/contrib/chatroom/tests/src \
      web/modules/contrib/chatroom/modules/chatroom_moderation/tests/src

Set `SIMPLETEST_BASE_URL` to the local Drupal HTTP site configured to use the
same dedicated, disposable `TEST_DATABASE`; BrowserTestBase sends HTTP requests
to this site while the tests use isolated table prefixes in that database.
Replace `http://contrib.local` when your local site uses a different host. Do
not point either setting at a production site or database containing data you
need.
