Commit Graph
179 Commits
Author SHA1 Message Date
Lucas RayanandClaude Sonnet 5.5 58d6f8e9e2 docs: sessions, accounts, trusted senders, conversations, themes and the new reader
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>
2026-10-23 06:24:36 -03:00
Lucas RayanandClaude Sonnet 5.5 c00134f2eb chore: keep the logo generator in the repository
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 06:12:49 -03:00
Lucas RayanandClaude Sonnet 5.5 8db69c5af9 Merge feat/viewer-and-logo: a drawn logo and a reader that suits both themes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 05:57:52 -03:00
Lucas RayanandClaude Sonnet 5.5 fece870d49 feat(webmail): a better reader and a drawn logo
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>
2026-10-23 05:57:52 -03:00
Lucas RayanandClaude Sonnet 5.5 9e50b47b5d chore(wolf): record what this stretch of work taught
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 22:44:54 -03:00
Lucas RayanandClaude Sonnet 5.5 d29ecec8d9 Merge feat/new-interface: logo and icons, dark and light themes, command menu
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 22:33:15 -03:00
Lucas RayanandClaude Sonnet 5.5 e667843b59 feat(webmail): the new interface - logo, dark and light themes, command menu
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>
2026-10-22 22:33:15 -03:00
Lucas RayanandClaude Sonnet 5.5 6b97807856 Merge feat/conversations: conversations in cascade, answered marker, reply under the conversation, and Undo send that undoes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 22:07:40 -03:00
Lucas RayanandClaude Sonnet 5.5 897f0122f4 fix(webmail): Undo send really undoes, and a send is not made twice
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>
2026-10-22 22:05:43 -03:00
Lucas RayanandClaude Sonnet 5.5 2080489319 feat(webmail): conversations - list, stacked reader, inline reply, settings switch
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 16:46:11 -03:00
Lucas RayanandClaude Sonnet 5.5 86a69d1a96 refactor(webmail): the composer is a component, so a reply can be written under a conversation
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 16:41:59 -03:00
Lucas RayanandClaude Sonnet 5.5 997dd8848f feat(auth): conversation_view preference, on by default
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 16:40:36 -03:00
Lucas RayanandClaude Sonnet 5.5 67d0c8aa5a feat(protocols): conversations - thread_id and in_reply_to written at delivery, list and read APIs
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>
2026-10-22 16:38:36 -03:00
Lucas RayanandClaude Sonnet 5.5 ff89e9dc44 chore(wolf): log the discard-draft bug
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 16:03:20 -03:00
Lucas RayanandClaude Sonnet 5.5 657a43d612 fix(webmail): Discard really discards the draft
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>
2026-10-22 16:02:27 -03:00
Lucas RayanandClaude Sonnet 5.5 d283ff6f8d Merge feat/trusted-senders: a sender the mailbox trusts skips spam and always shows images, kept on the server
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 15:48:35 -03:00
Lucas RayanandClaude Sonnet 5.5 d2611d39fa feat(webmail): trusted senders on the server, Not spam, and a trust pill in the reader
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 15:48:35 -03:00
Lucas RayanandClaude Sonnet 5.5 d7f9659b5e feat(protocols): trusted senders are not filed as spam, when the message proves its sender
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 15:45:10 -03:00
Lucas RayanandClaude Sonnet 5.5 b536ed13e7 feat(auth): trusted senders table and API
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 15:42:30 -03:00
Lucas RayanandClaude Sonnet 5.5 cc0adcd94d fix(auth,webmail): list a pre-accounts session in the switcher; preview as plain text
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>
2026-10-22 15:23:40 -03:00
Lucas RayanandClaude Sonnet 5.5 026f24a64a fix(auth): sign the webmail token for 30 days, not only its cookie
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>
2026-10-22 15:04:24 -03:00
Lucas RayanandClaude Sonnet 5.5 54203d596e Merge feat/persistent-sessions-accounts: 30-day sliding sessions, several accounts at once, mail rendered with its own styles
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 14:47:44 -03:00
Lucas RayanandClaude Sonnet 5.5 641ab4bbe8 feat(webmail): keep a message's own stylesheet so designed mail renders as sent
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 14:45:34 -03:00
Lucas RayanandClaude Sonnet 5.5 96e624dd12 feat(webmail): account switcher for the several signed-in accounts
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 14:44:50 -03:00
Lucas RayanandClaude Sonnet 5.5 0efc8f096a feat(auth): 30-day sliding webmail sessions and several accounts signed in at once
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>
2026-10-22 14:42:59 -03:00
Lucas RayanandClaude Sonnet 5.5 aea4c1ee5e Merge fix/bimi-per-domain-urls: each domain's BIMI logo under its own URL, and the DNS publisher wired
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 18:53:50 -03:00
Lucas RayanandClaude Sonnet 5.5 60c6f5731c fix(bimi): each domain's logo under its own URL, and the publisher actually wired
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>
2026-10-16 18:49:52 -03:00
Lucas RayanandClaude Sonnet 5.5 e3366ef09d Merge feat/bimi-dns-reconcile: publish the BIMI record to Cloudflare and keep it in step with the logo
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 18:38:16 -03:00
Lucas RayanandClaude Sonnet 5.5 6e49ca00e2 feat(bimi): reconcile the BIMI record to Cloudflare and keep it in step with the logo
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>
2026-10-16 18:17:07 -03:00
Lucas RayanandClaude Sonnet 5.5 0ff9028927 Merge feat/bimi-studio-and-avatar-cache: BIMI logo studio, certificate hosting and instant profile photos
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 17:15:05 -03:00
Lucas RayanandClaude Sonnet 5.5 e0e5b1b880 test(webmail): keep the byte-count test ASCII (lang-lint R9)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 17:08:41 -03:00
Lucas RayanandClaude Sonnet 5.5 dabd1568d1 feat(bimi): logo studio, certificate upload and a setup check in the console
The console took pasted SVG text and a URL. It now:

