CI / Build & test (Node 20) (push) Canceled after 0s
CI / Build & test (Node 24) (push) Canceled after 0s
CI / Build & test (push) Canceled after 0s
CodeQL / Analyze (javascript-typescript) (push) Canceled after 0s
Security / Secret scan (gitleaks) (push) Canceled after 0s
Security / Dependency scan (OSV-Scanner) (push) Canceled after 0s
Security / IaC/config scan (Trivy) (push) Canceled after 0s
Security / License compliance scan (Trivy) (push) Canceled after 0s
OpenSSF Scorecard / Scorecard analysis (push) Canceled after 0s
Rebrand. The product name is now Resenhacord everywhere a person reads it:
window title, tray, notifications, About panel, PWA manifest, page title,
recovery and instance-picker screens, and the four i18n strings that named
the app. Code identifiers (BackspaceElectronAPI, @backspace/* workspace
names, the federation protocol) are unchanged — they are not a brand, and
renaming them buys nothing but churn. AGPL notices and upstream attribution
stay as they were.
Two rename details that would each have hurt real users:
- electron-builder's productName changed but appId did not. NSIS keys the
installation on appId, so the updater replaces the Backspace install in
place instead of leaving a second app beside it.
- userData is keyed on app name, so the rename would have moved every
install to an empty profile — logged out, instance URL gone. main.ts now
walks a migration chain ("@backspace/desktop" → "Backspace" →
"Resenhacord"), each step a no-op once its source is gone, and one whose
target already holds data leaves it alone. Autostart lookups accept the
old registry entry name too.
Logo. Two speech bubbles in conversation, violet behind, rose in front with
three dots — the front one is talking. Sources are hand-written SVG in
assets/brand (square viewBox; the gap between bubbles is a mask, not paint,
so the alpha-only macOS template keeps the silhouette). PNG sources are
rendered from the icon SVG and the whole set — .icns, .ico, Linux PNGs, tray
variants, favicons, PWA, maskable — comes from the existing gen-icons
pipeline unchanged.
Pin notice. Pinning a message now posts "X pinned a message to this channel.
See all pinned messages." into the channel, the way Discord does, with two
links: the message itself (jumps to it) and the pins panel. Space messages
had no `type` column — only DM messages carried system events — so this adds
one (migration 0018, default 'user', verified against a copy of the
production database: 88 rows, all 'user'). The route inserts a type='system'
row alongside the pin and broadcasts it as message_created, so the client
renders it with the SystemMessage renderer it already has. Unpinning posts
nothing; it is housekeeping, not news. System notices are excluded from the
notification toast and the message sound — they are not from anyone.
The pins panel and jump target are local state in MainContent; a notice deep
in the timeline reaches them through two small uiStore requests (a counter
and an id), neither persisted.
Verified: web build, 506 web tests (2 new), server typecheck, 804 server
tests, desktop typecheck.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
193 lines
13 KiB
Markdown
193 lines
13 KiB
Markdown
# Roadmap — fork Resenha
|
|
|
|
Plano de features próprias desta instância. Arquivo exclusivo do fork
|
|
(nome com sufixo para não colidir com arquivos do upstream em merges).
|
|
|
|
Escrito em português por ser documento de planejamento do dono do fork; o
|
|
código e os commits seguem em inglês, como o resto do repositório.
|
|
|
|
## Entregue
|
|
|
|
| Feature | Commit | Nota |
|
|
|---|---|---|
|
|
| Ir para a call clicando no nome do canal | `c70b0095` | Exigiu o `voiceStore` passar a guardar o espaço da call — antes ele não sabia onde a call estava assim que o usuário navegava para outro servidor |
|
|
| Botão de GIF redesenhado | `20526e1b` | Contorno vazado com letras cheias, no lugar do bloco sólido |
|
|
| Explorador de GIF no banner | `20526e1b` | Sem upload: banner já aceita URL absoluta no cliente e no servidor |
|
|
| Teste de microfone com retorno | `bfe62d70` | `AudioManager.startMicTest/stopMicTest`; devolve o microfone ao parar, com duas travas independentes |
|
|
| Bloco de atividade no perfil | `d7da0ff2` | `ProfileActivity`; inclui correção de validação de assets no servidor |
|
|
| Favoritar GIFs + categorias (#6) | `fb662bfe` | Favoritos no servidor, por conta; guarda o resultado inteiro porque o provedor não busca por id |
|
|
| Registro de auditoria (#9) | `bbb190cb` | Tabela append-only genérica; 8 ganchos; sair ≠ ser expulso |
|
|
| Estatísticas do grupo | `18300517` | Tabela própria de sessões de voz; ganchos no ponto único de entrada/saída |
|
|
| Spotify por OAuth (atividade com capa e progresso) | `75316b08` | Token só no servidor; `state` assinado; atividades por fonte para não brigar com o detector do Electron |
|
|
| Menu do próprio nome | `f5451e1b` | Perfil, status e copiar ID. Sem Clips/trocar conta — não existem aqui |
|
|
| Cronômetro da call | `f5451e1b` | `startedAt` do servidor; zera sozinho porque sala vazia é destruída |
|
|
| Correções do Spotify (sincronia, sumiço, barra) | `c899253e` | Pausa virou estado; horário do servidor no `ready` corrige relógio |
|
|
| Soundboard no app desktop | `c899253e` | `window.prompt` não existe no Electron; campo inline no lugar |
|
|
| Áudio do sistema sem eco | `d525bbb8` `5b848432` | Módulo nativo com isolamento por processo + ganho e preset de música |
|
|
| Instaladores publicados pelo Gitea | `ce6bba05` | GitHub compila, Gitea distribui; atualização automática ligada |
|
|
| Fixar mensagens no canal | `4ceb5cd6` | Estado na própria mensagem; painel no cabeçalho; limite de 50 |
|
|
| Busca: filtros embutidos e tradução | `50a8f12c` | Os filtros já existiam; faltava `de:fulano` e descoberta |
|
|
| Emojis e figurinhas do servidor | `7d003021` | `:nome:` no markdown sem plugin; figurinha como mensagem inteira |
|
|
| Fundação de i18n (en + pt-BR) | `688a1335` | `src/i18n/`; pt-BR é parcial e cai para inglês. Aba Idioma nas configurações |
|
|
| Rebrand: **Resenhacord** + logo nova | (ver git log) | `productName` mudou, `appId` **não** — assim o NSIS troca a instalação antiga no lugar. `userData` migra `Backspace` → `Resenhacord` no primeiro boot (senão todo mundo cairia da sessão). Logo: duas bolhas de conversa, roxo → rosa; fonte em `assets/brand/*.svg`, PNGs e ícones gerados por `pnpm gen-icons` |
|
|
| Aviso "X fixou uma mensagem" | (ver git log) | Tabela `messages` ganhou `type` (migração 0018); a rota de pin posta uma mensagem de sistema. Dois links: pular pra mensagem e abrir o painel de fixadas |
|
|
| Menção `@everyone` | (ver git log) | Reusa o token `<@id>`; permissão `MENTION_EVERYONE` nova, concedida ao `@everyone` por padrão e retroativa via backfill no boot. Servidor neutraliza o token de quem não tem a permissão, no envio **e** na edição |
|
|
| Renomear canal (nome e tópico) | (ver git log) | Rota `PATCH /api/channels/:id` já existia; faltava interface. Normalização em `shared/constants` para servidor e web usarem a mesma regra |
|
|
| Volume da tela em 50% por padrão | (ver git log) | `DEFAULT_STREAM_VOLUME`; o publicador reforça o áudio do sistema, então o padrão anterior chegava alto demais |
|
|
| Sons 50% mais baixos | (ver git log) | Só `SFX_BASE_VOLUME` (0.8 → 0.4); os `.ogg` não foram regerados |
|
|
| Atualização do desktop verificada com mais frequência | (ver git log) | Era só na abertura e de 4 em 4 horas; agora a cada 30 min e ao focar a janela, com trava de 5 min |
|
|
| Preview de perfil nos participantes da call | (ver git log) | O popout já existia e era aberto de 11 lugares; **nenhum era de voz**. Ligado nas linhas da lista de voz e no nome dos tiles da grade |
|
|
|
|
## Já existia no código (verificado, não construir de novo)
|
|
|
|
- **Busca com filtros** — servidor (`q`, `from`, `has`, `before`, `after`),
|
|
client de API e painel no `SearchPopover` já existiam completos. Só faltava
|
|
tradução, sintaxe embutida (`de:fulano`) e descoberta.
|
|
|
|
- **Animação de digitação** — `TypingIndicator.tsx`, três pontos `animate-bounce`
|
|
escalonados em 0/150/300ms.
|
|
- **Sons de call/stream** — `SoundController.tsx`, montado no `AppLayout`:
|
|
stream started/ended, alguém entra/sai da tela, entra/sai da call, câmera,
|
|
mute, ringing. Os `.ogg` estão em `web/public/sounds/`.
|
|
- **Preview de perfil ancorado** — `uiStore.openUserProfile(user, anchor, placement)`
|
|
guarda `userProfilePopout`; popout posicionado no desktop, tela cheia no
|
|
mobile. Já era aberto por mensagens, menções, avatares, lista de membros,
|
|
DMs e painel de atividade. O que faltava era só a voz — agora ligado.
|
|
Continua faltando o bloco de atividade do print do Discord, que é a #8.
|
|
|
|
Se qualquer um dos dois não se manifestar em uso, o trabalho é **depuração**,
|
|
não implementação.
|
|
|
|
## Pendente — pedido original
|
|
|
|
Ordem sugerida: as pequenas primeiro, as grandes uma de cada vez.
|
|
|
|
| # | Feature | Tamanho | Observação técnica |
|
|
|---|---|---|---|
|
|
|
|
## Próximo foco (pedido em 2026-09-02): personalização do usuário e do perfil
|
|
|
|
A definir com o dono. Já existe: avatar, banner (imagem ou GIF), cor do avatar
|
|
e do banner, sobre mim, status personalizado, atividade (Spotify/jogos).
|
|
|
|
## Pendente — ideias aprovadas
|
|
|
|
| Feature | Tamanho | Observação técnica |
|
|
|---|---|---|
|
|
| Watch party | Grande | O screen share do LiveKit já existe; falta sincronizar posição de reprodução entre participantes |
|
|
|
|
## Regra de idioma (a partir de 2026-08-31)
|
|
|
|
Funcionalidade nova sai com interface em **pt-BR**, e a cada update um sistema
|
|
existente é traduzido. Os dois idiomas **coexistem**. Código, comentários e
|
|
commits seguem em inglês.
|
|
|
|
A fundação está pronta (`src/i18n/`). Para traduzir um sistema: adicione as
|
|
chaves em `locales/en.ts`, traduza em `locales/pt-BR.ts` e troque as strings
|
|
fixas por `t('chave')`. O que faltar cai para o inglês sozinho.
|
|
|
|
### Sistemas já traduzidos
|
|
|
|
- Configurações → navegação e aba Idioma
|
|
- Configurações → Voz (dispositivo de entrada, volume, teste de microfone)
|
|
- Cartão de perfil (sobre mim, membro desde, enviar mensagem, atividade)
|
|
- Configurações → Privacidade
|
|
- Configurações → Conexões (nasceu bilíngue)
|
|
- Seletor de GIF
|
|
- Chat: composer e mensagens (placeholder, anexos, responder, reações)
|
|
- Barra lateral: servidores, canais e menus de contexto
|
|
- Lista de membros (grupos por cargo, carregamento)
|
|
- Busca (rótulos, filtros e sintaxe embutida)
|
|
- Registro de auditoria e Estatísticas (nasceram bilíngues)
|
|
- Configurações do canal (visão geral, privacidade, exclusão e rótulos de permissão)
|
|
- Amigos: abas, listas, pedidos, aba de adicionar e cartões de descoberta
|
|
- Modal de convite (incluindo os motivos de falha por convite)
|
|
- Lista de membros da DM em grupo (remover e transferir propriedade)
|
|
- Configurações → Área de trabalho (início automático, atualizações, instância)
|
|
- Configurações → Voz: dispositivo de saída (completa a aba, junto com a entrada)
|
|
- Configurações → Atalhos (incluindo os nomes das ações e o aviso de conflito)
|
|
- Configurações → Conta (perfil, senha, conta desligada da origem, zona de perigo)
|
|
- Explorar servidores (cartões, entrar, pedir para entrar)
|
|
- Configurações → Voz: vídeo (prévia, permissões, escolha de câmera) — fecha a aba
|
|
- Criar canal, categoria e servidor
|
|
- DMs em grupo (nova DM, adicionar amigos, configurações do grupo, sair)
|
|
- Entrar num servidor (descoberta, código de convite, conectar e login federado)
|
|
- Excluir conta, transferir propriedade e a tela de erro geral
|
|
- Configurações do servidor → Visão geral (identidade, ícone, banner, zona de perigo)
|
|
- Configurações do servidor → Membros e banimentos
|
|
- Configurações do servidor → Cargos (incluindo a tabela de permissões)
|
|
- Configurações da categoria (renomear, privacidade, exceções, excluir)
|
|
- Configurações da instância → Geral (nome, descoberta, busca de GIFs)
|
|
- Mensagens de sistema do chat e a prévia delas na barra lateral
|
|
- Login, registro e a página de convite
|
|
- Voz: controles, informações de conexão, folha de entrada no celular, aba Voz
|
|
- Telas do celular (`Mobile*.tsx`)
|
|
- Navegação das configurações (servidor, usuário e instância) + Descoberta e
|
|
pedidos de entrada
|
|
|
|
Os rótulos de permissão viraram um conjunto único (`perm.*`), usado pelo painel
|
|
de cargos e pelos editores de exceção de canal e de categoria — antes havia
|
|
duas cópias da mesma lista.
|
|
|
|
### Fila sugerida de tradução
|
|
|
|
Configurações → Instância: registro, federação, transmissão, armazenamento e
|
|
usuários (os cinco painéis grandes, só o dono vê) · `ConnectedInstances` ·
|
|
`UserProfileModal` · `MainContent` e `ChannelSidebar` · mensagens de erro
|
|
vindas de stores e hooks (`instanceStore`, `useLiveKit`, `transferStore`)
|
|
|
|
## Correções pendentes
|
|
|
|
| Problema | Causa provável | Correção |
|
|
|---|---|---|
|
|
|
|
|
|
## App desktop — já existia (verificado 2026-08-31)
|
|
|
|
As três pedidas já estão implementadas e ligadas de ponta a ponta. **Não
|
|
construir de novo.**
|
|
|
|
- **Bandeja** — `createTray()` em `desktop/src/main.ts`, chamada na inicialização;
|
|
fechar a janela esconde em vez de sair (`mainWindow.on('close')`).
|
|
- **Notificações nativas** — `showNotification()` no processo principal, canal
|
|
IPC `show-notification`, e o web já chama por `platform/notifications.ts`.
|
|
- **Áudio do sistema no compartilhamento** — `setDisplayMediaRequestHandler`
|
|
devolve `audio: 'loopback'`; existe caixa de seleção no `ScreenSharePicker`
|
|
ligada a `screenShareConfig.shareAudio`, que atravessa o IPC.
|
|
|
|
Se algum não se manifestar em uso, o trabalho é **depuração**, não construção.
|
|
|
|
|
|
## Aprovadas, a fazer depois (2026-08-31)
|
|
|
|
Escolhidas pelo dono, inspiradas no Discord. **Nenhuma iniciada.**
|
|
|
|
| Feature | Tamanho | Observação técnica |
|
|
|---|---|---|
|
|
| **Resposta rápida de voz (soundboard por atalho)** | Pequena | O soundboard já está pronto; falta só marcar favoritos e ligar a atalhos de teclado, sem abrir painel. Cuidado: o limite de repetição do servidor continua valendo e é o que impede virar metralhadora |
|
|
| **Cargos com ícone e exibição separada** | Média | Cargos e cores já existem; falta ícone, o campo "exibir separadamente" e o agrupamento na lista de membros |
|
|
|
|
|
|
## Ideias novas — a avaliar
|
|
|
|
Ordenadas por relação valor/custo para um servidor de grupo fechado.
|
|
|
|
| Sistema | Tamanho | Por que faz sentido aqui |
|
|
|---|---|---|
|
|
| **Backup fora da VPS** | Pequena | Hoje app, banco, uploads, backups e as três cópias do repositório morrem no mesmo evento. Um envio periódico para fora resolve |
|
|
| **Aniversários e lembretes** | Pequena | Alto retorno afetivo, custo baixo: campo de data + verificação diária + mensagem no canal |
|
|
| **Perfis por servidor** | Média | Apelido e avatar diferentes por espaço, como no Discord. O modelo já tem membro por espaço |
|
|
| **Eventos agendados com presença** | Média | "Sexta 21h" com confirmação. Encaixa nas notificações e no PWA já instalado |
|
|
| **Notificações push de verdade** | Média | O `vite-plugin-pwa` e o service worker já estão lá; falta Web Push (VAPID) e o registro no servidor |
|
|
| **Níveis e conquistas** | Média | Gamificação por tempo em call e mensagens. **Mesmo registro de eventos da auditoria e das estatísticas** — três features, um mecanismo |
|
|
| **Clipes de call** | Grande | "Salvar os últimos 30 segundos" depois de alguém falar besteira. O LiveKit tem egress; exige buffer contínuo e armazenamento |
|
|
| **Fila de música compartilhada** | Grande | Um participante-robô publicando faixa de áudio na sala LiveKit. É o que mais muda o uso de um servidor de amigos, e o mais caro |
|
|
| **Autenticação em duas etapas** | Média | Só faz sentido depois de decidir o modelo de cadastro |
|
|
|
|
## Dependência que vale respeitar
|
|
|
|
**Auditoria (#9) e Estatísticas compartilham o mesmo mecanismo**: uma tabela de
|
|
eventos append-only no servidor. Construir a auditoria primeiro e as
|
|
estatísticas como leitura agregada dessa mesma tabela evita escrever dois
|
|
sistemas de registro paralelos que divergem com o tempo.
|