Add standalone invoice create/poll flow with unique subaddresses, a public
/pay/monero page, Oban poller, and optional Docker wallet-rpc sidecar. No
product unlock hooks—payments only.
S3/Magpie crashed in production because ExAws still called hackney after
it was dropped from the release. Point ExAws at Elektrine.HTTP (Gun), and
move NetBird plus the DNS tunnel agent off :httpc so outbound HTTP is one
stack.
Infer content type from the filename when the client sends an empty type
or application/octet-stream. Stop canceling transfers when the file
picker closes via click-away, and surface real save errors in the flash.
Browser img tags send Accept: image/* which the browser_api pipeline
rejected with 406. Route media through a dedicated session pipeline and
block public /uploads/kairo-sources/ static access.
finish_elevation logged a String.slice of the binary credential id into
JSONB, which raised Jason.EncodeError and returned 500 after a valid
passkey. Base64url-encode the prefix, JSON-sanitize audit details, and
never fail elevation if the audit row cannot be written.
Moving hackney (and its certifi dep) out of the prod release left
GunPool calling missing :certifi.cacerts/0, which crash-looped the app
and caused edge 502s. Use :public_key.cacerts_get/0 like the rest of
the TLS client stack.
Prove DNS zone ownership with per-zone TXT tokens and reserved operator
domains, harden auth/mail/VPN/edge paths against the remaining audit
findings, and tighten deploy/config hygiene so self-host defaults and CI
cannot reintroduce the same failure modes.
Open an upload dialog so project/tags can be set before save. Support file
wikilinks and ![[embeds]], copy [[title]], flexible title matching, and
autosave title/project/tags when selecting images and PDFs.
Export, parse, preview, and apply zone text with managed-record protection.
Add a Zone file tab and lower the DNS raw-btn design budget after kit cleanup.
Use a single rounded editor shell in mail and notes, keep badges from
stacking vertically, restyle uptime to match other product cards, and
pin mbox MIME extension preference.
Ship an Obsidian-style shell with wikilinks, backlinks, server search,
inbox triage, keyboard palette, mobile stack, file reader for media,
hashtag-style tags, and drag-and-drop source uploads.
MIME extension validation crashes when mime is not recompiled with
mbox/vcard. Accept any file at the LiveView layer and validate
extensions in the import handlers instead.
Add mail import (mbox/eml/zip), contact vCard import, and Nerve
encrypted backup plus client-side CSV import. Wire settings and
Nerve UI, API export/import endpoints, and tests.
Add Address.resolve/open so one handle fans out to DM, mail compose,
and profile (local or WebFinger). Ship authenticated API endpoints,
/address LiveView contact card, nav entry, and tests.
Default force-recreate only updates app/worker/mail/vpn. Edge services
(dns, turn, caddy) stay running so public :53/:443 keep answering; Caddy
config changes reload in place. Use --force-infra when edge containers
must be recreated. Admin VPN dashboard totals now use account quotas.
Also polish the 2FA challenge UI.
Removes catch-all private function clauses and error branches that the
call sites can no longer produce, and switches the remaining callers to
plain matches so a real regression fails loudly instead of being
swallowed by a generic 500/422 arm.
The stable gutter reserved a permanent ~15px strip on the right of the
sidebar even when no scrollbar was shown. Use a thin overlay scrollbar
instead, matching .app-sticky-sidebar-scroll.
Drop product subscriptions, paid registration checkout, admin products
UI, subscribe LiveView, webhooks, and stripity_stripe. Registration
with invites stays invite-only; social/RSS/push/IMAP subscribe paths
are unchanged. Add a migration to drop the billing tables.
Null client IPs after a 14-day window, skip network metadata on Tor and
invite/payment signup, wipe privacy data on account delete, add lite 2FA
and captcha credit claims, and fix Gun plain-HTTP protocol selection so
Haraka DKIM sync no longer crashes on connecting.
Add lite login/register with embedded captcha, account settings, prefer
lite/full cookies, and hardened captcha flows. Persist the Nerve
extension API token in local storage so browser restarts do not drop
auth, and save website entries via LiveView pushEvent.
Sync from API used a method=post link that built its form only on click, so
action-grant re-sign never attached and the POST bounced to elevate without
updating last allowlist apply. Use a real form, intercept dynamic admin POSTs,
omit empty WebAuthn transports that block the passkey prompt, and surface
elevation/sync errors instead of failing silently.
Lite cannot do real browser PoW without JS, and server mining was a bad
trade. Remove /lite/challenge entirely. External mail still spends
Identity Credits earned on the full site.
Add chunked server-side PoW under /lite/pow so Tor/JS-disabled clients
can earn Identity Credits for external mail and clear the site gate via
noscript fallback without browser mining.
Ship /lite as HTML+CSS only (no app.js/LiveView). Onion hosts default
/ and /login there. Includes public feed, post, cached remote actor,
and classic password login for privacy-minded clients.
Remote actor/community/post templates already use social-page-wrap for
max-w-7xl padding. Without the layout full-width flag, the app shell
added a second pad and looked narrower than timeline.
Self-host heartbeats only reach the VPN role. The app role was seeding
those servers and marking them offline after the timeout, so the profile
UI showed zero available servers.
Disable durable VPN session logs and never store client IPs. Drop admin
body decrypt and impersonation. Default mail privacy (no raw copy, no
inbound MTA IP, trash/spam retention). Tighten compose caps and split
edge/db networks; gate Tor/VPN packages by release modules. Update legal
copy and operator hardening docs.
Quota lived on each peer config, so adding a device (or revoking and
re-adding) reset usage. Track usage on vpn_account_quotas instead, suspend
all profiles when the account is over limit, and keep the ledger through
device revoke/recreate.
Docker creates a directory when a missing file path is bind-mounted; ensure
the allowlist snippet exists (and is not a leftover directory) before compose up.
Peer CIDRs are written to a host-mounted Caddy snippet and applied with
caddy reload plus Phoenix rpc, so hourly NetBird sync no longer force-recreates
the edge container or restarts the app.
Compose still planned "Creating" for elektrine_caddy_edge after NetBird
rewrites, which aborted the batch even when labels looked correct. Remove
the fixed-name container before force-recreate, retry missing services,
and include vpn in critical recovery.