- takes a PNG or SVG and makes the logo BIMI accepts (SVG Tiny PS, square,
  at most 32 KB). An SVG has what the format forbids removed and is told what;
  a PNG is traced into vectors in the browser (imagetracerjs, public domain),
  walking down quality presets until it fits. The person positions it as in the
  photo editor: drag, zoom, background colour, preview in a circle or rounded
  square, and downloads the exact SVG to give a certificate authority
- holds the .pem the authority returns, validated against the logo and domain,
  and serves it at /.well-known/bimi/vmc.pem (routed by the webmail)
- shows the DNS record and runs the setup check (logo, DMARC, record, public
  URLs, certificate)
- a golden-file contract: the SVGs the studio produces are validated by the
  server's own validator (Go) and pinned by the studio's tests (TS)
- found by those tests: an element inside a link kept its onclick when the
  link was unwrapped; links are now unwrapped before cleaning
- the BIMI and photo texts are in Brazilian Portuguese with accents (they had
  been written without), and in Spanish with accents

A VMC cannot be generated from an image: it is issued by a certificate
authority. The README and the panel say so.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 17:04:35 -03:00
Lucas RayanandClaude Sonnet 5.5 109b8360dd feat(bimi): hold the certificate, check the whole setup, serve the VMC
A Verified Mark Certificate cannot be made here: an authority issues it after
checking the organisation. What the service can do is hold the file the
authority returns, serve it where the DNS record points, and refuse one that
would make receivers ignore BIMI without a word.

- migration 0015: domain_bimi keeps the PEM chain next to the logo
- bimi.InspectCertificate reads a chain and reports every reason it would not
  work: private key blocks refused outright, the brand-indicator usage, the
  validity period, the domain (exact, wildcard or organisational), and that
  the logo embedded in the certificate (gzipped data URI in the logotype
  extension) is byte for byte the logo being published. Tested against two
  real public VMCs (eBay via DigiCert, CNN via Valimail) plus mutations
- GET /.well-known/bimi/vmc.pem (public, conditional, cacheable for an hour),
  and PUT/DELETE /api/v1/admin/bimi/certificate; the GET of the logo now
  reports the certificate as it stands against the logo being served, and
  replacing a logo under a held certificate says it no longer matches
