Files
backspace/docs/roadmap-resenha.md
T
devsyncwrldandClaude Fable 5.1 ef9c73501c
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
feat(profile): a full identity system — name styles, decorations, effects, nameplates, tag, links, board
The owner asked for profile customisation that is "completo e FODA", pointing
at Discord's profile editor. This is the whole thing, end to end, with a live
preview.

What a user can now set, and where it shows:

  - Display name style: 10 fonts × 9 effects (solid, gradient, neon, toon,
    pop, gummy, prism, glitch, fire) × two colours. Popout and full profile.
  - Avatar decoration: 10 (ring, neon, flames, stars, halo, vines, pixel,
    hearts, frost, crown). Inline SVG — no image assets, scales to any size.
  - Profile effect over the banner: 9 (sparkles, rain, snow, matrix,
    confetti, aurora, embers, bubbles, hearts). CSS particles with seeded
    positions so re-renders do not change the weather.
  - Nameplate behind the member-list row: 10 presets + custom two-colour.
  - Theme: two colours washed behind the card, and the banner fallback.
  - Pronouns, and a clan-style tag (emoji + 2–4 letters) beside the name,
    also on the member row.
  - Links, up to 5, with the brand icon picked from the host.
  - Board: favourite game, up to 5 in rotation, up to 10 wanted, a quote.
    Games come from Steam search through a small server proxy (cached,
    10 min) or are typed by hand; covers only load from Steam's CDN.
  - Badges, derived rather than stored: instance admin, server owner,
    founder (joined in the space's first month), veteran (a year), OG (six
    months), stylist. Nothing to grant, revoke or migrate.

Storage is one JSON column, users.profile_style (migration 0019), and one
normaliser in shared/profile.ts that both the server (on write and on read)
and the client (on render) run. It never throws: unknown ids fall back,
strings are cut to their limits, colours must be #rrggbb, link URLs must be
https, cover URLs must be a Steam CDN host. Kept out of the federation
durable-field set on purpose — peers on older builds do not know the field,
and it is cosmetic.

The editor is a new Settings > Profile tab. Its preview is the same
ProfileCard component the popout renders, with the draft style swapped in —
what you see while editing is, by construction, what others see.

Fonts are OFL builds self-hosted from public/fonts alongside DM Sans, latin
subsets only, ~120 KB in total.

Verified: web build, 517 web tests (11 new: normaliser bounds and fallbacks,
link icon detection, badge derivation), server typecheck, 804 server tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 23:36:23 -03:00

14 KiB
Raw Blame History

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

Identidade do perfil (entregue 2026-09-02, pedido: "completo e FODA")

Uma coluna JSON (users.profile_style, migração 0019) normalizada no servidor por shared/profile.ts. Aba Perfil nas configurações com prévia ao vivo (ProfilePanel renderiza o mesmo ProfileCard que o popout).

Peça Onde aparece Detalhe
Estilo do nome — 10 fontes × 9 efeitos × 2 cores popout, perfil completo Fontes OFL em public/fonts; efeitos são CSS (.name-fx-*)
Decoração do avatar — 10 popout, perfil, editor SVG inline em DecoratedAvatar, sem imagens
Efeito do perfil — 9 banner do popout e do perfil Partículas CSS com posições semeadas (ProfileEffectLayer)
Nameplate — 10 + personalizado lista de membros .nameplate-*
Tema (2 cores) fundo do cartão e banner sem imagem
Pronomes, tag (emoji + 2–4 letras) ao lado do nome; tag também na lista de membros
Links (até 5) popout e aba Sobre Ícone detectado pelo host; só https
Quadro: jogo favorito, rotação (5), quero jogar (10), citação aba Quadro do perfil; tira "Coleção" no popout Busca na Steam via /api/games/search (proxy, cache 10 min); capas só de CDN da Steam
Emblemas derivados popout e perfil admin, dono, fundador (1º mês), veterano (1 ano), OG (6 meses), estiloso — nada é armazenado

Fora do escopo desta entrega, candidatos a seguir: perfil por servidor (apelido/avatar por servidor), emblemas concedidos pelo admin, molduras animadas por upload, status com expiração.

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.