So bauen Sie eine Online-Community in Next.js

Ein Forum bewahrt auf, was seine Mitglieder geschrieben haben. Eine Community, die sich lebendig anfühlt, hat mehr gleichzeitig zu bieten. Mitglieder teilen ein Foto und bekommen eine Antwort, solange sie noch da sind, kommen in einen Raum zum Reden, per Stimme oder mit Kamera, schauen die Events des Clubs live und kommen mit ihrer eigenen Arbeit auf die Bühne, und sie sehen, wer gerade da ist. In einer Next.js-App ist jedes davon eine Verbindung, die offen bleibt, zu vielen Menschen gleichzeitig.
Dieser Beitrag geht jeden Teil durch, den eine echte Community-App braucht, mit einem vollständigen, funktionierenden Beispiel: Community, der Fotoclub aus unserer Next.js-Anleitung, mit seinen Kanälen, seinen Lounges zum Vorbeischauen und seinen Live-Events. Sie können es live ausprobieren: Melden Sie sich als Mia an, Host des Clubs: Die Portfolio-Review beginnt gerade. Öffnen Sie das Studio und gehen Sie live. Öffnen Sie den Club dann in einem privaten Fenster als Ava, schauen Sie die Review an, heben Sie die Hand und kommen Sie auf die Bühne.
Was eine Online-Community braucht
- Kanäle, die mithalten. Nachrichten und Fotos erreichen alle, die gerade lesen, sofort, mit Tipp-Anzeige und Reaktionen, und bleiben für alle gespeichert, die später kommen. Die Fotos öffnen sich nur für Mitglieder.
- Räume zum Vorbeischauen. Sprachräume und Räume mit Kameras und Bildschirmen, die Mitglieder betreten und verlassen, wie sie wollen, viele Menschen gleichzeitig über Medienserver (wie Medienserver funktionieren). Hosts, die jemanden stummschalten oder hinausnehmen können.
- Live-Events. Ein Host für alle Mitglieder, mit Chat und Reaktionen neben dem Bild, und ein Mitglied, das auf die Bühne geholt wird, um seine Arbeit zu zeigen (wie Livestreaming in Next.js funktioniert).
- Was gerade läuft. Wer in welchem Raum ist und welches Event live ist, aktuell auf jeder Seite, ohne Neuladen.
- Wer da ist. Wer online ist, und ein Weg, diesen Mitgliedern zu schreiben oder sie anzurufen.
All das läuft über Verbindungen, die offen bleiben, solange ein Mitglied auf der Website ist, und die kann eine Serverless-Funktion nicht halten (warum, und was sich dagegen tun lässt). Sie können jeden Teil selbst bauen, auf Websockets, WebRTC und eigenen Medienservern. Oder Sie lassen eine Echtzeit-Cloud die Verbindungen, die Anrufe und die Streams betreiben, während Ihr Server behält, was wirklich Ihres ist: die Mitglieder, die Regeln und die Daten. Genau das macht der Club, über WordPlus Cloud.
Das Beispiel: ein Fotoclub
Mitglieder teilen Fotos in Kanälen, um Feedback zu bekommen, etwa in #critique und #trips. Sie schauen in den Lounges vorbei: Coffee lounge per Stimme, Editing hangout mit Kameras und Bildschirmen. Die Hosts leiten Live-Events, eine Portfolio-Review oder einen Kurs zur Nachtfotografie, bei denen Mitglieder auf die Bühne kommen. Es ist eine Next.js-App mit dem App Router, Better Auth und Postgres, und ihr Echtzeit-Teil besteht aus wenigen Dateien. Fünf Schritte machen sie aus.
1. Kanäle mit Fotos, gespeichert auf Ihrem Server
Jeder Kanal ist ein Raum, benannt nach seiner Nummer: channel:2. Die Website deklariert sie einmal, nach diesem Muster, mit der Regel, wer darin sein darf:
const MESSAGES = { history: 50, emit: ['message', 'typing', 'reaction', 'read'], webhook: ['message', 'reaction'] };
realtime.room('channel:{id}', MESSAGES, async (user, _params, room) => mayWrite(user, room));Jedes Mitglied darf in einem Kanal sein, sonst niemand. Nachrichten, Tipp-Anzeige, Reaktionen und Lesebestätigungen gehen versiegelt über WordPlus Cloud von Seite zu Seite, und die Webhooks message und reaction bringen jede einzelne zum Server der Website, der sie in seiner eigenen Datenbank speichert. Die Seite des Kanals ist der fertige Chat auf diesem Raum:
<Chat
rt={useRealtime()}
room={room}
people={people}
messages={`/api/messages?room=${room}`}
upload="/api/files"
accept="image/jpeg,image/png,image/webp,image/gif"
maxFileSize={15 * 1024 * 1024}
/>messages ist die eigene Route der Website für ältere Nachrichten, die nachgeladen werden, während ein Mitglied nach oben scrollt. upload gibt dem Eingabefeld seine Büroklammer und nimmt auch Fotos an, die in den Chat eingefügt oder gezogen werden: Jedes geht gleich bei der Auswahl an die eigene Route der Website, und die Nachricht trägt nur, wo es sich öffnet. WordPlus Cloud sieht das Foto nie. Die Route entscheidet mit der eigenen Regel des Raums:
if (!me || !(file instanceof File) || !/^(channel|chat):\d+$/.test(room) || !(await realtime.mayJoin(room, me))) {
return Response.json({ error: 'This photo is not for this conversation.' }, { status: 403 });
}realtime.mayJoin() führt dieselbe Regel aus wie der Beitritt zum Raum: Wer einen Kanal lesen darf, darf dort ein Foto teilen, sonst niemand. Jedes Foto öffnet sich unter einer eigenen Adresse, die erneut prüft, wer es öffnet: Wer nicht zum Club gehört, bekommt nichts, ganz gleich, mit welcher Adresse.
2. Sprachräume, um die sich Hosts kümmern
Eine Lounge ist ein Gruppenanruf, benannt nach ihrer Nummer, lounge:3, in den jedes Mitglied hineinschauen kann. Die Regel macht die Hosts des Clubs zu ihren Hosts:
realtime.groupCalls('lounge:{id}', async (user) => {
if (!(await isMember(user))) return false;
return (await isHost(user)) ? { admin: true } : true;
});Die Lounge erscheint auf ihrer eigenen Seite, mit dem Button zum Hineinschauen darin:
<CallSpot rt={rt} call={room} className="h-[calc(100dvh-14rem)] rounded-2xl">
<GroupCallButton rt={rt} room={room} type={kind} title={name}>
{people.length > 0 ? 'Drop in' : `Open ${name}`}
</GroupCallButton>
</CallSpot>type ist audio für eine Sprach-Lounge und video für eine mit Kameras. Bevor ein Mitglied drin ist, zeigt CallSpot, was darin steht: wer gerade in der Lounge ist, und den Button. Danach nimmt der Anruf diesen Platz ein: die Bilder aller, oder ihre Kameras und Bildschirme, und die Steuerung. Ein Mitglied kommt mit ausgeschaltetem Mikrofon und ausgeschalteter Kamera herein und schaltet sie im Anruf ein, sodass ein Besuch nie überraschend ein Mikrofon öffnet. Auf einer anderen Seite der Website läuft die Lounge in einem Fenster in der Ecke weiter und kehrt zurück, wenn ihre Seite wieder geöffnet wird.
admin: true ist alles, was die Hosts brauchen. Auf dem Bildschirm eines Hosts hat jede Kachel der anderen Stummschalten und Entfernen, und der Anrufbildschirm fragt dafür über dieselbe Route, die das nur von einem Host annimmt.
3. Live-Events, mit Mitgliedern auf der Bühne
Ein Event ist ein Livestream, benannt nach seiner Nummer: event:5. Seine Regel legt fest, wer was ist: Der Host des Events geht live, und jedes andere Mitglied schaut zu:
realtime.streams(
'event:{id}',
async (user, { id }) => {
const event = await eventOf(id);
if (!event || !(await isMember(user))) return false;
return String(user) === event.host ? { role: 'host', quality: '1080p' } : 'viewer';
},
{ stage: true, reactions: true },
);Der Host geht aus einem eigenen Studio live, einer Seite der Website mit großem Bild, darunter Go live, und daneben der Chat und die gehobenen Hände:
<LiveStream
name={`event:${event.id}`}
view="studio-page"
title={event.title}
url={`/events/${event.id}`}
backUrl={`/events/${event.id}`}
/>Die Seite des Events gibt jedem Mitglied den Player mit seinem Chat, dasselbe <LiveStream> unter demselben Namen. Ein Host kann stattdessen auch aus OBS live gehen, mit der Adresse und dem Schlüssel, die das Studio angibt. stage: true ist die Bühne: Ein Mitglied hebt im Player die Hand, der Host sieht sie unter Guests und lädt es ein, und sobald es Join stage drückt, gehen seine Kamera und sein Mikrofon neben dem Host live, für alle, die zuschauen.
4. Was gerade läuft, auf jeder Seite
Neben jeder Seite zeigt eine Seitenleiste, wer in jeder Lounge ist und welches Event live ist, mit der Zahl der Zuschauer. Die Website führt für keins davon eine Tabelle. WordPlus Cloud weiß es:
export async function liveNow(): Promise<Map<string, number>> {
const live = new Map<string, number>();
for (const stream of await realtime.listStreams()) {
const event = idIn(stream.name, 'event');
if (event) live.set(event, stream.viewers);
}
return live;
}realtime.listCalls() und realtime.call(name).get() sagen dasselbe über die Lounges und wer in jeder ist. Damit es aktuell bleibt, schickt WordPlus Cloud der Website einen Webhook, sobald jemand in eine Lounge kommt oder sie verlässt, oder ein Event live geht oder endet. Die Website sagt es in einem Raum, dem jede Seite eines Mitglieds beitritt, und wenn ein Event live geht, sagt sie es jedem Mitglied:
realtime.on('stream.live', async ({ stream }) => {
const id = idIn(stream, 'event');
const event = id ? await eventOf(id) : null;
if (!event) return;
await realtime.to('club').emit('changed');
const everyone = (await members()).map((person) => person.id).filter((person) => person !== event.host);
await realtime.toUser(everyone).emit('live', { event: event.id, title: event.title, host: event.hostName });
});Im Layout hört jede Seite beides:
useRoom('club', { changed: () => router.refresh() });
useUserEvent('live', (data: { event: string; title: string; host: string }) => {
if (path !== `/events/${data.event}`) show({ text: `${data.host} is live: ${data.title}`, href: `/events/${data.event}`, live: true });
});Das Erste lässt jede Seite sich selbst erneut vom Server holen, ohne Neuladen, sodass die Seitenleiste und die geöffnete Seite aktuell bleiben. Das Zweite zeigt einen Hinweis auf jeder Seite, auf der ein Mitglied gerade ist: „Mia is live: Live portfolio review“, der das Event öffnet. group.joined, group.left und stream.ended sagen changed im selben Raum.
5. Wer online ist
WordPlus Cloud weiß, wer online ist: Jede Seite, für deren Mitglied die Website gebürgt hat, macht dieses Mitglied online, und die Seite erfährt, wenn Mitglieder kommen und gehen, ohne Anfrage an den Server der Website:
const { online } = useOnline(people.map((person) => person.id));
const here = people.filter((person) => online[person.id]);
const away = people.filter((person) => !online[person.id]);Die Mitgliederliste zeigt die zuerst, die online sind, jedes Mitglied mit Message und Call, und neben jeder Seite listet das Layout den Club genauso auf, die Hosts markiert. Die Seite eines Mitglieds zeigt, ob es online ist oder wann es zuletzt da war.
Was dazugehört
- Gespräche zu zweit. Die Seite eines Mitglieds enthält Ihr Gespräch mit ihm, Fotos inklusive, und sein Anruf erscheint neben den Nachrichten.
- Reaktionen und ein Chat bei jedem Event, neben dem Bild, und live gehen aus OBS oder jedem Encoder, der über WHIP sendet.
- Bildschirmfreigabe in einer Lounge mit Kameras, über die Steuerung des Anrufs.
- Namen und Gesichter aus Ihrer App. Jede Kachel, Nachricht und Bühne zeigt Namen und Foto eines Mitglieds so, wie das
profileder Website sie liefert, ohne in WordPlus Cloud eine Liste von Nutzern zu führen. - Zugang entziehen. Wenn jemand den Club verlässt, sagen die Regeln ab dann Nein, und
realtime.call(name).remove(user)nimmt die Person sofort aus einer Lounge.
Ausprobieren, dann selbst bauen
In der Live-Demo gehört der Club einen Tag lang nur Ihnen: Was Sie dort teilen oder wen Sie dort treffen, sieht sonst niemand, und ein Event oder eine Lounge endet nach 10 Minuten von selbst. Unter jeder Seite zeigt How this page works Schritt für Schritt den Code, der sie erzeugt, mit den Werten der Seite, die Sie gerade geöffnet haben.
Die Anleitung zur Community-Website baut die ganze Website auf, mit jeder Datei ihres Echtzeit-Teils in voller Länge. Livestreams in Next.js und Anrufe in Next.js zeigen jeden Weg, einen Stream oder einen Anruf in Ihre eigene App zu bringen. Für ein Team statt eines Clubs baut Videokonferenzen in Next.js die Meetings eines Team-Intranets.
Für WordPlus Cloud for Apps gelten Preise nach gleichzeitigen Verbindungen, ab 1.000, monatlich oder jährlich abgerechnet. Mit 1.000 Verbindungen sind Livestreams bis zu 50 Zuschauern gleichzeitig ohne Abrechnung und Gruppenanrufe bis zu 32 Personen mit Video gleichzeitig, wobei eine Person nur mit Audio halb zählt. Mit jeweils 1.000 weiteren Verbindungen kommen 20 Zuschauer und 12 Personen mit Video hinzu. Darüber verbraucht jeder weitere Zuschauer und jede weitere Person mit Video ein Credit pro Minute, ein Stream gezählt nur, solange er live ist, und Anrufe zwischen zwei Personen verbrauchen keine. Sehen Sie sich Livestreaming für Apps an, Videoanrufe für Apps, oder werfen Sie einen Blick auf die Preise für Apps. Fragen zu Ihrer Integration? Schreiben Sie uns.