- GET /api/v1/admin/bimi/check looks at what a receiver would: the logo, DMARC
  enforcement, the BIMI record, the public logo URL, the certificate and its
  public URL. Its HTTP client is HTTPS only and refuses non-public addresses
  after DNS, since the URLs come from DNS and an operator field
- the DNS record points a= at the held certificate when there is one

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 16:50:33 -03:00
Lucas RayanandClaude Sonnet 5.5 c0f556b190 fix(webmail): a new profile photo shows up everywhere at once
The photo endpoint was cached for five minutes with no revalidation, and only
the settings page added a version to the URL, so the header, the message list
and the reader kept the old photo until it expired.

- every <Avatar> reads a per-address version (and refetches when it changes);
  saving or removing a photo bumps it, in this tab and the other open tabs
- the server answers private, max-age=60, must-revalidate, so a stale copy
  lives for a minute at most and then costs one 304

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 16:44:14 -03:00
Lucas Rayan d82cf71f5b Merge branch 'refactor/mailbox-core' 2026-10-16 13:47:10 -03:00
Lucas RayanandClaude Sonnet 5.5 f2951c0ff4 docs: describe the mailbox core, its invariants and lock order
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 13:36:21 -03:00
Lucas Rayan 183191d18d refactor(mail): one send path for Sent, a fixed lock order, and concurrency tests
- the webmail's Send no longer files its own Sent copy: it asks Submit to
  (FileSentCopy), the same path SMTP clients use, so the rule exists once
- every operation now locks the folders first (lowest id first) and the message
  after. Opposite moves, and a move racing a flag change, deadlocked (SQLSTATE
  40P01) because they took those locks in different orders; the new test
  reproduces it (10-19 s of retries, errors) and passes in ~1 s with the order
- TestOneMailboxEverywhere drives SMTP, IMAP and the webmail on one mailbox,
  mixing them, and checks after each step that every view agrees with the others
  and with the rows. It fails on the previous code and passes now.
2026-10-16 13:30:59 -03:00
Lucas Rayan 67bbe7a50a refactor(mail): IMAP and the webmail read folders and messages through one MailStore
The folder list and the message list were two queries over the same tables. IMAP
took a folder's message count from a cached column and the webmail counted rows,
so the two could disagree. Both now ask MailStore, which counts the messages.
2026-10-16 13:22:05 -03:00
Lucas Rayan a8941a6191 refactor(mail): one definition of the standard folders, and reconcile the drift
The console created Reports, the CLI that makes the first administrator did not,
so that account had no folder for DMARC and TLS-RPT reports. The list now lives
in one SQL function, provision_default_folders (migration 0014), which both call.

The same migration reconciles what the two paths had left wrong in existing
mailboxes: folder counters and the mailbox's used bytes are recomputed from the
rows (only where they differ, so it is safe to run again).

create-admin can now be tested: fail() throws instead of exiting, and the command
runs only when invoked as one. The new test fails on the old code (no Reports).
2026-10-16 13:19:55 -03:00
Lucas Rayan caf52c0225 refactor(mail): one MailStore changes message state for every path
Flags, expunge, move, copy and folder deletion each existed twice: once for IMAP
(FlagRepository, ExpungeRepository, CopyRepository) and once for the webmail
(WebmailRepository). They kept the cached numbers true on their own and drifted:

- reading a message over IMAP never moved the folder's unread counter
- deleting in the webmail, or deleting a folder, never gave the quota back
- an IMAP expunge could push a counter below zero

MailStore now holds each state change once, in one transaction, with the same
rules everywhere: counters never go negative, a change that alters what a client
can observe raises the folder's modseq (one that alters nothing does not), the
quota follows the bytes, and a message is located by folder. The four repositories
are thin adapters that only translate how each path names a message.

