Przejdź do treści

Kontakty i wiadomości: HOWTO

Ten dokument prowadzi przez pełną ścieżkę: od atestacji kanału kontaktowego, przez publikację trasy i zaakceptowanie relacji, po prywatne dostarczenie wiadomości. Odpowiedzi pojęciowe i granice odpowiedzialności znajdują się w FAQ kontaktów i wiadomości.

Rozdziel źródła prawdy

Warstwa Odpowiedzialność Nie jest źródłem prawdy dla
Contact Attestation kontrola e-maila lub telefonu w określonym czasie tożsamości cywilnej i relacji
Contact Catalog atestowane claims i lookup-safe trasy zaproszeń lokalnej książki adresowej
Local contacts etykiety i owner-scoped projekcja UX capability authority
Local Relationship Layer klasy, członkostwa, predykaty i grupy właściciela transportu i passportów
Pseudonym Vault routing subject, pairwise nym i materiał odzyskania publicznego katalogu osób
Messaging outbox, inbox, treść, flagi i temporalny ślad dostarczenia odkrywania providerów
AD + INAC prywatny transport i admission artefaktów zgody na relację

Sprawdź konfigurację i gotowość

Najpierw uruchom daemonowe check-config, a następnie sprawdź warstwy osobno:

GET /v1/contact-catalog/status
GET /v1/messaging/status
GET /v1/local-relationships/status
GET /v1/messaging/contactability/options

Status ready jednego komponentu nie implikuje gotowości całego przepływu. Opcje contactability powinny wskazywać lokalnego uczestnika oraz odkrytego, zaufanego i świeżego providera atestacji. Kontakt zdalny wymaga ponadto działającej ścieżki AD/INAC.

Przygotuj uczestnika i routing subject

Kontaktowalność publikuje się dla konkretnego lokalnego uczestnika, ale katalog nie powinien ujawniać jego root identity. Utwórz lub zaimportuj uczestnika, odblokuj jego klucz podpisujący i utwórz osobny routing subject. Zachowaj rozdział:

participant/id       -> lokalna authority i podpis
routing-subject/id   -> publiczna trasa zaproszenia
pairwise nym         -> relacja po zaakceptowaniu prośby

Zapisz draft contactability

Draft deklaruje handle oraz przeznaczenie trasy. Nie publikuje jeszcze claimu:

POST /v1/messaging/contactability/draft
Content-Type: application/json
{
  "handles": [
    {"handle/kind": "email", "handle/value": "[email protected]"}
  ],
  "routes": [
    {"participant/id": "participant:LOCAL", "purpose": "messaging"}
  ]
}

Wartość handle jest transientnym wejściem operatora. Trwały indeks katalogowy powinien być lookup-safe; nie kopiuj surowego e-maila do publicznych diagnostyk ani audytu.

Uzyskaj contact attestation

Rozpocznij challenge przez daemonowy bridge, a następnie redeem zgodnie z adapterem dostawy providera:

POST /v1/messaging/contactability/attestation/challenges
POST /v1/messaging/contactability/attestation/challenges/{challenge_id}/redeem

Request contact-attestation-request.v1 określa contact/kind, contact/value, subject, żądany profil i czas ważności. Wynikiem jest passport kontroli kanału. Profil Story-010 może używać jawnego developmentowego always_accept; nie przenoś tego ustawienia do środowiska produkcyjnego.

Zwiąż atestację i opublikuj claim

Najpierw zwiąż passport z handlem w draftcie, potem opublikuj podpisany claim:

POST /v1/messaging/contactability/attest
POST /v1/messaging/contactability/publish
{
  "handle/kind": "email",
  "handle/value": "[email protected]",
  "passport": {"schema": "capability-passport.v1"}
}

Wartość passport powyżej skraca pełny passport zwrócony przez redeem; pokazany obiekt nie jest samodzielnie poprawnym passportem.

Publikacja przechodzi przez nadzorowany Contact Catalog. Claim bez poprawnej atestacji, z wygasłym passportem albo bez zgodnego subjectu powinien zostać odrzucony.

Zweryfikuj lookup bez ujawnienia identity

Provider Contact Catalog przyjmuje POST /v1/contact-catalog/lookups. Produkcyjny klient powinien korzystać z providera odkrytego przez Seed Directory, nie z zakodowanego endpointu. Minimalna semantyka requestu jest następująca:

{
  "schema": "contact-lookup-request.local.v1",
  "contact_index_value": "sha256:LOOKUP_SAFE_VALUE",
  "purpose": "messaging",
  "lookup_mode": "invitation-only"
}

Oczekiwany contact-lookup-result.v1 ma match/class = invitation-available i result/routes. Nie powinien zawierać root participant/id ani surowego handle'a.

Wyślij pierwszą wiadomość

Nadawca może podać zewnętrzny handle. Messaging zapisze wiadomość w outboxie, lecz nie wyśle jej jako treści do nieznanego odbiorcy przed zakończeniem contact request:

