{% load common_extras %}{% comment %} The contact's channel identities — read-only except for the one-way opt-out. These rows live on apps/messaging's models and this page only reads them. The one mutation goes through apps.contacts.activity → the messaging facade → the single write site in messaging/ingest.py, which is what keeps ROADMAP contract 3 ("opted_out_at is written in one place") literally true rather than true by convention. There is deliberately no un-opt-out. SPEC §19 puts opt-out at a chokepoint so it cannot be bypassed, and a toggle an operator could flip back is a bypass with a friendlier label — re-consent has to come from the contact. `platform_user_id` and `extra.username` are platform-supplied and therefore attacker-controlled (SECURITY-BASELINE §2): rendered escaped, never as a link. {% endcomment %}

Channels

{% for channel in channels %}
{% include "partials/_platform_icon.html" with platform=channel.platform size="sm" %}
{{ channel.username|default:channel.address }}
{{ channel.address }}
{% if channel.is_opted_out %} Opted out {{ channel.opted_out_at }} {% elif channel.opt_in %} Opted in {% else %} No consent recorded {% endif %} {% if channel.is_pending %} {% comment %} An address captured before any connection of that platform existed (ROADMAP contract 1). It is upgraded lazily at first send, so there is nothing wrong here — but it is worth saying, because the row has no channel behind it yet. {% endcomment %} Pending {% elif channel.window_open %} Window closes in {{ channel.window_expires_at|timeuntil:now }} {% else %} Window closed {% endif %}
{% if can_edit_contacts and not channel.is_opted_out %}
{% endif %}
{% empty %}

No channels yet. A contact becomes reachable when they message one of this workspace's connections. Importing an address does not create one.

{% endfor %}