# Here, Announce

> Who is currently on a presence topic, and what they say they are doing. Here is the converging set of people present, derived from their connections rather than written by the app; Announce decorates your own entry in that set and can never create or modify anybody else's, because the platform stamps who each entry is about.

<!-- id: realtime-presence · area: realtime · stability: stable · html: https://osysharp.com/reference/realtime/presence/ -->

## Summary        {#summary}

`Here` is who is **currently connected** to a presence topic; `Announce` says what you are doing. Both are read and
written on a page, and neither needs a row: the set is derived from the connections themselves.

```osy title="who is here, and what they are doing" test app=realtime-presence
[Principal] entity User {
  [MaxLength(200)] string Email;
  security { allow read when IsAuthenticated; }
}

entity Room {
  [Required, MaxLength(120)] string Name;
  security { allow read, create when IsAuthenticated; }
}

entity Member {
  [Required] Room Room;
  [Required] User Person;
  security {
    allow read where Member.Any(m => m.Room == Room && m.Person == user);
    allow create where Person == user;
  }
}

class Presence {
  public User Person;        // STAMPED by the platform — who this entry is about
  public string Activity;    // announced by that person
}

topic RoomPresence(Guid roomId) {
  Candidates = u => Member.Any(m => m.Room.Id == roomId && m.Person == u);
  Carries    = Presence;
  Presence   = true;
}

[Page("/room/{roomId}/header")]
[Render(CSR)]
component RoomHeader(Guid roomId) {
  live var here = RoomPresence.For(roomId).Here;

  on mount {
    RoomPresence.For(roomId).Announce(new Presence { Activity = "reading" });
  }

  render {
    Text($"{here.Count} here");
    foreach (var p in here) { Text($"{p.Person.Email} — {p.Activity}"); }
  }
}
```

## Signature      {#signature}

```osy syntax
live var here = Topic.For(<address>).Here;       // the set of people currently present
Topic.For(<address>).Announce(<status>);         // decorate your OWN entry; never somebody else's
```

## Description    {#description}

### `Here` is a set, not a feed   {#here}

A presence topic's `Here` is the converging set of who is currently present — not a log of arrivals and departures.
Reading it as a set is what makes it self-correcting: a page that misses one update is fixed by the next, rather than
drifting further from the truth with every missed event.

One person is one entry however many pages they have open.

### Presence is derived from the connection   {#derived}

You are in the set because your page is subscribed, and you leave because it went away. Nothing an app writes can put
somebody in a room they are not in, or keep them there after they have gone — which is what makes the set worth
trusting, and what stops a crashed browser staying online for ever.

Invisible mode needs no flag: a page that does not subscribe is not in the set.

### An entry is your own type, with WHO filled in for you   {#entry}

`Carries` names the class an entry is made of. Declare one field of your app's principal type on it — call it
whatever you like — and **the platform fills that field in**. Everything else on the class is yours to announce.

```osy syntax
class Presence {
  public User Person;        // the platform writes this; an app that tries is refused at compile time
  public string Activity;    // yours
}
```

The field is chosen by its **type**, not its name. A class with two principal-typed fields is ambiguous — the
compiler cannot tell which one means *who this entry is about* — and is refused at the call site naming both.

### `Announce` decorates your own entry, and only your own   {#announce}

`Announce` adds your detail to that entry — a status, an activity. It **cannot create or modify anybody else's**, and
that is structural rather than checked: the entry exists because your page is subscribed, and who it is about comes
from your connection. There is nothing in an `Announce` that names a person, so announcing as somebody else is not a
refused request — it is one you cannot write.

Presence vocabulary like *away* or *do not disturb* is the app's to define, not the platform's.

### You see the people you may see   {#visibility}

A presence set contains real records, so it obeys the same read rules everything else does: each viewer's set is
built under their own authority. Somebody present whose record you may not read is simply not in your set — the same
answer a query would give you, not a blank silhouette.

### Announcing is not a message   {#not-a-message}

An announcement is a statement about your **current** state, not an event. Re-announcing replaces; it does not
accumulate, and nobody receives a history of what you were doing. One person is one entry however many pages they
have open, and the most recent thing they said is what everyone sees.

## Examples       {#examples}

The example above is compiled by the documentation gate.

For what people SAY in a room rather than who is in it, see [Listen](https://osysharp.com/reference/realtime/listen/).

## See also       {#see-also}
- [Listen](https://osysharp.com/reference/realtime/listen/) — receiving what was SAID in a room, rather than who is in it
- [topic](https://osysharp.com/reference/realtime/topic/) — the declaration, `Presence = true`, and publishing
- [Realtime](https://osysharp.com/reference/realtime/index/) — realtime in one page
- [component](https://osysharp.com/reference/ui/component/) — the `live var` a presence set feeds