The contract test added before this change (which failed on 8 of its cases)
now passes, as does the full suite.
2026-10-16 13:15:32 -03:00
Lucas Rayan e63b68acb2 test(mail): contract that every path must keep counters, modseq and quota true
Runs each state change through IMAP and through the webmail and checks the cached
numbers against the rows. It fails today where the two stacks drifted: IMAP never
moved the unread counter, and the webmail never gave the quota back.
2026-10-16 13:12:24 -03:00
Lucas Rayan 9c8b9c00fc fix(smtp): keep a copy of every submitted message in the sender's Sent folder
A message sent over SMTP submission was delivered but left nothing behind: the
account's Sent folder stayed empty. Webmail files its own copy after sending,
and a mail client cannot do it either, since IMAP APPEND is not implemented, so
nothing ever filled Sent for SMTP clients.

- ProcessOutboundEmailInput.FileSentCopy asks Submit to file the signed message
  in the sender's Sent folder, as read (not unread), sharing the blob the
  delivery jobs already reference; one copy per submission, not per recipient
- the SMTP submission session sets it; the webmail leaves it off because it
  files its own copy without the Bcc line, and asking twice would duplicate it
- filed only after the message is durably queued, so a submission refused by the
  send limit leaves nothing behind; a failure to file is logged, never returned,
  because the mail is already on its way and the client would send it again

Tests: unit cases (asked/not asked, shared blob, failure swallowed, limit
refusal, no repository) and an end-to-end test on the real submission server
that fails with "Sent holds 0 messages" without the fix. Full go test ./...
(25 packages) with TEST_DATABASE_URL, go vet and lang-lint are clean.
2026-10-16 12:51:46 -03:00
Lucas Rayan 110a240cd9 fix(auth): app passwords now sign in SMTP, IMAP and POP3
The webmail creates app passwords (shown once, stored hashed, with scopes) but
the protocol servers only compared a login against mailboxes.password_hash, so
an app password was always refused with 535 / authentication failed. They exist
because mail clients cannot do a second factor.

- port.MailboxAuth carries the mailbox's app passwords (newest 20) with their
  scopes; the Postgres repository loads them and stamps last_used_at on use
- verifyCredential accepts the mailbox password or an app password that holds
  the scope of the protocol; SMTP, IMAP and POP3 use it. ManageSieve keeps the
  mailbox password only, as no default scope covers it
- a malformed app password hash is skipped instead of failing the login; a
  malformed mailbox hash still surfaces as the server-side error it was

Tests: unit cases for scopes and malformed hashes, the three entry points,
repository tests against Postgres, and an end-to-end test on the real
submission server that fails with 535 without the fix and passes with it.
Full `go test ./...` with TEST_DATABASE_URL, go vet and lang-lint are clean.
2026-10-16 09:21:08 -03:00
Lucas RayanandClaude Sonnet 5.5 8e7c0abd0a fix(lint): codigo so em ASCII (lang-lint R9) nos arquivos de destinatarios
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 10:32:38 -03:00
Lucas RayanandClaude Sonnet 5.5 931ddcd004 fix(deps): corrige CVEs HIGH/CRITICAL que bloqueavam o release
O scan Trivy do CI falhou no push anterior e impediu a publicacao das
imagens, entao a producao seguiu na versao antiga.

- webmail: next 15.5.21 -> 15.5.27 (RCE no otimizador de imagens e
  cache poisoning), sharp -> 0.35.5, source-map-js -> 1.2.2,
  dompurify -> 3.4.17
- protocols: golang.org/x/net 0.58 -> 0.60 (DoS HTTP/2) e toolchain
  Go 1.25 -> 1.26 (stdlib corrigida a partir de 1.26.9)

Verificado localmente: imagens e repositorio sem achados HIGH/CRITICAL,
testes e build verdes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 10:27:37 -03:00
Lucas RayanandClaude Sonnet 5.5 50a67531ba feat(webmail,auth): leitor estilo Outlook, responder a todos, importantes e isolamento do admin de dominio
Webmail
- Leitor de mensagem em componente proprio, com barra de comandos fixa,
  cabecalho compacto, faixa de imagens bloqueadas e chips de anexo.
