Repository navigation
v0.1.7
Added
- Chat offers its two acts wherever a person is shown. A guest's card on a
calendar event now carries "Chat" and "Start a meeting", performed by this
module. Offered only for someone with an account on this instance: there is
nobody to talk to behind an outside address, and a button that always fails is
worse than an absent one.
Added
- A meeting attached to an event carries that event's title. Renaming it in
the meetings list renames the event too, and renaming the event renames the
meeting — one title in two places instead of two that slowly disagree. Linked
meetings show a small link mark beside their name, so the consequence is
visible before you type. A meeting whose event lets it go (the call was taken
off it, or the event was deleted) keeps its name and becomes its own again;
its link goes on working.
Changed
-
Joining the call from an event opens it in a new tab. The link followed
in place, so reaching the meeting meant abandoning the event you were in the
middle of writing. The call also outlives the visit to the event: it belongs
in a tab of its own. -
The video-call card in an event carries no camera of its own. The row's
gutter already shows this module's mark, and the card says in words who hosts
the call; a camera an inch away was decoration, not information.
Added
-
A meeting room attached to an event you never save no longer survives it.
Adding a video call to an event has to create its room straight away — the
link is what gets saved, so it must already point somewhere. Until now that
room stayed for good, even when the event was abandoned: closing the form
without saving, or taking the call back off it, left an empty meeting in your
list that you never knowingly created. A room created that way is now a draft
and belongs to the form: taking the call off the event or closing the form
deletes it, saving the event keeps it. Reloading the page, closing the tab,
losing the network or crashing needs no cooperation either — the room carries
its own deadline and the server removes it on its own. A draft room never
shows up in anyone's meeting list while it is one, and a room somebody has
already joined or written in is never removed by any of this. -
The Meetings page lets you review and manage each meeting without joining
it. Clicking a meeting used to drop you straight into its call. Now a plain
click opens a details panel on the right instead: the day and time, the member
list, and a plain transcript of everything said in the meeting — so a past
meeting can be read back at a glance. Joining is now an explicit Join
button, which appears on a row on hover and also sits at the bottom of the
panel. -
Meetings can be deleted from the Meetings page. Each row now carries a
delete button (and one in the details panel too), removing the meeting from
your list after a confirmation. Every row also has a right-click / “⋮” context
menu — Join, details, copy link, delete — a starting set we will keep
extending. -
Select several meetings and act on them at once. A checkbox appears on
each row (on hover, or once a selection is under way); Ctrl/Cmd-click toggles
a row and Shift-click extends a range. A toolbar then shows how many are
selected, with Select all, Copy links and Delete — the deletion
asks once for the whole set. -
A meeting's options no longer look forbidden to the person who owns
them. The settings that depend on host management were greyed out until it
was switched on — which reads as "you may not", and a host quite reasonably
asked why they were refused their own meeting. Nothing is greyed now: the
settings can be prepared at any time, and a line under the master switch says
they take effect once it is on. -
A meeting can record itself. Its options gained a second section,
Meeting recordings: the legal warning — recording without everyone's
permission may be illegal — and one choice, "Record this meeting". Ticked,
the room starts recording on its own as soon as someone allowed to record is
in it, and everyone is told as they always were. It starts once per room: a
reconnection does not start a second one, and a host who stopped it on
purpose does not see it start again under them. The consent step did not
disappear — it moved to where the decision is made, under the same warning,
because asking twice for one decision teaches people to dismiss the asking. -
A meeting can run ACTIVITIES, and its host decides who may start one.
An activity is something one person launches and everyone gets — a file put
in front of the room, and whatever other modules come to offer: any module
may register one, and the room lists what it finds. Nothing is hard-wired;
when nothing is registered there is no activities menu rather than an empty
one. The host may reserve launching for themselves. -
The meeting's audio and video have exactly one door, and the host holds
the key. The media never touches a server here — it is exchanged directly
between browsers — so there is one function through which anything else in
this product could obtain it, and the host's setting is checked at that
function rather than by whoever calls it. -
A meeting can be closed to whoever merely holds its link. Its access type
is now a choice: Open — the link is enough, as it has always been — or
Open to trusted people, where only those the host put in the room walk
in. Everyone else is refused by the server, and may ask to join when the host
allows it: they see a page that sends one request and waits, the host sees
them queued inside the meeting and admits or refuses them in one press, and
being admitted puts them in the room there and then. Asking twice is asking
once. Refused twice, they may not ask again — a door that can be knocked
on forever is a way of knocking until someone gives in; from there only the
host adding them opens it. -
A meeting's host can set its rules before it starts. The ⚙ on the event's
meeting card opens the video call options: host management, who may share a
screen, who may send reactions, whether participants may write in the
meeting's chat, and whether the host must arrive before anyone else. Off by
default — the master switch has to be turned on before any of the others
apply, so a meeting stays open unless someone decides otherwise. Only the
host sees the panel, and only the host may save it: the server checks, it
does not merely hide the button. Chat moderation and "host joins first" are
refused by the server; screen sharing and reactions are enforced by the room
itself, because the media travels directly between participants and no
server stands in its path — each switch says which it is. -
A calendar event can carry a Kubuno video call, created in place. When
this module is installed, the video row of the calendar's event editor is
its own, and the row's icon becomes this module's logo: one button creates
the room and attaches its link; the event then
shows a card naming the call, with its full address, a copy button and a ✕
that takes it away — an event holds one call at a time. A link pasted from
elsewhere gets the same card, without the pretence that we host it. The
room is a conversation anyone holding the link may join; it is not deleted
when the link is removed, since an edit may be abandoned and a link already
shared is not cheap to break. -
The meeting's messaging is the conversation itself. It was a bare list of
lines with no author: you could not tell who had written what. It now loads
the history, so someone joining midway reads what was already said, groups
messages by author with a picture, a name and a time, and renders them with
the same component as the rest of the app — attachments, images, polls,
replies, reactions and link previews all work. Files can be attached and
emoji picked without leaving the meeting. -
The meeting shows who is speaking. The tile of whoever has the floor is
outlined in blue, tinted with a faint blue veil, and wears a small badge
whose three bars follow their voice. It is heard from the audio itself, so it
works for everyone in the meeting, and someone whose microphone is off is
never shown as speaking. -
Meetings can be recorded. The person who holds the meeting can start a
recording from the meeting menu. Everyone is told when it starts and stops,
and a red REC indicator with a running time stays visible throughout — a
recording is never silent. The file captures the presentation when someone is
sharing and the participants otherwise, with every voice mixed in, and it is
filed in the recorder's own files when the recording stops, in a "Chat"
folder created on first use — it belongs to whoever made it. Without a files
module to write to, it is posted to the meeting's conversation instead so it
is never lost. It is stopped automatically if the meeting ends, and after two
hours. -
A page follows leaving a meeting. Instead of dropping straight back into
the app, leaving a meeting now leads to a page offering to rejoin it or go to
the home screen, and asking how the audio and video quality was. It returns
home on its own after a minute. The rating is kept, one answer per person and
per meeting, and a later answer replaces the earlier one. -
Ending a meeting is now distinct from leaving it. The host of a meeting —
whoever owns or administers the room — is offered both when they hang up:
leaving lets the others carry on, ending closes the meeting for everyone at
once and the page that follows says so and offers no way back in. Everyone
else simply leaves. -
Host moderation. From the participants panel, a host can mute someone or
remove them from the meeting. A host can only mute: turning a microphone back
on stays the person's own decision, and the person is told who muted them.
Removal is checked by the server, not only hidden in the interface.
Fixed
-
Ending a meeting now really ends it. It was only a message sent from one
browser to the others: a client that missed it stayed in a meeting that was
over, and anyone could walk straight back in through the link. The room is
now closed on the server, every member is told over their own connection, and
a meeting that has been ended can no longer be joined — opening its link says
so plainly instead of dropping you into an empty room. Its host reopens it
simply by starting it again. -
A new presentation replaces the one in progress. When someone started
sharing while a screen was already shared, the first one kept the stage and
the newcomer was never seen. The stage now shows the latest presentation, and
a presentation that had been set aside does not hide the next one. -
The person who opened a meeting can always end it for everyone. Holding
the meeting was worked out from a single request made while joining; when it
did not answer, the host silently lost their own actions and the red button
just left the meeting. Whoever created the room now holds it, read from the
room itself. -
Everyone's camera is now sent, not only the first person's. A connection
opened before the camera and microphone had finished starting carried no
outgoing track, and nothing ever added one: that person was seen and heard by
nobody for the rest of the meeting. The tracks are now attached as soon as
the devices are ready, and the connection renegotiated. -
Leaving a meeting no longer ends it for the person left behind. The last
participant to remain used to have their window closed. A meeting is a room:
it stays open, whoever opened it and whoever leaves. Only its host ending it
closes it for everyone. A plain call still ends when nobody is left. -
A late arrival now receives what is broadcast. The room was read once, on
joining, so anyone who arrived afterwards never received changes of state —
a raised hand, a muted microphone, a recording starting. Anyone who signals
is now known.
Changed
-
Selecting a meeting no longer draws a border. Opening a meeting's
details, ticking it, and the bulk-action toolbar now just tint their
background instead of outlining it. -
This module now installs as a Kubuno package (
.kbpkg) only. Its system
packages (Debian/RPM and the Windows and macOS installers) are no longer
built: the module is distributed as one.kbpkgper platform (Linux, Windows,
macOS) that the Kubuno server installs itself — from the admin console, or
offline withkubuno modules:install <file>.kbpkg. -
Meeting objects now move instead of jumping. Tiles and the shared screen
glide and resize to their new place whenever the layout changes: someone
joins or leaves, a presentation starts or stops, a side panel opens. A tile
keeps its identity as it moves between the grid and the strip. Dragging the
window edge is not animated, so the meeting follows the pointer exactly
rather than trailing behind it. -
The strip of participants wraps onto another row. In a narrow meeting —
a portrait window, or one with a side panel open — the people above a
presentation now continue on a second row instead of being squeezed into a
single line. They keep a readable size, and only shrink if the rows would
otherwise take more than half the meeting. -
The meeting side panel is never covered. Tiles moving to their new place
used to be drawn over the panel for the length of the animation, hiding its
header and search field. The meeting is now clipped to its own area, the
panel sits above it, and the strip of participants shrinks to the width it
has instead of running past it. -
The meeting side panel stays visible at any window size. Chat,
participants, settings and effects no longer get pushed off-screen when the
window is narrowed, and the panel now sits as a rounded card set in from the
right edge. -
Your own presentation is named as yours. The stage said "Presentation by
you"; it now reads "Your presentation". -
Participant tiles are all the same size, and use the room they have.
Every tile is identical to the others whether or not the camera is on, and
when nobody is presenting they grow to take as much of the meeting area as
they can while all staying visible. -
A meeting no longer repeats who is presenting. The presentation already
names its author on the stage, so the bar above it stays quiet. It only
offers the way back when the presentation has been set aside. -
Someone with their camera off now shows their profile picture. Their tile
becomes a coloured card with a large round photo in its centre, falling back
to the initial when no picture is set, instead of a small grey badge. -
A shared screen is no longer cropped. The frame around a presentation now
takes the exact shape of what is being shared, so the whole screen is visible
and no empty band is left around it. It follows the shape live when the
shared window is resized. -
Meeting tiles are rounded squares. People now appear in square tiles with
rounded corners, in the grid as well as in the strip beside a presentation. -
The meeting panels follow the meeting. The chat, participants, settings
and effects panels were white against the meeting dark stage; they are now
dark like it, and the meeting menus use the platform menu component. -
People search now only shows members of your own organizational unit.
Starting a conversation, adding someone to a space, or picking a person to
invite lists accounts from your organizational unit (and its sub-units), not
the whole instance. Conversations you already have are unaffected. -
The RPM package now names the same maintainer as the Debian one. Its
changelog entry used a placeholder address on a domain the project does not
use; it now names the project's designated maintainer on the project's own
domain, matching the.deb. Nothing about what the package installs changes. -
The package maintainer address moved to the project's own domain. The
Debian package'sMaintainerfield now names the project's designated
maintainer on the project's own domain. Nothing about what the package
installs changes. -
Security reports now go to the project's own domain. The address
published inSECURITY.mdmoved to the project's own domain; the previous
one is retired. Reporting through GitHub Security Advisories is unaffected. -
The README now opens with the module's logo. The public README on
GitHub now shows the module's designer logo (the same PNG shown as the
browser tab icon and in the applications menu) at the top of the page — the
repository landing now matches the icon a signed-in user sees inside the
platform. The image ships in-repo, under.github/logo.png, so it renders
even when the repo is browsed offline. -
New Chat logo — a sky-blue hexagon with a white speech bubble, used as
the browser-tab icon and in the applications menu. It is now raster (PNG)
designer artwork. -
Square corners on chat popups. Docked conversation popups now have
square corners, matching the platform's flat floating-window look. -
Calls no longer contact a third-party STUN service, and can use a self-hosted TURN relay.
The web client had two public STUN servers hard-coded, so every call handed
the participants' addresses to a third party — and, STUN alone not crossing
symmetric NATs, calls from mobile networks failed anyway. The STUN/TURN
servers are now an instance setting (new "Calls" page of the chat
administration): STUN URLs, TURN URLs, and either coturn's shared secret —
from which the server mints a per-user, 24-hour TURN credential, so the
secret never reaches a browser — or a static credential.GET /chat/config
exposes them asice_servers, which the web client (and any native client)
reads when a call starts. With nothing configured, calls only connect between
hosts that can reach each other directly; the page says so. -
Classic window glyphs on chat popups and the call window. Expand is a
plain square and minimizing a call to its thumbnail uses the
picture-in-picture glyph, instead of diagonal double arrows.
Fixed
-
Cameras stay on while someone shares their screen. Sharing used to take
the place of the presenter camera on the call, so their face disappeared for
everyone the moment they presented. The screen is now sent alongside the
camera rather than instead of it: the people keep their tiles, camera and
all, while the shared screen has the stage. -
A tile always shows whether the person can be heard. The microphone
indicator had been reduced to a badge that only appeared when someone was
muted; it is back next to every name, crossed out when the microphone is off. -
The meeting menu opened behind the meeting. Menus are drawn at the top of
the page while the meeting covered the whole screen above them, so the menu
was present but invisible. The meeting now sits just below the layer menus
and dialogs use, and they appear over it as they should. -
Sharing your screen now actually reaches the others. Sharing only swapped
an existing camera stream, so from an audio call — where there is no video
being sent at all — nothing was shared; and with the camera off, the others
kept showing your avatar instead of your screen. The screen is now added to
the call when needed, the call renegotiated, and a shared screen is never
hidden by the camera-off state. Your own tile also shows what you are
sharing, so you can see that it worked. -
The meeting interface no longer mixes languages. Several new meeting and
call labels only existed in French and showed up untranslated in an English
interface. They are translated now. -
Opening a meeting link now reliably starts the call. Joining a meeting by
its link opened the room but sometimes left it silent, because the call was
started after a short delay that the page's own navigation could cancel. The
call now starts as the room opens. -
Conversation rows no longer change size when hovered. The quick actions
that appear on a conversation when the pointer is over it are taller than the
text, which grew the whole row on hover; that line now has a fixed height, so
the row stays the same size whether or not the actions are showing. -
A message you send from one device now appears live on your other
devices. The live connection groups all of a user's tabs and devices on one
channel, and a new message was broadcast to the conversation while excluding
its sender — which silenced that whole channel, so the sender's other devices
learned of the message only on reload. New messages (and read receipts) now
reach every device of every member, including the sender's own; the tab that
sent the message still shows it once. Edits, deletions, reactions and pins
already behaved this way. -
Shared photos and files showed "Media unavailable" to everyone but the
sender. Downloading an attachment ran an access check whose result was read
back with the wrong integer type, so it failed with a database error for
anyone who was not the person who uploaded the file — that is, every
recipient, for every image, video, voice message and file. The sender always
saw their own media, which is why it looked intermittent. The check is fixed;
media now loads for all members of the conversation, and non-members are
still refused. -
A withdrawn dependency is no longer used. A crate deep in the tree
(spin0.9.8, pulled in through the HTTP stack) was yanked by its authors.
No vulnerability was announced, but a withdrawn crate has no business in a
release; the lockfile now takes the version that replaced it. -
The package could not be built where
zipis absent. The Windows job of
the continuous integration has nozip, so the Windows package was simply lost
the first time it was attempted — a script failure, not a build failure. The
builder now falls back to 7-Zip, then to PowerShell.
Added
-
A presentation carries its own controls. Over the shared screen: take it
off your main screen so it becomes a tile among the others, mute or unmute
its sound, and a menu offering to set it aside (a viewer is told plainly that
they cannot end someone else presentation). In its corner: a zoom you can
then drag around, opening it in a window of its own that floats above other
applications, and enlarging it to the full screen. Sharing a screen now also
offers to carry its sound, and never proposes the meeting own tab as a
source. -
A meeting rearranges itself around a shared screen. When someone
presents, the people shrink to a strip along the top and the shared screen
takes the stage, with a banner naming who is presenting. The presentation
carries its own controls: full screen, a corner window, and a menu to stop
presenting or to set it aside; a presentation set aside comes back from that
same banner. The participants panel lists the presentation as its own entry
under its author, the way a second stream would be. -
Being added to a meeting now rings you. Someone invited from the
participants panel of a running meeting gets the same incoming-call screen as
a direct call, naming who invited them and which meeting, with accept and
decline. Accepting opens the meeting lobby, so their camera and microphone
still only start when they say so. -
A fuller participants panel, and a way back into a meeting after a reload.
The panel lists everyone under a collapsible group with the count, searches
the people present, gives each of them a menu, and lets you invite someone
from your organizational unit without leaving the meeting. Refreshing the page
no longer drops you out for good either: the tab remembers the meeting it was
in and offers to rejoin in one click, through the lobby, so the camera and
microphone still only start when you say so. Hanging up clears the offer and
closing the tab forgets it. -
The meeting's "more" menu is complete, with side panels. It offers the
layout switch, full screen, picture-in-picture, backgrounds and effects, a
phone dial-in and settings. Settings and effects open as panels on the right
of the meeting, the way the chat and participants panels do: settings picks
the microphone, speaker and camera without leaving the call; effects carries
the backgrounds, filters and appearance tabs. Two entries state plainly what
this instance cannot do rather than pretending: a phone dial-in needs a
telephony gateway, and backgrounds and filters need a person-segmentation
model that is not installed. -
A meeting now looks and behaves like a meeting. It fills the screen with
a dark stage: a bar across the top showing the elapsed time, the meeting's
name and how many people are in it; a grid of participants where each tile
carries the person's name, a badge when they are muted, and a pin control to
put them front and centre; and, past nine people, one tile standing for
everyone else. The controls at the bottom follow the same shape as any
meeting tool: microphone and camera each with their own device picker,
present, reactions, raise hand, a "more" menu (spotlight or grid, full
screen, corner window, devices) and, set apart from them, the red leave
button. On the right of the bar, the chat and a new participants panel that
lists everyone with their microphone state. -
Joining a meeting now goes through a lobby. Before a meeting's call
starts, a preview screen shows your camera and microphone, lets you turn
either off and pick your input and output devices, then a "Join the meeting"
button enters the call with those choices. Every way into a meeting — the
instant meeting, a meeting card, a shared meeting link — passes through it. -
A "Meetings" page. A new "Meetings" entry in the sidebar opens a
full-width page with a day header and a navigable week strip, the day's
meetings grouped into "Upcoming" and "Past" (each shown with its time and
title, with a "Join" button) and a field to join a meeting by its link.
Creating a meeting stays on the sidebar's "New" button. It is the home for
the chat's meeting rooms. -
The "New" button now starts meetings. Alongside "New message", it offers
"Start an instant meeting" (creates a meeting room and drops you straight into
its video call), "Create a meeting for later" (creates the room and hands you
a shareable link, copied to the clipboard), and "Schedule a meeting" (opens
the calendar), the last shown only when the calendar module is installed. -
This module now ships a
.kbpkg— the single package format a Kubuno
server installs by itself, the same file on Linux, Windows and macOS. It
carries the same binary, interface and manifest as the system packages,
arranged the way the server expects to find a module on disk, plus a
SHA256SUMSso a copy carried offline can be checked without the catalogue.
Nothing changes for existing installations: the.deb,.rpm,.exeand
.pkgare still published, and a catalogue that sees both simply prefers the
new one. It is also the only format the server can unpack without an external
tool, which is what makes one-click installation possible away from
Debian-like systems.
Fixed
-
A built package could be thrown away instead of published. The job that
attaches a package to the release waited ten minutes for another workflow to
create that release, then gave up with "release never appeared — build.yml
likely failed". The diagnosis was wrong: on a repository whose.debtakes
longer than ten minutes to build, the release simply did not exist yet, and a
package that had built perfectly was discarded. Four modules reached v0.1.6
with packages missing for some systems because of it. The job now creates the
release itself when it is missing, so it no longer depends on another workflow
finishing first. -
Loading older messages could skip or repeat some. The "load more" cursor
compared message identifiers, which are random, while the history is ordered
by date — so a page boundary could land anywhere and a long history was
walked non-deterministically. The cursor now resolves to the pivot message's
date and identifier, and pages are strictly older than it in the very order
they are displayed. The API is unchanged for clients. -
Retrying an interrupted send no longer fails. When the network dropped
in the middle of a send and the client retried with the same nonce, the
server answered "nonce already used" and the client showed an error for a
message that had in fact been stored. A retry by the same author now returns
the existing message (flaggedduplicate) — the nonce acts as an idempotency
key, which is also what an offline relay re-injecting the same envelope
needs. A nonce reused by another user is still refused as a replay. -
A deleted message no longer vanishes from the thread on reload. Live,
a deleted message showed "Message deleted" in its place; after reopening the
conversation it was simply gone, leaving the reader to wonder what had been
there. Deleted messages now come back as empty placeholders (typedeleted,
no content), like every mainstream messenger. Messages removed automatically
— expired ephemeral ones, or those past the instance retention — stay
hidden, as before. -
Every event arrived once per hour the tab stayed open. The chat's live
connection was re-established each time the session token was renewed, but
the previous connection's closing handler fired after the new one had
started and reconnected on its own — so a tab open for an hour held four
connections and received four copies of every message, typing indicator and
call signal. Duplicate call signals made the browser renegotiate the same
call several times, which is why a call could show "Connecting…" forever
even when the network path was fine. Each connection now only ever
reconnects itself. -
The call window closes by itself when the last other participant hangs
up. It used to stay open on an empty call, leaving the user to hang up on
nobody. It now closes as soon as nobody else is left — also when the person
you were ringing declines. The initiator of a meeting room who has not been
joined yet keeps the window open, since that call has not started. -
Declining a call now tells the caller. Tapping the red button on an
incoming call only closed the overlay; the caller kept ringing until they
gave up. The caller's window now closes at once. -
An audio call can turn into a video call without hanging up. The camera
button now works during an audio call: it opens the camera, adds the video
to everyone in the call and switches the window to the video layout. It
turns to video for the others too the moment anyone's camera comes on, and a
participant who keeps their camera off shows their avatar rather than a black
frame.
Added
-
Security policy and CI quality gate. A
SECURITY.mddocuments how to
report vulnerabilities, and a CI workflow enforcesclippy -D warnings, a
dependency-vulnerability audit (cargo audit) and the frontend typecheck/tests. -
Push notifications for new messages and incoming calls. When a message
becomes visible to the other members of a conversation (sent now, or
delivered by the scheduler), Chat now asks the core to notify their
registered devices (UnifiedPush) — so a phone with the app asleep still
learns that something arrived. The notification carries who wrote, never
what: the title is the sender's name (or the group's name, with the sender
in the body), the body is generic, and it links to the conversation. Members
who muted the conversation or set themselves to "Do not disturb" are not
notified, and each user's per-module push preferences in the core still
apply. An incoming call rings the callee's devices the same way
(chat.call_ring), so a native client can show its full-screen call UI. -
The conversation list now carries each conversation's latest message.
Every entry ofGET /conversationsincludes alast_messagepreview (the
newest message the caller may see, in the same envelope as the message
list), so a client can show a preview per row in one request instead of one
per conversation.
Security
- Chat now authenticates proxied requests from a signed token instead of
trusting plain headers. Requests must carry a validX-Kubuno-Authtoken
minted by the core with this module's internal secret (seekubuno-modauth),
rather than readingX-Kubuno-User-*headers at face value — which any process
reaching Chat's loopback port could otherwise forge to act as any user.