POST /v1/messaging/outbound
Content-Type: application/json
{
  "recipient/handle": {"kind": "email", "value": "[email protected]"},
  "subject": "Próba kontaktu",
  "body": "Cześć, czy możemy porozmawiać?",
  "content-type": "text/plain"
}

Uruchom przetwarzanie kolejki:

POST /v1/messaging/outbox/process

{"batch/limit": 10}

Obsłuż zgodę transportową i contact request

Jeżeli węzły nie mają jeszcze relacji transportowej, odbiorca zobaczy notyfikację inac/invitation-request. Po jej zaakceptowaniu ponów przetwarzanie outboxu. Następnie pojawi się osobna notyfikacja contact-request/received:

GET /v1/operator/notifications?limit=50
POST /v1/operator/notifications/{notification_id}/actions/accept

{"version": 1}

Użyj wersji zwróconej przez konkretną notyfikację; przykład 1 nie jest stałą. Akceptacja contact request tworzy lub aktualizuje lokalny kontakt, członkostwo contacts, pairwise mapping i wąski receive passport. Po decyzji ponownie przetwórz outbox nadawcy.

Sprawdź outbox, inbox i body

Warstwy odczytu są rozdzielone:

GET /v1/messaging/outbox
GET /v1/messaging/outbox/{envelope_id}/body
GET /v1/messaging/mailboxes
GET /v1/messaging/mailboxes/{mailbox_id}/messages
GET /v1/messaging/mailboxes/{mailbox_id}/messages/{envelope_id}/body
GET /v1/messaging/messages/{message_id}

Body endpointy są osobnymi, ograniczonymi powierzchniami. Lista wiadomości nie powinna przypadkowo przenosić pełnej treści ani sekretów diagnostycznych.

Zmieniaj flagi jako fakty

Read/unread i pokrewne flagi zapisuj przez endpoint flag wiadomości. Runtime utrwala messaging.flag.v1, a read model składa aktualny stan:

POST /v1/messaging/messages/{message_id}/flags

Nie edytuj SQLite ani plików Maildir ręcznie. Gdy projekcja wymaga odbudowy, użyj POST /v1/messaging/reindex; dla zaległych faktów użyj POST /v1/messaging/pending-facts/replay.

Klasyfikuj kontakty bez nadawania authority

LRL pozwala dodać członkostwo i rozwiązać grupę:

POST /v1/local-relationships/memberships
POST /v1/local-relationships/group.resolve
{
  "owner/ref": "participant:LOCAL",
  "contact/ref": "contact:EXAMPLE",
  "class/id": "friends",
  "status": "active",
  "actor/ref": "participant:LOCAL",
  "reason/code": "operator-classification"
}

Rozwiązanie grupy jest owner-scoped i respektuje blokady. Wynik jest kandydaturą do routingu, nie passportem i nie zgodą na broadcast.

Wycofaj kontakt albo capability

Przy zakończeniu relacji wykonaj jawnie właściwe operacje: zmień lub usuń lokalny kontakt, ustaw członkostwo LRL na blocked albo nieaktywne oraz odwołaj receive passport. Następnie sprawdź revocation view i ponów reindex, jeżeli operator naprawiał projekcję. Nie usuwaj faktów historycznych po to, aby „wyczyścić” widok.

Uruchom Story-010

Z katalogu node/ przygotuj profile i uruchom pełny, samowystarczalny smoke:

python3 tools/acceptance/story-010-operator/story-010-local-profiles.py init
python3 tools/acceptance/story-010-operator/story-010-local-profiles.py \
  ad-smoke --strict

Dla bramki LRL uruchom:

python3 tools/acceptance/story-010-operator/story-010-relationship-acceptance.py

Acceptance działa na dwóch profilach węzła na jednym hoście. Potwierdza kontrakty, restarty, provider discovery, prywatne dostarczenie i owner-scope, lecz nie zastępuje testu przez publiczną sieć ani produkcyjnego adaptera dostawy OTP.

Diagnozuj od granicy, na której powstała odmowa

Objaw Najpierw sprawdź
brak providera atestacji Seed Directory trust, freshness i capability profile
publish claim odrzucony passport, subject, expiry i podpis claimu
lookup zwraca no-match lookup-safe canonicalization, purpose i aktywność claimu
outbox czeka na permission notyfikację INAC, contact request i retry schedule
contact istnieje, lecz message jest odrzucona membership contacts, receive passport i revocation view
inbox ma rekord bez body bounded body surface, Maildir i projection diagnostics
grupa różni się między operatorami owner/ref, status membership i lokalne predykaty

Naprawiaj najniższą niespełnioną granicę. Ręczne dopisywanie rekordów do dalszej warstwy maskuje przyczynę i tworzy stan, którego nie da się odtworzyć.

Dokumenty źródłowe