- Divisor arrastavel entre lista e leitor (mouse, setas, duplo clique),
  largura persistida e limites que preservam os dois paineis.
- Destinatarios em chips (Para, Cc, Cco): aceita nomes com virgula,
  colagem de listas, validacao e bloqueio de envio com endereco invalido.
- Responder a todos, sem o proprio endereco e sem repetidos; In-Reply-To
  e References nas respostas; prefixo Re:/Fwd: sem repeticao.
- Marcar como importante (estrela, filtro, linha da lista) e enviar com
  alta importancia (Importance/X-Priority), com etiqueta no leitor.
- Sanitizador: a regexp de URI customizada descartava todo atributo que nao
  fosse link (width, colspan, bgcolor...), o que desmontava tabelas de
  e-mail; imagens de fundo agora sao bloqueadas de forma reversivel.

Protocols
- POST /api/v1/mail/flagged (\Flagged) com bump de modseq para IMAP.
- Renderizacao expoe message_id, in_reply_to e important.
- Cabecalhos de resposta validados contra injecao.

Auth
- As views do admin de dominio eram globais: dashboard, fila de saida,
  DMARC, preflight e diagnostico mostravam dados de todos os dominios.
  Agora todas respeitam o escopo da sessao; super admin segue vendo tudo.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 10:09:55 -03:00
Lucas RayanandClaude Opus 5 b5baf33a63 fix(bimi): as rotas existiam no protocols e o proxy nao as conhecia
O painel respondia "API endpoint not found" e o logotipo devolvia a pagina de
404 do Next. As rotas estavam registadas no servico protocols, mas o proxy do
webmail decide o upstream por uma lista propria, e eu nao acrescentei a "bimi"
-- exactamente o erro contra o qual o comentario dessa lista avisa.

Ficam ambas cobertas por testes: cada area administrativa que o protocols
possui, e o caminho well-known do logotipo. Esquecer isto nao volta a ser
silencioso.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 22:41:00 -03:00
Lucas RayanandClaude Opus 5 c59548e311 Revert "revert: foto de perfil e BIMI, para restaurar o servico"
Repoe as duas funcionalidades. A reversao foi uma precaucao enquanto o site
estava em baixo, e acabou por ser ela a provar que a culpa nao era delas: o
502 continuou depois de reverter.

A avaria era o servico web nao declarar porta nenhuma, o que levava o Coolify
a gerar um servico Traefik apontado ao porto 80. Fica corrigida no commit
anterior, com expose 3000.

As migracoes 0012 e 0013 nunca sairam do repositorio nem da base de dados, por
isso o codigo reposto encontra as tabelas que espera.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 22:29:12 -03:00
Lucas RayanandClaude Opus 5 e93fa19bdd fix(compose): o web nao declarava a porta, e o proxy adivinhava mal
O servico web nao tinha ports nem expose -- so a etiqueta do Traefik com
loadbalancer.server.port=3000. Essa etiqueta serve os routers escritos aqui,
mas o Coolify gera os seus proprios a partir dos dominios configurados, e para
esses precisa de descobrir a porta. Sem expose e sem porta fixada no dominio,
cai nos 80, onde nada escuta: ligacao recusada, 502 em todos os hostnames, com
o contentor perfeitamente saudavel e o Coolify a reportar running:healthy.

Aconteceu agora porque a migracao de servidor de 2026-09-02 recriou a
aplicacao e a afinacao anterior perdeu-se. O expose deixa a porta descoberta
sozinha, para nao depender de uma configuracao que vive fora do repositorio.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 16:02:11 -03:00
Lucas RayanandClaude Opus 5 e30d000e43 revert: foto de perfil e BIMI, para restaurar o servico
O site ficou a responder 502 em todos os hostnames depois do deploy destas
duas funcionalidades. A reversao vem primeiro; o diagnostico vem a seguir, com
o servico de pe.

As migracoes 0012 e 0013 ficam. Sao aditivas, nada no codigo revertido as usa,
e apaga-las deixaria a base de dados numa versao sem ficheiro correspondente,
o que parte o proprio migrate no arranque seguinte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 08:45:16 -03:00