Chat stays usable when the file service is off or down. Files up to 256 MB are hosted like chat; downloads try the host first and fall back to file-service tickets.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> [CI]
Chat stays usable when the file service is off or down. Files up to 256 MB are hosted like chat; downloads try the host first and fall back to file-service tickets.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> [CI]
Space info now carries avatar_version instead of the inlined thumbnail; the worker fetches the thumbnail once per version. Legacy base64 rows are migrated to files on startup, and the daily backup uploads avatar files.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> [CI]
- dev images are built only when the push touched code that image uses (path filters);
webdrop-files does not wait for the frontend build
- one v* tag releases both images (:tag and :latest) after the shared checks
- registry build and push live in scripts/ci-publish-image.sh, used by every workflow
- containers: fix the api Containerfile (missing Sync project), add Containerfile.files,
Quadlet units for the file service (prod and dev), env examples, and registry
auto-update for the production units so each machine pulls only the image it runs
- dissolve core-bridge into api (wire contract), domain (models), services (what the UI
calls) and worker (everything that runs in the Web Worker, grouped by account, crypto,
space, files, shares, runtime); regroup features, lib and store by responsibility and
delete unused components
- the UI only reads backend capabilities (domain/capabilities); one tokenRole picks the
token, hasCode/isRetryable handle errors; pre-checks that decided permissions on the
client are gone; tests fail if those rules are reimplemented
- files go straight to the file domain (create, upload, download, delete, commit, cancel);
the host sees one registration per file; creating a channel allocates a file domain and
works even when the file service is down
- file panel shows which channel the files belong to and its space usage; unlimited files
preview in chat; videos get a stored cover; the file service status is shown
- fix: console flooded by Retry-After reads on every upload frame
- all authorization rules (owner/creator, per-channel read/write grants, who may
remove whom, delete rules, structure management) live in ChannelPolicy; a test
fails if they are reimplemented elsewhere
- ChannelInfo carries what the caller may do (can_*), member and invitation lists
say who can be removed; clients display it and never derive it
- the host no longer stores or calls the file service: it only signs short-lived
tickets from space permissions (create/put/get/delete/domain), and keeps an opaque
fileDomain reference on the channel
- a whole file is registered in one request (last frame header + per-frame length and
digest) instead of one request per 1 MiB frame; the signed manifest still has to
match every digest
- drop file quota/threshold, receipts, reconcile and delete-queue code from the host
- contract generator emits constants for enums, error codes, token roles, permissions
and share states
- file domains are created, queried, sized and deleted by the file service
(POST/GET/DELETE /file/v1/domains), with per-domain quota enforced on write
- /file/v1/options publishes the quota choices; nothing about files lives on
the host any more
- tickets carry the issuing space and a unique id: a domain only accepts tickets
from its own space, and read/delete tickets work once (no replaying a counted
download)
- uploads stay pending until the client confirms them; abandoned ones are swept
after 24h, and an upload ticket can cancel its own bytes
- backup target is S3 (SigV4 client, no SDK) instead of WebDAV
- CORS allows the methods the browser really uses (POST, DELETE) and exposes Retry-After
- structure mutations returned the full structure to any member who could call them (moving an item after sending a message exposed channels the member has no access to)
- moving items now requires write access to the destination channel; new folders require an existing channel
- account avatars are only readable by the owner or accounts sharing a space
- new projects WebDrop.FileApi (file service), WebDrop.FileProtocol (shared tickets and receipts) and WebDrop.Sync (WebDAV)
- file content of any size goes to the file service; chat, avatars and space structure stay on the main backend
- tickets issued by the main backend, receipts by the file service, deletion queue and daily reconciliation
- daily database snapshot and file sync to external storage (OpenList/WebDAV) with a 30 day retention
- reorganize Core, Storage and Api into feature folders (namespaces unchanged)
- web client uploads file frames to the file service and reads them with tickets
Messages from other members or devices used to render as an unknown member
until the space structure refreshed. Use the author account the server
records for the object, together with the loaded profiles, when the item
arrives.
Opening a space link while signed out shows the sign-in page first and keeps
the link in memory. The channel settings no longer offer the stranger switch,
and the client supports API contract major 8.
Drop unauthenticated guests from channels: the allow_guests setting, the
/guests endpoints and the guest seat table are gone, and requests without an
account session get 401 account_required. Share links are unaffected.
Contract version is now 8.0.0.
Activate the account with parallel requests, run the full vault sync in the
background, skip the duplicate space list request, and send the rejoin
together with the first screen of data. [CI]
Spaces, channels, files, members and the account move into a left drawer,
the top bar keeps only the essentials, and touch devices get a tap menu
instead of always-visible delete buttons. Also fixes the history checkboxes
in the channel settings sheet.
Accepting an invitation no longer waits for the vault sync, the redundant
join right after joining is skipped, and the crypto state, first log page and
channel metadata are requested in parallel.
Two side-by-side zones (stacked on narrow screens) with an icon and a
one-line positioning each: quick share is temporary, read-only and needs
no account; spaces are long-lived, multi-user and need a login. Shorter
copy, my shares listed under the share input, and an empty state for
spaces.
- account settings: sidebar sections (profile, devices, security,
invitations, sync and sign-in) instead of one long scroll; inline device
rename, confirmations for destructive actions and toast feedback
- sign-in/register: split layout with a quiet brand column, text tabs and
underlined inputs; registering asks for the password twice and explains
that it cannot be recovered
- move invitation accept/label helpers into store/invitations so the
toast and the settings inbox share them
- add the home page zone styles used by the next commit
- chat: left-aligned discord-style messages with grouped senders, hover
actions, an auto-growing composer and file cards
- send: render messages and files locally first and replace the
placeholder when the worker publishes the real item; failures keep the
text with a retry action
- navigation: space rail plus a flatter channel list with the space name
header and collapsible groups
- members: right pane tabs (files / members) grouped by online, offline
and pending users, with a prominent invite action and a top bar shortcut
- notifications: toast host for invite results; invitees get a toast with
an accept action, and the invitation payload now carries the space name
and inviter inside the encrypted grant
- users over devices: drop device names, the device list and device
rename/release; senders show the account (guests show as guest) and the
share panel only keeps links
- follow contract 7.0.0 (max_members, members_used, members_full, /join)
- docs: ui-design and frontend updated for the new layout and concepts
Remove sealLabel/openLabel and their label constants; devices are no
longer named per channel. Rename the create setting seats to
max_members and point the e2e join helper at POST /join.
Contract 7.0.0 (breaking). Devices become an attribute of the account;
members are managed per user, and only unauthenticated guests keep a
per-terminal registration.
- rename seats -> max_members, seats_used -> members_used,
seats_full -> members_full, SeatJoined -> JoinResult, the `seats`
stream control message -> `members`, and POST /channels/{id}/seats ->
POST /channels/{id}/join (stored channel settings are migrated on start)
- drop per-terminal encrypted device labels and the seat list/release
endpoints; add GET/DELETE /channels/{id}/guests for guest terminals
- authenticate account members by account session only: the terminal key
is optional for logged-in accounts, no seat row is written for them,
and gated-download grants are counted per user (per terminal for guests)
- GET /channels/{id}/members now returns online, devices and
online_devices per account; presence is tracked in memory from active
WebSocket/SSE subscriptions and is not pushed over the stream
- owner invitation list no longer returns accounts that already joined