The job inherited the implicit success() and was skipped whenever the build job
upstream was skipped (images reused). It now checks publish explicitly, like
publish does. Notes come from the matching CHANGELOG section through
scripts/release-notes.sh, not from the commit log of the whole history.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Release hashes services/, migrations/ and config/; when images for that hash
already exist it skips CI and the build and only applies the new tags. Tagging
a release no longer recompiles the webmail.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- CHANGELOG.md and CHANGELOG.pt-BR.md, from the project history.
- .env.example now serves development and production; scripts/init-env.sh
(make env) creates .env with random secrets. .env.production.example is gone.
- docs/RELEASING.md: the pipeline, how a version is cut and deployed, the runners.
- DEPLOYMENT.md and both READMEs updated for Gitea and the new env flow.
- Service versions set to 1.0.0.
- CI: the proxy network step is idempotent and the stack is torn down always,
since the runner's Docker daemon now outlives a job.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Release workflow only ever published container images; there was no entry
under Releases. The new job runs after every image is published and writes the
image list and the commit log since the previous tag.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
npm and Go module caches, the embedded Postgres binaries, Trivy's database, and
the daemon's own layer cache for image builds. The webmail Next build is no
longer run a second time outside the Dockerfile.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The default 5s does not fit a chain of 11 hashes on a shared CI runner. The
production cost parameters are untouched.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The job workspace is a volume the DinD daemon cannot see, so migrations and the
Trivy filesystem scan now docker cp their inputs. Trivy's image gate flagged
next 15.5.27 (unauthenticated RCE in image optimisation, fixed in 15.5.28) and
go-jose 4.1.4 (DoS, fixed in 4.1.6); both are patch bumps.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
aquasecurity/trivy-action clones the Trivy repository from the workflow's own
server, which on Gitea is not GitHub. The gha buildx cache has no Gitea
counterpart.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Release now pushes to git.lucasrguerra.dev.br instead of ghcr.io, tags each
architecture separately (no artifact upload, no gha cache) and joins them with
imagetools. GITHUB_OUTPUT and GITHUB_STEP_SUMMARY stay: they are the runner's
own interface and the GITEA_* equivalents are not set.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Release now pushes to git.lucasrguerra.dev.br instead of ghcr.io, tags each
architecture separately (no artifact upload, no gha cache) and joins them with
imagetools. Workflows live in .gitea/workflows and use the gitea context.
GITHUB_OUTPUT and GITHUB_STEP_SUMMARY stay: they are the runner's own interface.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The README opens like a product page: the mark, a line on what it is, the
links, the language switch and a picture of the real interface running on an
invented mailbox, in dark and light and in both languages. scripts/screenshots
holds that invented mailbox and the script that photographs it, so the pictures
can be redone. Previews now decode any HTML entity through the browser rather
than a short list, so a Portuguese or marketing preview no longer prints
ç or ·.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
README: what the webmail now does, the architecture roles, a short guide with the
shortcuts, testing with a real database, and an honest list of what is not
finished. New docs/WEBMAIL.md as the reference for each feature and for the
colour system. OPERATIONS: sessions and trusted senders. DEPLOYMENT: the
two-step release as API calls, and what to expect when upgrading. MAILBOX-CORE:
the conversation invariants and migrations 0015 to 0018.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The mark is rebuilt as a lambda of two square-cut strokes of one weight, joined
without a seam, on a flat ultramarine tile with continuous corners: the rounded
strokes and the gradient are gone. A message written plainly is now drawn in the
app's own colours instead of a white slab, with text too dark for the ground
lifted and white backdrops cleared; a designed one (newsletter, receipt) keeps
its white sheet. A reply's quoted history folds behind a button. A narrower
reading column, a larger title, and a way to see a plain message as sent.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A mark (a lambda on an ultramarine tile with the flap of an envelope), the
favicon, home-screen icons and an install manifest. Every colour is a variable
defined once per theme, and the Tailwind scales the screens already use read
them, so dark (the default) and light are a change of values and not of
classes. Geist is served by the app itself. Ctrl+K opens a command menu for
folders, actions, accounts and appearance, and typing something that matches no
command searches the mail; c writes a message and / goes to the search field.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The countdown sent from inside a state updater and Undo's button submitted the
form, so Undo stopped the timer and then started the send over. The timer is
now held in a ref, Undo is type=button, and leaving the screen flushes a
pending send once. Snippets drop a stylesheet the preview was cut inside of.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A reply now joins the conversation of the message it answers (Message-ID,
In-Reply-To, References), falling back to the subject for replies with no
headers. /mail/threads lists a folder as conversations and /mail/thread/{id}
returns one. Replying from the webmail flags the answered message.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The button was a link to the inbox, so the autosaved draft stayed in Drafts.
It now removes the stored draft for good (not into Trash), stops the autosave,
and cleans up a save that was already in flight.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A browser signed in before account cookies existed has only lm_user_session,
so the switcher showed it as loading forever. The active session now always
counts and is filed on first listing. Message previews drop the HTML and
entities the server stored.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
issueSession raised the cookie and the session row to 30 days but still let
createJwt default to 8 hours, so the session would have died at 8 hours with
a cookie that outlived it. Also covers account switching, sign-out and
renewal against a real database.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The webmail session now lasts 30 days and is swapped for a fresh token once a
day while in use; the console keeps its fixed 8 hours. Each sign-in is also
filed under lm_acct_<mailbox id>, with new endpoints to list and switch
accounts, and sign-out now leaves the other accounts signed in.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Two bugs found by the setup check right after the last deploy:
- every domain's BIMI record named the deployment's own mail host, and the
server picked the domain from the host name, so only the primary domain's
logo could be fetched: ciberlab.seg.br's record pointed at a 404. The logo
and the certificate are now served at /.well-known/bimi/<domain>/..., the
record names that, and the webmail routes it. The old path still answers
- SetBimiPublisher ran before SetBimiAPI, found no BIMI API to attach to and
was dropped, so saving a logo never published the DNS record by itself. It is
kept on the router now, so the order does not matter
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The reconciler never wrote the BIMI record: only the console's verification
knew about it, so a stored logo was never published to the zone.
- SyncDnsRecordsInput carries the BIMI logo and certificate URLs; the record is
created, updated (a= added or dropped) and, when the logo is removed,
deleted. Only a record carrying this reconciler's comment is retired: one
made by hand is left alone
- bimi.Publish decides the record in one place for the timer sweep, the
console's button and the panel's verification. A held certificate is
advertised only while it is valid for the logo being served: replacing the
logo ends the certificate, and a record that kept naming it makes every
receiver reject BIMI, including those that need no certificate
- saving or removing the logo or the certificate triggers the reconciliation in
the background; the panel shows the record as the server writes it, says when
a certificate is held back and why, and has a publish-now button
- a read error is not 'no logo': the sync leaves the record alone instead of
deleting it over a database hiccup
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>