filipedeschamps / tabnews.com.br

Conteúdos para quem trabalha com Programação e Tecnologia.
https://tabnews.com.br
GNU General Public License v3.0
5.16k stars 383 forks source link

Publicações Promovidas #1491

Open aprendendofelipe opened 1 year ago

aprendendofelipe commented 1 year ago

Vou apenas rascunhar como imagino que poderiam ser as publicações promovidas, mas o resultado final provavelmente será diferente da ideia inicial (pode até ser completamente diferente).

As publicações promovidas terão semelhanças e diferenças com as demais publicações.

As semelhanças são:

As particularidades são:

Ao ter o custo em TabCash para uma publicação promovida relacionado às qualificações, uma publicação mal avaliada, que acabar saindo dos relevantes, praticamente não terá custos adicionais, enquanto outra que for bem avaliada e, consequentemente, mais visualizada, acabará resultando em um custo maior (até o limite estabelecido pelo autor).

Detalhando melhor a ideia:

  1. Ao criar uma publicação promovida, deve ser escolhida a quantidade de TabCoins promovidos e mais dois parâmetros opcionais: limite de consumo de TabCash e limite de tempo publicada.
  2. A quantidade inicial de TabCoins promovidos irá definir apenas o destaque inicial da publicação entre as demais publicações, o que irá variar normalmente conforme as qualificações recebidas e a idade da publicação.
  3. A quantidade de TabCoins promovidos terá um custo de X TabCash por cada TabCoin, onde X pode variar conforme a cotação do momento.
  4. O limite de TabCash extra define o máximo que será consumido conforme forem ocorrendo as interações, onde a cada interação será consumido mais Y TabCash. Se for deixado sem limite, a publicação ficará no ar até ser consumido todo o TabCash do autor.
  5. Para as cotações (valores de X e Y), podemos começar de forma parecida com o que fizemos com os ganhos de TabCoins ao publicar, ou seja, podemos começar com uma cotação fixa e ir ajustando manualmente conforme a necessidade. Mais para frente, quando entendermos melhor a mecânica, podemos automatizar a cotação de forma a manter uma quantidade saudável de anúncios. No início, com o grande acúmulo de TabCash atual, acho que precisamos começar com cotações bem acima de 1, pois senão pode ocasionar um excesso de anúncios nos destaques.
  6. Publicações promovidas não dão e nem retiram nenhum TabCoin do autor. Elas apenas consomem TabCash. Assim evitamos que se promova publicações pensando apenas em gerar mais TabCoins do que o investido para promover. Até por serem temporárias, nem faria sentido gerar TabCoins com elas. Mas elas podem ser uma propaganda do perfil do usuário ou de algumas de suas publicações, o que também pode trazer mais TabCoins do que o investido, mas dessa forma acredito ser aceitável.
  7. Qualquer qualificação que a publicação receber muda o saldo da publicação, consome mais Y TabCash do autor, mas não dá e nem retira TabCoins dos usuários (seja o autor ou o qualificador), fazendo assim o custo (TabCash) para o autor ter alguma relação com o alcance da publicação. O custo não será diretamente proporcional ao alcance (pois as qualificações não são), mas dessa forma existe o benefício de ficar isento de visualizações de robôs e de manipulações.
  8. Como não haverá custo para os qualificadores, as publicidades não diminuirão o saldo disponível para qualificações das demais publicações.
  9. Mesmo sem consumo de TabCoins, apenas usuários com 2 ou mais TabCoins poderão qualificar as publicações promovidas, limitado a uma qualificação por usuário/publicação. Isso deve dificultar a manipulação indevida dos custos e do ranqueamento de conteúdos promovidos.
  10. Precisamos dificultar o bloqueio das publicações promovidas, seja por extensões para navegador, seja por sistemas que usam conteúdos da API do TabNews. Por isso que acredito que não deve haver nenhuma forma de identificar que é um conteúdo promovido, a não ser após efetuar a qualificação sem consumo de TabCoins.
  11. O fato de não identificar que é uma publicação promovida também pode ajudar com uma qualificação mais isenta.
  12. A publicação promovida será despublicada quando ocorrer o primeiro entre os seguintes eventos: o autor despublicar manualmente, o limite de tempo for alcançado, o limite de TabCash for atingido ou o saldo de qualificações ficar negativo.
  13. Acho que seria saudável limitar a uma publicação promovida por autor, mas permitindo editar a publicação existente ou despublicar e criar uma nova.
rodrigoKulb commented 1 year ago

Ótimo quando você fala no formato

  • Formato: O formato da publicação promovida nas interfaces, seja web ou API, será o mesmo das demais publicações.

Acho que seria importante informar que são "Patrocinadas" não? Talvez reservar os 3 primeiros lugares para elas. O time de cache diferente, pois assim que finalizar o consumo de TabCash não devem ser mais exibidas. Sugestão Captura de tela em 2023-08-02 21-06-00

aprendendofelipe commented 1 year ago

Acho que seria importante informar que são "Patrocinadas" não?

É um outro caminho, mas precisa desenvolver o restante da ideia e pensar na mecânica de funcionamento, pois quase nada da minha sugestão inicial funcionaria se for mostrar que a publicação é promovida sem o usuário precisar qualificar para descobrir isso.

Alguns pontos para pensar:

  1. Versão Web: Deixar um espaço fixo no layout para propaganda deve funcionar para o #1492 , mas não para publicações promovidas, já que os usuários se acostumariam a ignorar aquele pedaço, e talvez a maioria nunca clicaria nessas publicações. Não funciona da mesma maneira que um feed de imagens, onde o usuário normalmente já vê o conteúdo sem precisar clicar em nada.
  2. API: Se a API do TabNews é gratuita, não podemos facilitar que sejam filtradas as publicações promovidas, pois elas não chegariam, por exemplo, nos Apps, Feeds RSS e sites que usam a API.
  3. Como as promovidas estão sujeitas às qualificações, acho que podemos deixá-las aparecerem como as demais publicações.
  4. Tem que ser mais vantajoso criar uma publicação promovida do que uma publicação normal, senão elas não fazem sentido.
  5. Usei as qualificações para fazer os custos das promovidas se basear em algo difícil de manipular. Se for destacá-las como publicidade, precisa criar outro mecanismo.
  6. Eu concordo que seria melhor se fosse possível deixar claro que são promovidas sem o usuário precisar votar para descobrir isso, mas não encontrei maneira de funcionar, então é melhor focar nos banner se não gostarem da ideia das promovidas. Mas é claro que ótimas ideias podem surgir resolvendo todos os problemas. 💪
rodrigoKulb commented 1 year ago

Ótimos pontos, gosto do caminho que você está querendo seguir. Mas ainda acho importante ter a informação que aquela publicação foi "patrocinada". Mas vejo um problema quando informamos isso nas APIs correndo risco de corte dessas informações.

  • Tem que ser mais vantajoso criar uma publicação promovida do que uma publicação normal, senão elas não fazem sentido.

Se deixar sempre as 3 primeiras patrocinadas resolveria essa questão.

Poderia manter a regra de qualificação para ordenar entre as top 3 e utilização do saldo como custo.

Mas realmente é algo que precisamos pensar, porque envolve um caminho completamente diferente para o desenvolvimento.

OBS: Estou afastado do projeto um bom tempo, então ainda estou me atualizando com as informações! 😅️

rodrigoKulb commented 1 year ago

@aprendendofelipe, saindo totalmente fora do planejado, somente jogando uma ideia: e se a natureza da publicação não alterasse nada, e pudéssemos utilizar os TabCash para "turbinar" a publicação por um tempo ou por visualizações? Desta forma, a publicação em si não mudaria nada. Apenas seria uma forma de "patrocinar" uma publicação normal. Assim que finalizasse o período, ela voltaria a ser uma simples publicação.

aprendendofelipe commented 1 year ago

Vou tentar simplificar e expor o que eu considerei, pois assim fica mais fácil de encaixar cada ideia em alguns dos resultados que podemos obter.

Dependendo das regras que criarmos, vamos chegar em uma destas 3 situações, onde apenas a segunda é desejável:

  1. Não vale a pena usar TabCash, pois não aumenta as visualizações e nem os ganhos de TabCash;
  2. Vale a pena usar TabCash apenas para aumentar o alcance (uma troca de TabCash por visualizações);
  3. Sempre vale a pena usar TabCash, pois dá mais visualizações e devolve o TabCash investido, ou porque devolve ainda mais TabCash (Farm);

Na prática, dependendo da ideia, ela vai transitar entre as opções acima dependendo de diversos fatores, como dia e horário, quantidade de TabCash investido, tipo de conteúdo etc. Mas mesmo sem chegar nesse nível de detalhamento, já é possível descartar algumas ideias que tem mais tendência de resultar nos indesejados casos extremos.

Para analisar em qual dos casos acima nós chegamos com cada configuração, podemos olhar para estes resultados:

  1. Promovendo com TabCash, a publicação tem mais visualizações do que sem usar TabCash?
  2. O autor ganha mais TabCash do que o TabCash investido para promover?

Vaja na tabela a seguir que só existe um caso desejado. Então cada sugestão precisa resultar nesse caso, em que só vale a pena usar TabCash se for para dar mais visualização a algo.

Onde cada ideia se encaixa?

Visualizações TabCash Vale a pena promover algo usando TabCash?
Diminui Diminui Nunca
Diminui Não muda Nunca
Diminui Aumenta Só serviria para farmar
Não muda Diminui Nunca
Não muda Não muda Nunca
Não muda Aumenta Sempre
Aumenta Diminui Só para melhorar o Alcance (única saudável)
Aumenta Não muda Sempre
Aumenta Aumenta Sempre

Por que descartar as outras linhas da tabela?

Os casos em que nunca vai valer a pena usar TabCash não fazem sentido, pois eliminam a razão de TabCash existir.

Já para os caso em que sempre vai valer a pena usar TabCash para promover qualquer publicação, o problema será justamente esse. Pra quem tem TabCash, não vai fazer sentido publicar algo e não promover, mas a publicação promovida não vai ter muita vantagem com relação às demais promovidas, que também serão em grande quantidade.

O único diferencial real seria negativo, ou seja, a segregação de quem não tem TabCash, como os novos usuários, que dificilmente conseguiriam ganhar seus primeiros TabCash, já que estaríamos em um caso em que as promovidas tem muito mais vantagens sobre as não promovidas.

Esse caso de valer muito a pena usar TabCash nos levaria para o paradoxo de Braess, onde cada indivíduo vai levar mais vantagem se agir de uma certa forma que não é a melhor quando se pensa no coletivo. Para quem não conhece o paradoxo, ontem à noite o Daniel Nunes postou um vídeo muito legal:

PARADOXO DE BRAESS: Construir Estradas PIORA o Trânsito?

rodrigoKulb commented 1 year ago

@aprendendofelipe concordo plenamente, desta forma para resolver é simples.

Uma postagem quando patrocinada com TabCash para ganhar mais visualização, o usuário não poderia receber novas TabCoins com upvote, assim que o período de patrocínio encerrar. Voltaria normalmente.

Desta forma uma postagem sempre será uma postagem, apenas entrar em uma fase de patrocinada ou não.

Temos algum problema nessa lógica?

Gabriel-Tapes commented 1 year ago

O ponto que acredito que necessite de mais atenção é esse:

Consomem TabCash do autor a cada diferente usuário que qualificar (seja voto positivo ou negativo) ou comentar

Perder TabCash para cada comentário pode desincentivar conteúdos que gerem engajamento, pois só iria gastar mais tabcash, já que comentar é de graça e ainda pode gerar tabcoins para quem comenta.

Talvez algo importante de ser lembrado é que, mesmo que seja revenue share e a publicação seja impulsionada, ainda deve seguir as regras de conduta do site, portanto o conteúdo de valor deve ser mais valorizado nesse caso. Um caminho que poderia ser seguido é que as qualificações positivas recebidas pelo post no período de impulso valham o dobro, mas de forma que o autor não as receba. Perceba que por si só, nos moldes atuais, receber mais votos positivos também é impulsionar a publicação. Aliando isso ao fato de que para votar não seria necessário gastar tabcoins, talvez fosse importante limitar esses votos para que apenas quem tem tabcoins suficientes possam votar e um limite de 1 voto por IP (como era feito antes) para evitar manipulações indevidas.

Existem três casos para a qual uma publicação provavelmente será impulsionada:

  1. Para possívelmente tirar do "limbo" uma publicação que o autor se esforçou muito ou que quer mais engajamento e destaque
  2. Para testar a funcionalidade
  3. Para divulgação

Obviamente mais casos surgirão com o tempo, mas inicialmente acredito que sempre se encaixarão nesses três casos. Em qualquer dessas situações teremos posts possivelmente irrelevantes, que não serão tão impulsionados naturalmente (seria importante que as qualificações negativas também tivessem o efeito das positivas?), mas aqueles que tiverem valor concreto seriam muito mais beneficiados, o que cumpre o objetivo do site.

Outro ponto a se atentar também é se será possível impulsionar mais vezes uma determinada publicação ou se terão formas de aumentar esse tempo de impulso.

Rafatcb commented 6 months ago

Acho interessante a possibilidade de "impulsionar" uma publicação (seja uma publicação do tipo conteúdo + divulgação, seja apenas conteúdo), mas essa dinâmica difere um pouco do anúncio básico (não é temporário, já tem TabCoins e comentários, já tem "tempo de vida" etc.), então acredito que podemos deixar para depois, focando no que é realmente o mais simples e funcional possível agora.

De toda forma, é importante ter em mente que essa é uma possibilidade futura, então projetamos o sistema de forma que seja possível acomodar essa funcionalidade.

Eu não deixaria o "custo de votar" nulo em publicações promovidas. Isso pode facilitar desnecessariamente os usuários votarem negativamente em todo anúncio, e hoje temos algumas facilidades que permitem o usuário poder votar mais (como o login diário).

Apesar disso, concordo com o autor não ganhar TabCoins de votos recebidos em uma publicação promovida.

Eu concordo que um espaço fixo não é legal para isso, as publicações podem estar "misturadas" com as outras relevantes, numa ordem que faça sentido.

Como dito nesse vídeo, acho importante ficar claro que aquilo é um anúncio, e que o anúncio está contribuindo com o usuário X. Esse uso de palavras pode mudar a percepção do leitor, principalmente para não chegarmos num ponto onde os usuários negativem qualquer anúncio simplesmente por ser um anúncio.

Outro ponto que citei em https://github.com/filipedeschamps/tabnews.com.br/issues/1490#issuecomment-1967740034, as "publicações promovidas" podem ser mais comerciais, e se não estiverem marcadas devidamente, os usuários podem achar que a publicação deveria ser removida. Imagino que uma publicação promovida extremamente comercial não será bem recebida, mas pode ser um pouco melhor recebida se devidamente identificada, já que a forma de avaliar pode mudar: "é uma propaganda, mas gostei da ferramenta/projeto/...".

Claro, podemos ter o problema de quem usa a API passar a ignorar isso, ou bloquearem usando uma extensão do navegador, mas acho que vale correr o risco inicialmente. Em alguns cenários de cálculo do "custo do anúncio" (para o anunciante), essa situação não implicará em um maior custo por um retorno menor. Por exemplo, se o custo for por interações (comentários/votos), ou for por visualização na página da publicação (e não no /relevantes, por exemplo). Isso muda se o cálculo for por tempo que o anúncio está no ar (o que não me parece legal) ou por visualizações no /relevantes.

Minha sugestão aqui seria "pagarmos para ver" no início.

Bom, vi alguns comentários sobre "pagar" para criar, para definir uma quantidade de TabCoins iniciais, para receber votos, comentários, e para definir o tempo que ficará como promovida.

Para simplificar, eu gostaria de sugerir tirar o tempo da equação. Podemos começar de forma que toda publicação promovida fique promovida por 24 horas. Escolher o tempo traz um pouco de complexidade, e o usuário poderia ser esperto e deixar promovida apenas nos horários que há mais público, e de madrugada não teria nenhuma publicação promovida, por exemplo.

E talvez, a princípio, experimentaria não "cobrar" por receber comentários.

Edit 16/03/2024: Sugiro também que o custo de TabCoins iniciais não aumente linearmente, mas sim que, quanto mais TabCoins, mais caro. Ou seja, supondo que o primeiro TabCoin custe 1 TabCash, se eu quiser criar uma publicação com 10 TabCoins, não vou gastar 10 TabCash, mas sim 30, por exemplo (números aleatórios).

Algumas sugestões adicionais

Agora, uma questão para elaborar mais: foi proposto que a publicação seja despublicada ao alcançar o tempo limite ou quantidade máxima de TabCash gasto pré-estabelecido. Acho o segundo caso um pouco estranho, porque digamos que foi uma propaganda que o pessoal realmente gostou, e recebeu vários votos de forma relativamente rápida: ela desapareceria em pouco tempo.

Se definirmos que a publicação ficará promovida por um tempo determinado, podemos informar isso na UI.

Fora essa última questão, e apesar de alguns poucos pontos que sugeri serem diferentes da ideia inicial, acho que dá para o sistema funcionar bem. A maior dificuldade provavelmente será encontrar o ponto de equilíbrio de TabCash.

Rafatcb commented 6 months ago

Este comentário contém apenas sugestões de como uma publicação promovida pode ser destacada na UI. Trouxe várias alternativas e tentei mostrar como meu raciocínio foi evoluindo para chegar na opção que eu mais gostei.

A publicação promovida

Seguindo com a ideia que mencionei em "Sobre identificar as publicações promovidas.", no meu comentário anterior, fiz alguns testes para elaborar melhor como isso pode ficar na prática. As imagens Mobile abaixo foram simuladas numa largura de 320px.

Vale o disclaimer que as imagens que eu coloquei para exemplificar abaixo tem como nome do autor filipedeschamps, mas é uma publicação que criei em localhost copiando partes de textos de outros lugares, apenas para dar noção de algo real.

1. Label "Anúncio", ao lado do nome do usuário.

Desktop Mobile
Label ao nome do autor, amarelo, escrito "Anúncio", com o tooltip "Este anúncio está contribuindo para o usuário nome do usuário" O memso cenário que o anterior, porém numa tela menor. O texto da tooltip fica cortado.

Inicialmente pensei em destacar usando um Label com variant="attention" dentro da publicação:

No caso do exemplo Mobile, o texto da Tooltip fica cortado, mas isso poderia ser resolvido mudando para "Este anúncio está contribuindo para o autor", por exemplo. Mais para frente mostro outros exemplos com essa alternativa.

Acho que será necessário diferenciar textos para um "Anúncio" e uma "Publicação promovida", que podem funcionar exatamente da mesma forma, mas o primeiro sendo algo comercial e o segundo sendo um conteúdo. Digo isso pensando no que já mencionei anteriormente, sobre publicações (anúncios) exclusivamente comerciais. Ou, então, podemos usar o adjeitvo "patrocinado", que é mais neutro nesse cenário.

Pensando sobre o propósito do LabelGroup que existe hoje, ao lado do nome do usuário, os usos seriam coisas como: Novo usuário, Autor, Robô, Moderador etc. Tudo isso é sobre o autor. Então, podemos pensar em mostrar que a publicação é um anúncio de outra forma, para termos uma UI mais consistente.

2. Texto negrito "Publicação patrocinada", acima da linha do nome do usuário.

Desktop Mobile
Texto "Publicação patrocinada" numa linha acima do nome do usuário. O texto é amarelo, em negrito. No hover, mostra uma tooltip com o texto "Esta publicação está contribuindo para o autor" O mesmo cenário que o anterior, porém numa tela menor

Nesse caso, usei a mesma cor do <Label variant="attention">, que é color: 'attention.fg'. Continuei deixando o Tooltip, mas com o texto menor. E, como o texto principal está englobando tanto "anúncios" quanto "publicações promovidas", neutralizei o texto para "Esta publicação está contribuindo para o autor". Talvez tenha ficado muito genérico, e "Este patrocínio está contribuindo para o autor" fique melhor.

3. Texto negrito "Publicação patrocinada com TabCash", acima da linha do nome do usuário.

Desktop Mobile
Texto "Publicação patrocinada com TabCash" numa linha acima do nome do usuário. O texto é amarelo, em negrito. No hover, mostra uma tooltip com o texto "Este patrocínio está contribuindo para o autor" O mesmo cenário que o anterior, porém numa tela menor

O texto "Publicação patrocinada" é bem curto, então temos espaço para escrever "Publicação patrocinada com TabCash". Isso deixa claro o que queremos passar com os "anúncios": o TabCash tem um uso, e um desses usos é criar uma publicação patrocinada/promovida; o autor só conseguiu patrocinar a publicação porque já criou conteúdo, ganhou TabCoins e qualificou conteúdos; a plataforma não "vendeu" o espaço por dinheiro.

Também mudei o Tooltip para vocês verem como fica na prática a alternativa que sugeri anteriormente.

4. Texto negrito "Publicação patrocinada com TabCash", acima da linha do nome do usuário, com ícone.

Ícone Desktop Mobile
Megafone Texto "Publicação patrocinada com TabCash" numa linha acima do nome do usuário. O texto é amarelo, em negrito, e com um ícone de megafone antes dele. No hover, mostra uma tooltip com o texto "Este patrocínio está contribuindo para o autor" O mesmo cenário que o anterior, porém numa tela menor
Ad Texto "Publicação patrocinada com TabCash" numa linha acima do nome do usuário. O texto é amarelo, em negrito, e com um ícone escrito "Ad" antes dele. No hover, mostra uma tooltip com o texto "Este patrocínio está contribuindo para o autor" O mesmo cenário que o anterior, porém numa tela menor

O ícone pode dar um destaque extra. Eu estava em dúvida se seria uma adição positiva, porque a opção 3 já me parecia um destaque interessante no topo da publicação, mas decidi testar. Usei size={14}.

Vendo assim, reforço minha opinião de que não precisamos adicionar um ícone.

5. Texto negrito "Publicação patrocinada com TabCash", acima da linha do nome do usuário, mantendo o alinhamento dos TabCoins com o título.

Desktop Mobile
Texto "Publicação patrocinada com TabCash" numa linha acima do nome do usuário e dos TabCoins da publicação. O texto é amarelo, em negrito. No hover, mostra uma tooltip com o texto "Este patrocínio está contribuindo para o autor" O mesmo cenário que o anterior, porém numa tela menor

Quando montei os outros exemplos, não tinha percebido que eu deixei de "alinhar os TabCoins com o título", então criei esse para terem noção de como ficaria "do jeito certo".

Se quiser ver uma captura de tela completa para ter noção de como esse texto fica junto do conteúdo, clique aqui. Coloquei o modo escuro também. Desktop: ![Publicação inteira no Desktop, conforme o exemplo 5](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/9ad6091b-5e10-4451-8245-f10780d127f3) ![Publicação inteira no Desktop, conforme o exemplo 5, no modo escuro](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/5f540bf0-2f4b-407d-ae29-a7e9160b8c5d) Mobile: ![Publicação inteira no Mobile, conforme o exemplo 5](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/ff5cb228-8e0a-4d0d-a607-56a250a5bdcc) ![Publicação inteira no Mobile, conforme o exemplo 5, no modo escuro](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/06ba447a-db72-4adb-b3f9-6f363bdf79e4)

A lista de conteúdos

O exemplo do @rodrigoKulb me inspirou para as experimentações que fiz no tópico anterior, então decidi adaptar a ideia do tópico anterior para a lista de conteúdos, não deixando as publicações promovidas fixas num local.

1. Texto negrito "Publicação patrocinada com TabCash", acima do título do conteúdo.

Desktop Mobile
Texto "Publicação patrocinada com TabCash" numa linha acima do título do conteúdo. O texto é amarelo, em negrito. O mesmo cenário que o anterior, porém numa tela menor

Mesmo padrão que mostrei no conteúdo. Também podemos ter a Tooltip aqui.

2. Texto negrito "Publicação patrocinada com TabCash", numa linha acima do título do conteúdo e do número da posição.

Desktop Mobile
Texto "Publicação patrocinada com TabCash" numa linha acima do título do conteúdo e do número da lista. O texto é amarelo, em negrito. O mesmo cenário que o anterior, porém numa tela menor

Aqui só mudei o alinhamento do número da lista. Aproveitei para tirar o print numa janela anônima, sem ter visitado o link, para vocês verem a diferença.

Acho melhor manter o número alinhado com o título para a leitura continuar fácil, "batendo o olho" o leitor consegue entender. Fiquei em dúvida se esse espaçamento entre os itens é pequeno demais a ponto de confundir a pessoa sobre qual é a publicação patrocinada.

Se quiser ver uma captura de tela completa para ter noção de como isso fica na lista de conteúdos, clique aqui. Coloquei imagens do modo escuro também Desktop: ![Captura da tela inteira no Desktop, conforme o exemplo 2](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/be689ad9-7fba-4ed7-892d-914056bffaf2) ![Captura da tela inteira no Desktop, conforme o exemplo 2, no modo escuro](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/b5b9198a-425b-46ef-9d5c-f200aca1c7e1) Mobile: ![Captura da tela inteira no Mobile, conforme o exemplo 2](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/3d0886d0-9707-49d0-9f6f-a82d5809294e) ![Captura da tela inteira no Mobile, conforme o exemplo 2, no modo escuro](https://github.com/filipedeschamps/tabnews.com.br/assets/26308880/5a1ec6bf-9dac-4eb2-8277-474574c7341e)

3. Com o texto e destacando o "fundo" do item da lista.

Desktop Texto "Publicação patrocinada com TabCash" numa linha acima do título do conteúdo. O texto é amarelo, em negrito. Fundo do item em amarelo claro.
Mobile O mesmo cenário que o anterior, porém numa tela menor

Trouxe esse exemplo para ver como ficava. É algo similar ao que o Google fazia anos atrás. Para a cor de fundo, usei attention.subtle.

Não gostei dessa alternativa. Não é terrível, ela é viável, mas acho que está dando destaque demais aos anúncios (mesmo a cor de fundo sendo clara), e precisaríamos ter uma atenção extra aos contrastes. Além disso, com os Banners causará uma poluição maior ainda. Outro ponto é que nossos olhos se acostumarão a ignorar isso (banner blindness).

aprendendofelipe commented 6 months ago

Ótimos estudos Rafa!

Vendo os resultados, eu acho que não é necessário algo tão chamativo para deixar claro que é um conteúdo promovido.

O que acham de algo assim?

Conteúdo Lista
Conteúdo Patrocinado Conteúdo Patrocinado na lista
Rafatcb commented 6 months ago

@aprendendofelipe eu gostei do uso do verde, já que é a cor do TabCash. Na lista de conteúdos, não sei se teríamos casos "muito ruins", onde o nome do usuário ficaria "r...", principalmente considerando a duração sendo algo como "22 minutos atrás", que é um texto mais longo.

Na publicação em si, você não acha que pode ter aquele problema que mencionei, dos Labels serem mais relacionados ao autor do que ao conteúdo? Uma alternativa pode ser como ficou na lista de conteúdo, escrito em texto normal, colorido e sem a borda.

Eu esbocei mais algumas ideias, agora no fluxo de criar uma publicação promovida. Eu comecei a criar estes exemplos antes do seu comentário, por isso estão similares ao meu comentário anterior, mas obviamente aqui seguiríamos o padrão adotado (cores e termos escolhidos).

Uma nova pergunta, acha melhor usarmos "Patrocinar/Patrocinado" ao invés de "Promover/Promovida" em todo lugar? Eu acho que faz sentido, mas nos exemplos que criei abaixo está uma mistura, a depender do local onde o texto é exibido.

Como criar uma publicação promovida

Informações necessárias

Com base nos comentários anteriores, esse processo pode exibir algumas informações e demandar outras do usuário. Além do necessário para criar uma publicação normal, a criação de uma publicação promovida provavelmente envolverá:

UI

Seguindo com algumas elaborações de UI, estou colocando aqui mais algumas ideias justamente para outras pessoas poderem opinar e já termos algo mais trabalhado na hora de chegar na implementação (ou seja, ninguém ser pego de surpresa ao avaliar um PR).

Independente de onde for adicionado esse fluxo, imagino que a opção de criar uma publicação promovida deve estar visível apenas caso o usuário tenha a feature, e habilitada apenas caso o usuário possa realmente criar, por exemplo, se o limite de publicações promovidas for X, e já terem X publicações promovidas, então a ação ficaria desabilitada com uma explicação próxima. Algo como:

Não é possível criar uma publicação promovida agora, saiba mais (link para uma pergunta do FAQ que explica isso).

Ou mesmo algo específico já dizendo o motivo de não poder criar a publicação promovida.

1. Adicionar um Checkbox na página /publicar e exibir os campos específicos quando ele estiver marcado

Um checkbox no fim do formulário de campos para criar uma publicação, escrito "Promover publicação. Saiba mais.", onde o "Saiba mais" é um link

Essa foi a primeira ideia que passou pela minha cabeça. Podemos exibir um Checkbox para os usuários que já possuem a feature de "promover publicação". Para dar contexto, poderia ter um link Saiba mais (ou outro texto) direcionando para a pergunta do FAQ sobre publicações promovidas.

É uma solução simples e discreta. O aviso para o estado disabled pode ser assim:

Texto "Não é possível criar uma publicação promovida agora. Saiba mais." abaixo do Checkbox. O "Saiba mais" é um link

Aqui, o Saiba mais também é um link para o FAQ (outra pergunta). Usei o FormControl.Caption para exibir a mensagem.

Os campos relacionados à uma publicação promovida podem ser exibidos ao marcar o Checkbox:

Desktop Mobile
Abaixo do checkbox "Promover publicação. Saiba mais" marcado, três campos na mesma linha: "TabCoins promovidos" com a legenda "Sua publicação iniciará com 1 TabCoin.", "Limite de TabCash" com a legenda "Ao atingir o limite, a publicação será removida." e "Limite de tempo (em horas)" com a legenda "Tempo máximo que a publicação ficará visível.", seguido por "Custo inicial: 32 TabCash" numa nova linha, em negrito, amarelo. O mesmo cenário da imagem anterior, mas numa tela pequena. Cada campo fica numa linha diferente.

Não consegui pensar numa boa exibição para os campos, já que eles tem valores curtos. Tentei buscar um equilíbrio entre o tamanho do Label e do Caption para os campos serem auto-explicativos. Nos exemplos acima, a largura dos TextInputs está em 100px e os dois primeiros FormControls estão com sx={{ flex: '1 1 160px' }}, e o terceiro sx={{ flex: '1 1 204px' }}.

Depois de ter visto o exemplo do @aprendendofelipe , tive uma outra ideia de como exibir o custo, que acho mais consistente com nossa UI:

fontSize não especificado Texto "Custo inicial: 32 TabCash" sem negrito e na cor preta normal, mas com o ícone do TabCash
fontSize: 1 Mesma imagem que a anterior, porém com o texto menor

Sem especificar o fontSize, o texto fica maior do que o resto da página (Labels, Captions e o texto dos campos obrigatórios), então coloquei também uma imagem com o fontSize: 1.

2. Nova página para criar publicação promovida, com link dentro do próprio perfil

Desktop Mobile
Perfil do usuário, numa tab escrita "Publicações promovidas", mostrando uma lista de publicações. A primeira está com um texto negrito amarelo "Publicação patrocinada com TabCash", a segunda não. O mesmo cenário da imagem anterior, mas numa tela pequena.

Outra opção é criar uma publicação promovida numa página própria. Isso não é totalmente necessário, mas foi a única alternativa ao exemplo anterior que consegui pensar. Eu havia pensado nisso inicialmente para evitar que o usuário criasse uma promovida sem querer, por exemplo, mas como ele precisará preencher novos campos, não acho que isso é um problema.

Essa nova página pode ser acessada através de uma tab no próprio perfil onde o usuário pode ver as publicações promovidas (ativas ou inativas) e mais detalhes sobre elas, já que o seu histórico de publicações promovidas não ficará disponível na aba "Publicações" do perfil (lá pode ser exibida a publicação promovida que está ativa).

Além das publicações que já foram promovidas, a lista pode conter todos os tipos de anúncios, e o botão "Criar publicação" pode ser um botão com o ícone de três pontos (KebabHorizontalIcon), onde exibirá o ActionMenu com opções para criar uma publicação promovida, um banner etc. A princípio, apenas o próprio usuário teria acesso à essa página, mas podemos criar uma permissão para que moderadores vejam o histórico de anúncios de outros usuários.

Ao clicar no botão "Criar publicação", redirecionaríamos para uma página /publicar-promovida, por exemplo, que seria parecida com a /publicar, porém com um texto mais claro de que está criando uma publicação promovida. Talvez a única diferença acabasse sendo o h1 e não ter um checkbox. Depois de ter feito a opção 1, acho que não precisamos de uma página específica para criar uma publicação promovida.

3. Aba de publicações promovidas dentro do próprio perfil, com link para /publicar

Também podemos optar por uma mistura da opção 1 e 2, onde existirão dois caminhos para criar uma publicação promovida:

  1. Indo direto para /publicar; ou
  2. Indo no perfil, vendo as publicações promovidas/anúncios e clicando no botão Criar publicação, que redirecionará para /publicar, mas com o Checkbox "Promover publicação. Saiba mais." marcado.
aprendendofelipe commented 6 months ago

@aprendendofelipe eu gostei do uso do verde, já que é a cor do TabCash.

Pensei no verde por esse motivo mesmo, mas para exemplificar usei o padrão do label ao invés de usar a mesma cor do TabCash. Escolhendo o verde mesmo, que por mim está legal, podemos ver qual tom fica melhor.


Na lista de conteúdos, não sei se teríamos casos "muito ruins", onde o nome do usuário ficaria "r...", principalmente considerando a duração sendo algo como "22 minutos atrás", que é um texto mais longo.

Sim, isso iria ocorrer em telas muito pequenas, onde acho que poderíamos omitir o saldo de TabCoins para ficar melhor.

E pensando em omitir o saldo de TabCoins, me ocorreu agora que talvez faça sentido omitir sempre o saldo dos promovidos na lista de conteúdos, já que o número em si será algo artificial. Podemos talvez mostrar o detalhamento dos votos junto dos TabCoins promovidos no mesmo Tooltip. Algo a se pensar...

Ficaria como abaixo, onde também já coloquei o tom verde de TabCash, pois me pareceu melhor, principalmente no modo dark:

Conteúdo patrocinado

Na publicação em si, você não acha que pode ter aquele problema que mencionei, dos Labels serem mais relacionados ao autor do que ao conteúdo? Uma alternativa pode ser como ficou na lista de conteúdo, escrito em texto normal, colorido e sem a borda.

Acho que os labels não precisam ser somente sobre o autor. Acho que podem ser também sobre o conteúdo, mas vamos ver como fica sem a borda. 👍


Uma nova pergunta, acha melhor usarmos "Patrocinar/Patrocinado" ao invés de "Promover/Promovida" em todo lugar? Eu acho que faz sentido, mas nos exemplos que criei abaixo está uma mistura, a depender do local onde o texto é exibido.

Como palavra única que já expressa o que queremos, eu acabei gostando mais de "patrocinado" do que "promovido", mas para o verbo gosto mais de "promover" do que de "patrocinar".

Talvez para deixar ainda mais claro, e menos repetitivo, pode mudar o Tooltip para "Promovido com TabCash", mesmo mantendo a palavra "Patrocinado" no destaque me verde. Eu acho melhor se der para unificar, mas é mais importante deixar claro, então é melhor saber outras opiniões sobre isso...


Gostei das sugestões para criar a publicação, e acho que é bom deixar mais de um caminho para chegar até lá.

O endereço da página pode ser o mesmo de publicar qualquer conteúdo, pois acho que isso facilita para os usuários. Caso contrário teremos que criar um modo fácil do usuário migrar os dados de uma página para a outra, caso ele tenha começado a criar no lugar errado.

Uma alternativa legal para se testar é usar um Dialog com os campos extras.

Rafatcb commented 6 months ago

@aprendendofelipe não sei se você já começou a implementar algo. Eu estou apenas pensando em como poderia ser feito. Como parece que os campos mencionados nos comentários anteriores seriam o suficiente para criar um anúncio, comecei a pensar na parte da API e do banco de dados.

Neste comentário já vou colocar alguns nomes de campos, propriedades e tabela do banco de dados, então se terem sugestões melhores, podem falar.

Tem bastante informação aqui, e eu acabei escrevendo num "vai e volta", complementando conforme percebia detalhes, então se algo ficou incompleto ou inconsistente, me avise também.

Criação de uma publicação patrocinada

API: POST /api/v1/contents

Como (muito provavelmente) usaremos a mesma tela para criar uma publicação normal e uma publicação patrocinada, podemos usar o mesmo endpoint, adicionando uma funcionalidade sem quebrar o comportamento atual.

{
  title: string,
  body: string,
  status: 'published' | 'draft',
  source_url: string | undefined,
+   sponsor: {
+     initial_tabcoins: number,
+     max_tabcash: number,
+     max_hours: number,
+   }
}

Pensando sobre, eu gostei da ideia de adicionar um novo atributo (no caso, sponsor) que conterá todas as informações necessárias para criar um conteúdo patrocinado (ou, futuramente, promover um conteúdo existente). Assim, deixamos essa funcionalidade "encapsulada", facilitando a validação e deixando claro que os atributos aninhados (initial_tabcoins, max_tabcash e max_hours) estão relacionados à essa funcionalidade.

Banco de dados

Hoje, em contents, temos id, parent_id, owner_id, slug, title, body, status, source_url, published_at, created_at, updated_at, deleted_at e path.

Pensando numa flexibilidade em tratar diferentes tipos de anúncio de uma forma parecida, me parece compensar criar uma tabela para eles. Talvez advertisements. Acho o nome um pouco complicado mas não consegui pensar em algo melhor (ads?).

Essa nova tabela poderia armazenar informações úteis sobre todo tipo de anúncio.

Levando em consideração o que é importante para a criação de uma publicação promovida (initial_tabcoins, max_tabcash e max_hours), a primeira informação ficará armazenada em balance_operations, então sobram max_tabcash e max_hours.

Ambas são relevantes para o caso de um anúncio de custo variável. Temos que pensar também que um outro tipo de anúncio pode ter um custo inicial X e nenhum custo variável.

Dito isso, o que seria interessante de ter numa tabela de anúncios?

A quantidade de TabCash gasto no anúncio, seja ele fixo ou variável, pode ser obtida pelo balance_operations, como é feito com os TabCoins de conteúdos e usuários, e com o TabCash de usuários.

PS: deactivate_at e deactivated_at são nomes bem parecidos e podem causar confusão na hora de programar e na revisão do código.

Eventos

Hoje, ao criar uma publicação, criamos um evento e depois atualizamos ele com metadata:

{
  type: 'create:content:text_root',
  originatorUserId: string,
  originatorIp: string,
  metadata: {
    id: string
  }
}

Agora que já refleti sobre quais dados poderíamos armazenar especificamente sobre a publicação patrocinada na tabela própria de anúncios, consigo pensar melhor sobre o que armazenar no evento.

Procurando manter o padrão, podemos armazenar apenas o id do anúncio. Saindo do padrão, podemos armazenar também a quantidade de TabCash que o usuário tinha no momento de criação da publicação patrocinada. Não sei se isso faz sentido.

A partir daqui, vejo duas opções ao criar uma publicação patrocinada:

1. Armazenar novos dados no evento criado.

Podemos armazenar os dados discutidos acima no metadata do evento create:content:text_root:

{
  type: 'create:content:text_root',
  originatorUserId: string,
  originatorIp: string,
  metadata: {
    id: string,
    advertisement_id: string,
    user_tabcash: number
  }
}

2. Criar o evento create:content:text_root, mas também criar um novo evento específico (sponsor:text_root).

Outra opção é criar, além do create:content:text_root, um novo evento para um conteúdo patrocinado, já tendo em mente que futuramente poderemos promover um conteúdo já publicado, onde criaríamos este evento também.

Acredito que assim facilitará a busca desse tipo de evento (conteúdo patrocinado) sem precisar buscar por algo armazenado no metadata.

Os dados armazenados em metadata seriam os mesmos da opção 1, com uma leve mudança, já que o metadata.id seria o identificador do anúncio, e não do conteúdo:

{
  type: 'sponsor:text_root',
  originatorUserId: string,
  originatorIp: string,
  metadata: {
    id: string,
    content_id: string,
    user_tabcash: number
  }
}

Podemos seguir esse mesmo raciocínio com outros tipos de anúncio, como o anúncio em banner (que é outro issue) que poderia ser sponsor:banner, por exemplo.

Não sei se vale a pena diferenciar o tipo aqui também, como mencionei na tabela advertisement, criando um tipo sponsor:text_root:temporary e outro sponsor:text_root.

Atualização do saldo

Precisaríamos criar um registro em balance_operations sobre o gasto de TabCash do usuário, assim como já ocorre ao ganhar TabCoins/TabCash e ao perder Tabcoins.

Em balanceType existem os tipos user:tabcoin, user:tabcash, content:tabcoin:initial, content:tabcoin:credit e content:tabcoin:debit. O amount pode ser um valor positivo ou negativo. Dito isso, não teríamos nenhuma novidade:

{
  balanceType: 'user:tabcash',
  recipientId: string, // id do usuário
  amount: number, // negativo, valor gasto para promover a publicação
  originatorType: 'event',
  originatorId: string // id do evento `create:content:text_root` (opção 1) ou `sponsor:text_root` (opção 2) 
}

O custo de TabCash não foi definido ainda.

Voto em publicação patrocinada

API: POST /api/v1/contents/[username]/[slug]/tabcoins

Nada muda na interface.

O comportamento será diferente. Ao invés de dar TabCash ao autor do conteúdo, irá consumir. Se o autor ficar sem TabCash, a publicação deve deixar de ser patrocinada.

Sobre o consumo de TabCoins para votar e o limite de votos, não foi definido (eu dei uma opinião em https://github.com/filipedeschamps/tabnews.com.br/issues/1491#issuecomment-1970168518 diferente do que havia sido sugerido em outros comentários).

Eventos

Hoje o evento criado é:

{
  type: 'update:content:tabcoins',
  originatorUserId: string,
  originatorIp: string,
  metadata: {
    transaction_type: 'credit' | 'debit',
    from_user_id: string,
    content_owner_id: string,
    content_id: string,
    amount: 2
  }
}

A mudança no evento acima dependerá de uma mudança do comportamento, isto é, se haverá cobrança de TabCoins ou não (amount = 2 ou 0). Fora o amount, acredito que o resto permaneça igual.

Atualização do saldo

Hoje acontecem quatro atualizações no saldo:

  1. user:tabcoin: quem votou, perde 2 TabCoins.
  2. user:tabcash: quem votou, ganha 1 TabCash.
  3. user:tabcoin: o autor da publicação ganha ou perde 1 TabCoin.
  4. content:tabcoin:credit ou content:tabcoin:debit: o conteúdo ganha ou perde 1 TabCoin.

Deverá ser atualizado para:

  1. user:tabcoin: com a mudança de comportamento, pode continuar igual ou não existir mais.
  2. user:tabcash: com a mudança de comportamento, pode continuar igual ou não existir mais.
  3. user:tabcash: depende da mudança de comportamento. Talvez o autor perca TabCash apenas se for um voto positivo, talvez perca sendo positivo ou negativo. Imagino que o valor será 1 TabCash (não me lembro de ter visto um comentário sugerindo outro valor).
  4. content:tabcoin:credit ou content:tabcoin:debit: o conteúdo ganha ou perde 1 TabCoin. (sem mudanças)

Obter publicação patrocinada

API: GET /api/v1/contents/[username]/[slug] e GET /api/v1/contents/[username]/[slug]

Aqui será necessário verificar se a publicação é patrocinada.

Na API, imagino que poderíamos passar um is_sponsored: true. O que acham? Para isso, vou colocar duas opções que consegui imaginar:

1. Realizar um JOIN para verificar se a publicação existe na tabela advertisements, e se o registro mais recente ainda está ativo. Talvez isso "pese" nas consultas.

2. Criar uma coluna a mais na tabela contents que indica se está patrocinada ou não. Ainda precisaríamos verificar em algum momento se a publicação está patrocinada para atualizar o valor dessa coluna.

Atualizar publicação patrocinada

API: PATCH /api/v1/contents/[username]/[slug]

Além do que já existe hoje, podemos permitir o usuário alterar o gasto máximo de TabCash e o tempo de duração caso seja uma publicação patrocinada e ativa. Podemos continuar passando o objeto sponsor, como na criação, mas apenas com max_tabcash e max_hours.

Acredito que não devemos ter nenhuma restrição ao atualizar um conteúdo patrocinado: tudo bem atualizar o título, corpo e fonte, e também atualizar o status para deleted, sem reembolsar o TabCash gasto.

No caso de deleted, já podemos atualizar a tabela advertisements, caso a criemos.

Caso seja uma publicação não patrocinada, eu sugiro permitir promovê-la, mas não agora, para não deixar a primeira fase de implementação ainda mais complexa. Nesse caso, só precisaria passar o objeto sponsor que sugeri no tópico sobre a criação da publicação, com max_tabcash, max_hours e initial_tabcoins.


Dúvidas

O que fazer quando acabar o período de uma publicação temporária patrocinada?

Considerando que vamos criar a publicação na tabela contents, após o período ela ficará como deleted?

E quando isso será verificado?

Terá um tipo de cronjob, além de uma verificação quando a publicação receber votos (para verificar se o autor ainda possui TabCash disponível), ou será verificado sempre que ter um GET na lista de conteúdos para ver se o tempo acabou?


Uma forma de burlar ao promover uma publicação "permanente"

Futuramente, ao permitirmos promover uma publicação existente, surgirá uma preocupação: a pessoa usar os Tabcoins iniciais para impulsionar e depois remover o patrocínio. Assim, a publicação terá destaque em Relevantes por causa dos TabCoins, mas não aparecerá como patrocinada e nem custará TabCash quando o autor receber votos positivos.

Estou colocando isso aqui apenas para não esquecer desse detalhe. De início, não será uma preocupação porque a publicação desaparecerá, já que é temporária.

aprendendofelipe commented 5 months ago

Ótimos pontos @Rafatcb! 💪

Você focou, mas acho melhor focarmos ainda mais nas publicações promovidas, sem querer já deixar "preparado" para outros tipos de anúncios, pois depois podem (ou não) ser criadas tabelas/formulários/fluxos totalmente diferentes para cada tipo. Um único tipo de anúncio já é complexidade suficiente, e já vai exigir quebrar o problemas em diversos menores.

Publicações promovidas

Eu pensei nesse nome "publicação promovida" para aproveitarmos o que der do que já foi pensado para as publicações, além de mostrar eles na lista de conteúdos, mas não pensando em poder realmente promover um conteúdo. Anúncios serão anúncios, apenas poderão ter um formato parecido com o dos conteúdos, ou seja, um título, o corpo em markdown e um link destacado no final (que provavelmente não será uma fonte, mas uma chamada para ação).

Dito isso, acho que não precisamos (nem devemos) deixar preparado para lidar com transformação de publicação em anúncio e vice-versa, e nem salvar nada dos anúncios na tabela de conteúdos. Os eventos e endpoints provavelmente serão apenas parecidos com os dos conteúdos.

Tabela Balance Operations

Acho que compensa colocar como pré-requisito a separação em diferentes tabelas antes de começarmos as transações com TabCash.

Ou só eu que enxergo TabCoins de conteúdos, TabCoins de usuários e TabCash como três ativos completamente diferentes? Eles nunca precisarão ser computados juntos.

Rafatcb commented 5 months ago

e nem salvar nada dos anúncios na tabela de conteúdos

Entendi. Então, publicações patrocinadas (anúncios) e promovidas ("normais impulsionadas") serão duas coisas diferentes mesmo, apesar de terem algumas características em comum.

Ou só eu que enxergo TabCoins de conteúdos, TabCoins de usuários e TabCash como três ativos completamente diferentes? Eles nunca precisarão ser computados juntos.

Eu enxergo como três coisas diferentes também, mas os TabCoins e TabCash do usuário são computados juntos para retornar com os dados do usuário, além do caso do voto, que muda o saldo de TabCoin e TabCash do mesmo usuário. Acha que vale a pena separar em três tabelas mesmo?

aprendendofelipe commented 5 months ago

Entendi. Então, publicações patrocinadas (anúncios) e promovidas ("normais impulsionadas") serão duas coisas diferentes mesmo, apesar de terem algumas características em comum.

Sim, e pode ser até que as impulsionadas nunca sejam implementadas.

Ou só eu que enxergo TabCoins de conteúdos, TabCoins de usuários e TabCash como três ativos completamente diferentes? Eles nunca precisarão ser computados juntos.

Eu enxergo como três coisas diferentes também, mas os TabCoins e TabCash do usuário são computados juntos para retornar com os dados do usuário, além do caso do voto, que muda o saldo de TabCoin e TabCash do mesmo usuário.

Mas não é junto no sentido de se beneficiar dos dados estarem na mesma tabela.

Acha que vale a pena separar em três tabelas mesmo?

Acredito que sim 👍

Rafatcb commented 5 months ago

@aprendendofelipe imagino que a próxima etapa seja elaborar o esquema da nova tabela para esse tipo de anúncio, conforme as necessidades que foram discutidas acima, certo?

Rafatcb commented 5 months ago

Banco de dados

Tabela para publicações patrocinadas

Pensando no banco de dados e reaproveitando algumas coisas que comentei em https://github.com/filipedeschamps/tabnews.com.br/issues/1491#issuecomment-2002219992, podemos ter uma tabela sponsored_posts para representar as publicações patrocinadas. As colunas seriam:

O initial_tabcoins, que será um dado informado ao criar uma publicação patrocinada, pode ser obtido através da tabela de saldos.

Saldo

Eu sugeri que os votos em publicações patrocinadas continuem consumindo TabCoins de quem votou. Pelo o que me lembro, ninguém concordou nem discordou. Se essa sugestão for aceita, então será criado um debit em content_tabcoin_operations como já é feito em "votos normais" hoje.

Entretanto, do lado do autor da publicação, ao invés de ganhar TabCash, perderá. Se formos seguir o padrão de content_tabcoin_operations, então podemos criar uma coluna balance_type na tabela user_tabcash_operations com os tipos credit e debit. Após a migração, todos os valores existentes hoje seriam do tipo credit.

Ao criar uma publicação patrocinada, o autor também perde TabCash, e acredito que podemos seguir o mesmo raciocínio do parágrafo anterior.

Por fim, temos o saldo de TabCoins da publicação patrocinada. O comportamento é muito parecido com o de contents, com os valores initial, credit e debit, mas a publicação patrocinada está na tabela sponsored_posts, e não contents, e recentemente fizemos uma separação de balance_operations para três tabelas diferentes, cada uma sobre um tipo de saldo específico. Dito isso, me parece ser necessário criar uma tabela sponsored_post_tabcoin_operations.

Então aqui teríamos:

Eventos

Ao criar uma publicação patrocinada:

{
  type: 'create:sponsored_post',
  originator_user_id: string,
  originator_ip: string,
  metadata: {
    id: string,
    user_tabcash: number
  }
}

Ao votar numa publicação patrocinada:

{
  type: 'update:sponsored_post:tabcoins',
  originator_user_id: string,
  originator_ip: string,
  metadata: {
    amount: number,
    sponsored_post_id: string,
    from_user_id: string,
    sponsored_post_owner_id: string,
    transaction_type: 'credit' | 'debit'
  }
}

Ao editar uma publicação patrocinada:

{
  type: 'update:sponsored_post',
  originator_user_id: string,
  originator_ip: string,
  metadata: {
    id: string,
    updated_fields: string[] // similar à edição do perfil
  }
}

Ao desativar uma publicação patrocinada:

{
  type: 'deactivate:sponsored_post',
  originator_user_id: null | string,
  originator_ip: null | string,
  metadata: {
    id: string,
    trigger: 'owner' | 'moderator' | 'max_tabcash_cost' | 'time_expired' | 'not_enough_tabcash'
  }
}

Esse último evento sai do padrão que temos em outras ações (criação de conteúdo, edição etc.), mas acredito ser relevante. Não sei se o motivo (metadata.trigger) da publicação patrocinada ter sido "desativada" deve estar em events ou outro lugar, mas parece útil guardar essa informação.


Me corrijam se algo estiver errado e digam se esqueci de algo ou se possuem sugestões de melhoria.

aprendendofelipe commented 5 months ago

Pensando no banco de dados e reaproveitando algumas coisas que comentei em #1491 (comment), podemos ter uma tabela sponsored_posts para representar as publicações patrocinadas.

Por que mudar o padrão de contents para posts? Não acha melhor sponsored_contents?

As colunas seriam:

  • body: Acho interessante ser obrigatório; não me parece que uma publicação patrocinada sem texto seria bem recebida.

Concordo. O caso sem o body poderia ser um outro tipo de anúncio para pensarmos no futuro, onde, ao clicar no título, já direciona diretamente para fora do TabNews, mas precisa ficar claro que isso irá acontecer, e é algo bem diferente do discutido aqui, já que não teria qualificações (nem a página específica do anúncio para receber votos), ou seja, aqui o body precisa ser obrigatório mesmo.

  • link: O link que está sendo patrocinado (parecido com a fonte de uma publicação). Obrigatório.

O que você pensa como justificativa para o link ser obrigatório? Talvez fizesse sentido se fosse proibido colocar links no corpo do anúncio, mas não sei se nesse momento precisamos nos preocupar com isso.

  • max_tabcash_cost: Quantidade limite de TabCash que o anúncio consumirá até sair do ar.

Melhor deixar isso para a tabela com o balanço de TabCash dos anúncios. Daí, para definir os anúncios que serão mostrados, não será preciso consultar o saldo do usuário, mas apenas do anúncio, assim como as qualificações também só precisarão movimentar o saldo dos anúncios.

Na publicação/edição, o autor vai reservar certa quantidade de Tabcash que poderá ser consumida, e isso entra no balanço do anúncio. O autor poderá editar o anúncio para disponibilizar mais TabCash, e até poderia retirar o anúncio do ar e resgatar o saldo remanescente, uma possibilidade que não precisa existir na primeira versão, se isso complicar algo.

Com isso evitamos que a soma dos limites de TabCash dos anúncios de um mesmo usuário fique acima do saldo disponível desse usuário. Esse detalhe é algo importante se formos liberar mais de um anúncio ao mesmo tempo para o usuário. E mesmo se formos limitar a um anúncio, acredito que o limite seria por tipo de anúncio, então isso ainda será importante.

Falando sobre limitar a quantidade de anúncios ativos de um mesmo usuário, pode ser suficiente limitarmos os anúncios exibidos ao mesmo tempo, sem precisar limitar a quantidade ativa, pois assim permitimos a criação de campanhas com diferentes anúncios que se revezam.

  • deactivate_at: Horário que o anúncio sairá do ar, calculado a partir do "tempo máximo" informado pela UI/API.
  • deactivated_at: O anúncio pode ser desativado antes do deactivate_at de forma manual, pelo limite de consumo de TabCash ou por falta de TabCash do autor.

Entendi, mas acho que não há necessidade das duas colunas. A deactivate_at seria equivalente à deleted_at da tabela contents, e a publish_at seria equivalente à published_at, com a diferença que no momento da criação (created_at) ou edição (updated_at) do anúncio, o autor pode escolher os horários de início e término do anúncio. E acho que faz mais sentido o autor definir diretamente as datas e horários do que escolher um limite de tempo em horas.

Se o autor decidir retirar o anúncio antes da hora definida anteriormente, basta ele editar a publicação, alterando o deactivate_at, e isso ficará registrado nos eventos. Ele pode até não definir deactivate_at e, nesse caso, o que vai definir se o anúncio continua disponível é o saldo de TabCoins/TabCash do anúncio. O saldo insuficiente também vai impedir a exibição do anúncio mesmo que ainda esteja dentro da faixa de tempo entre publish_at e deactivate_at.

O initial_tabcoins, que será um dado informado ao criar uma publicação patrocinada, pode ser obtido através da tabela de saldos.

Esse initial_tabcoins é sobre o que eu falei dos TabCoins promovidos, certo? Não tenho certeza sobre a forma exata que pensei quando rascunhei a descrição da issue, mas agora penso que isso não deve alterar o saldo que aparece para os usuários. Acho que os usuários deveriam ver apenas o saldo das qualificações. Talvez seja ainda melhor mostrar apenas a quantidade de qualificações positivas, mesmo que começando sempre em 1, como é o padrão dos conteúdos.

O TabCash consumido inicialmente, e que vai definir o destaque inicial da publicidade entre as demais publicidades, não poder ser confundido com o saldo de qualificações.

Então TabCoins promovidos e initial_tabcoins não são bons nomes para isso. Seria melhor usar um nome relacionado à TabCash, que é o que realmente será utilizado. Então esse destaque inicial seria dependente da quantidade de TabCash que foi "gasta" pelo autor de forma permanente ao criar a publicação, sem contar a parte que pode ser consumida com as qualificações (e futuramente com as visualizações). E isso vai na tabela de balanço de TabCash dos anúncios.

Uma simplificação que pode fazer sentido na versão inicial, é não separar o que é consumido de forma definitiva e o que poderia ser resgatado. Deixa o consumo de TabCash ao criar a publicidade como sendo permanente, e esse valor contribui ao mesmo tempo em qual é o posicionamento inicial (pois ainda não há qualificações), e quantas qualificações o anúncio poderá receber.

Será que quem vota em anúncios deveria ganhar TabCash? Para incentivar os votos em anúncios, acho que será preciso dar TabCash. Nesse caso, o custo mínimo em TabCash para o autor do anúncio tem que ser maior do que 1 TabCash por voto recebido.

Eu sugeri que os votos em publicações patrocinadas continuem consumindo TabCoins de quem votou. Pelo o que me lembro, ninguém concordou nem discordou. Se essa sugestão for aceita, então será criado um debit em content_tabcoin_operations como já é feito em "votos normais" hoje.

Continuo achando que votos em anúncios não devem consumir TabCoins, pois isso restringe menos os usuários que podem votar, e não compete com as qualificações dos conteúdos. É importante incentivar mais os votos em anúncios, pois enquanto não estivermos computando as visualizações, o alcance será medido/cobrado (TabCash) pelas qualificações.

Acho que será normal alguns tipos de anúncios receberem mais votos negativos, e podemos usar isso na classificação deles, diminuindo o alcance dos mais negativados, mas sem retirar totalmente do ar, e sim fazer com que o investimento para sua exibição seja maior.

E isso dos votos negativos é o que mais me faz pensar que talvez seja interessante mostrar apenas os votos positivos dos anúncios.

Acho que é consenso que devemos limitar a um voto por usuário, e tudo isso facilita armazenar os votos já que podemos usar uma CONSTRAINT UNIQUE composta pelo id do anúncio e do usuário que votou. Isso faz a modelagem dos votos dos anúncios ficar ainda mais diferente dos conteúdos, mas deve ser bem diferente mesmo.

Entretanto, do lado do autor da publicação, ao invés de ganhar TabCash, perderá.

Dá a impressão que você está dizendo que hoje, nos conteúdos "normais", o autor ganha TabCash ao receber votos positivos, mas, por enquanto, o autor nunca ganha TabCash. Quem ganha Tabcash é quem vota nos conteúdos.

A nova funcionalidade permite usar TabCash, que será consumido em certa quantidade no momento de criar/editar um anúncio. O autor de uma publicidade poderá "ganhar" TabCash se implementarmos um resgate do que não foi consumido pelo anúncio, mas isso pode até ficar para outro momento.

Se formos seguir o padrão de content_tabcoin_operations, então podemos criar uma coluna balance_type na tabela user_tabcash_operations com os tipos credit e debit. Após a migração, todos os valores existentes hoje seriam do tipo credit.

Será que você quis dizer sponsored_tabcash_operations? Não consegui enxergar a necessidade da coluna balance_type na tabela user_tabcash_operations.

Ao criar uma publicação patrocinada, o autor também perde TabCash,

Consumir e perder não são sinônimos. Melhor usar a palavra "perder" apenas em casos de "erros" ou "punições". A princípio, o autor do anúncio apenas "consome" seu TabCash. É claro que ele estará "perdendo" TabCash se não estiver consumindo de forma inteligente, mas isso deveria ser a excessão, não a regra.

e acredito que podemos seguir o mesmo raciocínio do parágrafo anterior.

Pelo jeito você falava mesmo da tabela user_tabcash_operations, então não ficou clara qual seria a necessidade de balance_type. Não vejo necessidade de alterar a tabela atual.

Por fim, temos o saldo de TabCoins da publicação patrocinada. O comportamento é muito parecido com o de contents, com os valores initial, credit e debit, mas a publicação patrocinada está na tabela sponsored_posts, e não contents, e recentemente fizemos uma separação de balance_operations para três tabelas diferentes, cada uma sobre um tipo de saldo específico. Dito isso, me parece ser necessário criar uma tabela sponsored_post_tabcoin_operations.

Então aqui teríamos:

  • user_tabcash_operations: Nova coluna balance_type

Ainda não entendi qual é a necessidade da nova coluna.

  • sponsored_post_tabcoin_operations: Nova tabela, igual a content_tabcoin_operations.

Não acho que seria igual, mas apenas parecida.


Massa @Rafatcb, pensar sobre o assunto para fazer os comentários acima me deu uma clareza bem maior sobre como podemos chegar na primeira versão.

Rafatcb commented 4 months ago

Por que mudar o padrão de contents para posts? Não acha melhor sponsored_contents?

Mencionei o posts por ser algo específico de "conteúdos raiz", e não qualquer conteúdo (e pensando em conteúdos raiz ao invés de publicação, faria mais sentido sponsored_root_contents, que é bem verboso). Podemos seguir com sponsored_contents sem problemas.

O que você pensa como justificativa para o link ser obrigatório? Talvez fizesse sentido se fosse proibido colocar links no corpo do anúncio, mas não sei se nesse momento precisamos nos preocupar com isso.

Me parece estranho a pessoa criar um anúncio sem o CTA (call to action). Pensando em algumas situações que podem ocorrer (e que envolvem ao menos um link): divulgar um projeto, site, produto ou serviço, portfólio, vaga de emprego, perfil de rede social, blog... Você pensou em algum cenário de anúncio sem link?

O que pensei agora é realizar uma "pesquisa de mercado" ou algo do tipo pelos comentários, e o motivo de fazer isso num anúncio ao invés de numa publicação normal seria a possibilidade de ter um impulsionamento inicial. Pode fazer sentido permitir isso.

Melhor deixar isso para a tabela com o balanço de TabCash dos anúncios. Daí, para definir os anúncios que serão mostrados, não será preciso consultar o saldo do usuário, mas apenas do anúncio, assim como as qualificações também só precisarão movimentar o saldo dos anúncios.

Na publicação/edição, o autor vai reservar certa quantidade de Tabcash que poderá ser consumida, e isso entra no balanço do anúncio. O autor poderá editar o anúncio para disponibilizar mais TabCash, e até poderia retirar o anúncio do ar e resgatar o saldo remanescente, uma possibilidade que não precisa existir na primeira versão, se isso complicar algo.

Hm, não havia pensado numa tabela de saldo de TabCash dos anúncios. Você pensou nela como tendo esse saldo inicial investido pelo autor, e depois cada tipo de interação seria como um débito nessa tabela? Parece uma boa forma de lidar com isso, melhor do que retirar aos poucos do autor. No fim do tempo limite do anúncio, podemos reembolsar o autor se houver TabCash não utilizado.

deactivate_at seria equivalente à deleted_at da tabela contents, e a publish_at seria equivalente à published_at

Eu não havia sugerido uma publish_at :sweat_smile: , não pensei na possibilidade de "agendar" um anúncio numa primeira versão, mas entendi seu comentário.

O saldo insuficiente também vai impedir a exibição do anúncio mesmo que ainda esteja dentro da faixa de tempo entre publish_at e deactivate_at.

Sim, mas não teremos em sponsored_contents o horário exato que o anúncio foi desativado. Faz sentido manter o deactivated_at como um dado a mais para o autor? Possibilitaria um raciocínio como "Criei um anúncio com X TabCash esperando que fosse durar N dias, mas durou M", ou mesmo uma verificação sobre qual foi a duração de cada anúncio que ele criou.

Mesmo que optemos por não ter o deactivated_at agora e optemos por criar ele em outro momento, esse dado poderia ser "calculado" com base na data do último saldo de TabCash que a publicação patrocinada "gastou", mas pensei ser uma informação útil de já armazenar no sponsored_contents.

Esse initial_tabcoins é sobre o que eu falei dos TabCoins promovidos, certo?

Sim, eu havia interpretado dessa forma.

Não tenho certeza sobre a forma exata que pensei quando rascunhei a descrição da issue, mas agora penso que isso não deve alterar o saldo que aparece para os usuários. Acho que os usuários deveriam ver apenas o saldo das qualificações. Talvez seja ainda melhor mostrar apenas a quantidade de qualificações positivas, mesmo que começando sempre em 1, como é o padrão dos conteúdos.

O TabCash consumido inicialmente, e que vai definir o destaque inicial da publicidade entre as demais publicidades, não poder ser confundido com o saldo de qualificações.

Então, vamos supor que o autor impulsione com 10 TabCash. Para facilitar o entendimento aqui, vamos dizer que 1 TabCash equivale a 1 TabCoin (na hora da implementação, muito provavelmente será diferente).

É assim que você pensou? E no hover, exibiria que tipo de detalhes sobre os votos? +1 | -1 ou também exibiria a quantidade de TabCash de impulsionamento (no exemplo acima, 10)?

Acredito que podemos experimentar não contar os negativos no somatório. Outra opção que também podemos experimentar é não exibir o somatório de TabCoins que a publicação tem, e nesse cenário não sei se exibiríamos os dados no hover ou apenas usaríamos para calcular a posição no rank. Um exemplo mais ou menos assim é o Hacker News:

Seis publicações no Hacker News, uma não é possível votar, e não exibe a quantidade de votos

A publicação 10 não possui votos e nem a seta para votar porque é um anúncio. No nosso caso, permitiríamos votar.

Um ponto que considero positivo em esconder os votos é evitar a manada que ocorre de vez em quando, quando um conteúdo tem muitos votos positivos ou negativos, e acaba acumulando mais simplesmente por já ter muitos. Vejo isso com mais frequência em conteúdos negativados.

Será que quem vota em anúncios deveria ganhar TabCash? ... Continuo achando que votos em anúncios não devem consumir TabCoins, pois isso restringe menos os usuários que podem votar, e não compete com as qualificações dos conteúdos. É importante incentivar mais os votos em anúncios, pois enquanto não estivermos computando as visualizações, o alcance será medido/cobrado (TabCash) pelas qualificações.

Enxergo dois problemas em dar TabCash e não cobrar TabCoins:

  1. Isso incentivará o usuário a votar em todos os anúncios, mesmo sem prestar atenção, apenas para ganhar 1 TabCash.
  2. Isso pode desequilibrar o sistema, de forma que alguém que nunca fez uma publicação consiga acumular TabCash até conseguir fazer uma publicação patrocinada.

Acho positivo limitar a um voto por usuário, mas continuamos com os problemas acima. Lembrando o issue https://github.com/filipedeschamps/tabnews.com.br/issues/352, o fluxo completo imaginado na época era:

  1. Você gera TabCoins através de conteúdos com valor concreto.
  2. Depois gasta essas TabCoins qualificando outros conteúdos, e com isso gerando TabCash.
  3. Depois gasta esses TabCash em anúncios (e no futuro outras coisas, como features, ou qualquer outra coisa massa que conseguirmos inventar).

Se formos deixar sem custo de TabCoins para votar, acredito que a pessoa deva ter algum tipo de reputação (digamos, uma quantidade mínima de TabCoins ou TabCash), mas talvez isso limite ainda mais a quantidade de pessoas que podem interagir do que se mantivéssemos a cobrança de 2 TabCoins. Podemos considerar cobrar 1 TabCoin. O que acha de tudo o que mencionei aqui? Te fez pensar em algo diferente?

Entretanto, do lado do autor da publicação, ao invés de ganhar TabCash, perderá.

Dá a impressão que você está dizendo que hoje, nos conteúdos "normais", o autor ganha TabCash ao receber votos positivos, mas, por enquanto, o autor nunca ganha TabCash. Quem ganha Tabcash é quem vota nos conteúdos.

Me confundi no texto. Quis dizer que ao invés de ganhar TabCoin, perderia TabCash, mas conforme concordei com você neste comentário, o TabCash já estaria reservado para isso e essa reserva seria consumida conforme a publicação patrocinada recebesse votos, com uma possível implementação de devolver a reserva não utilizada (mesmo que não tenhamos o reembolso num primeiro momento, acho importante termos em algum momento).

Se formos seguir o padrão de content_tabcoin_operations, então podemos criar uma coluna balance_type na tabela user_tabcash_operations com os tipos credit e debit. Após a migração, todos os valores existentes hoje seriam do tipo credit.

Será que você quis dizer sponsored_tabcash_operations? Não consegui enxergar a necessidade da coluna balance_type na tabela user_tabcash_operations.

Não, quis dizer user_tabcash_operations mesmo. Enxergo duas opções:

A tabela content_tabcoin_operations funciona da primeira forma (mas também tem o balance_type initial). Não sei se temos algum benefício em criar o balance_type em user_tabcash_operations, mencionei apenas como possibilidade de seguir o padrão de content_tabcoin_operations.

sponsored_post_tabcoin_operations: Nova tabela, igual a content_tabcoin_operations.

Não acho que seria igual, mas apenas parecida.

Com base no seu comentário, fiquei em dúvida em como isso seria armazenado, visto que teremos tanto o TabCash que impulsionou a publicação patrocinada quanto os TabCoins de votos recebidos. Seriam duas tabelas, sponsored_content_tabcoin_operations e sponsored_content_tabcash_operations?

aprendendofelipe commented 4 months ago

Comentários

Mencionei o posts por ser algo específico de "conteúdos raiz", e não qualquer conteúdo

Falando nisso, a princípio penso que as publicações patrocinadas também receberão comentários. Ou será que é melhor não?

Chegou a pensar em armazenar os comentários das patrocinadas na tabela de conteúdos normais? Isso pode exigir alguma mudança na tabela.

Link obrigatório/opcional

O que você pensa como justificativa para o link ser obrigatório? Talvez fizesse sentido se fosse proibido colocar links no corpo do anúncio, mas não sei se nesse momento precisamos nos preocupar com isso.

Me parece estranho a pessoa criar um anúncio sem o CTA (call to action). Pensando em algumas situações que podem ocorrer (e que envolvem ao menos um link): divulgar um projeto, site, produto ou serviço, portfólio, vaga de emprego, perfil de rede social, blog... Você pensou em algum cenário de anúncio sem link?

Não acho estranho, mas, assumindo que seja, por que não poderíamos deixar o usuário criar o anúncio sem o link se ele preferir assim?

O que pensei agora é realizar uma "pesquisa de mercado" ou algo do tipo pelos comentários, e o motivo de fazer isso num anúncio ao invés de numa publicação normal seria a possibilidade de ter um impulsionamento inicial. Pode fazer sentido permitir isso.

A pesquisa seria para responder qual dúvida?

Tabelas de saldos

Hm, não havia pensado numa tabela de saldo de TabCash dos anúncios. Você pensou nela como tendo esse saldo inicial investido pelo autor, e depois cada tipo de interação seria como um débito nessa tabela? Parece uma boa forma de lidar com isso, melhor do que retirar aos poucos do autor.

Eu acho que o caminho é por aí.

A tabela content_tabcoin_operations funciona da primeira forma (mas também tem o balance_type initial). Não sei se temos algum benefício em criar o balance_type em user_tabcash_operations, mencionei apenas como possibilidade de seguir o padrão de content_tabcoin_operations.

O initial é uma razão para armazenarmos balance_type em content_tabcoin_operations. A outra razão é para poder anular um voto sem precisar criar um novo voto contrário, ou seja, +1 credit e -1 credit = 0 de saldo e considerado nenhum voto, pois 1 foi desfeito, o que é diferente de +1 credit e -1 debit = 0 de saldo, mas são 2 votos contrários.

Com base no seu comentário, fiquei em dúvida em como isso seria armazenado, visto que teremos tanto o TabCash que impulsionou a publicação patrocinada quanto os TabCoins de votos recebidos. Seriam duas tabelas, sponsored_content_tabcoin_operations e sponsored_content_tabcash_operations?

Dá para criar duas tabelas, ou uma só, tem vantagens e desvantagens em cada caso.

O saldo insuficiente também vai impedir a exibição do anúncio mesmo que ainda esteja dentro da faixa de tempo entre publish_at e deactivate_at.

Sim, mas não teremos em sponsored_contents o horário exato que o anúncio foi desativado. Faz sentido manter o deactivated_at como um dado a mais para o autor? Possibilitaria um raciocínio como "Criei um anúncio com X TabCash esperando que fosse durar N dias, mas durou M", ou mesmo uma verificação sobre qual foi a duração de cada anúncio que ele criou.

Mesmo que optemos por não ter o deactivated_at agora e optemos por criar ele em outro momento, esse dado poderia ser "calculado" com base na data do último saldo de TabCash que a publicação patrocinada "gastou", mas pensei ser uma informação útil de já armazenar no sponsored_contents.

Acho mais útil o usuário poder consultar um histórico do anúncio, como um extrato das qualificações e do TabCash. Mas não precisa disso no primeiro momento.

Mecânica

Então, vamos supor que o autor impulsione com 10 TabCash. Para facilitar o entendimento aqui, vamos dizer que 1 TabCash equivale a 1 TabCoin (na hora da implementação, muito provavelmente será diferente).

  • Autor investiu 10 TabCash.
  • A publicação exibe 1 TabCoin, mas está numa posição do rank como se tivesse 10 TabCoins.
  • Alguém votou positivamente, a publicação exibe 2 TabCoins, mas está numa posição do rank como se tivesse 11 TabCoins.
  • Alguém votou negativamente, a publicação exibe 2 TabCoins, e volta para a posição do rank como se tivesse 10 TabCoins.

É assim que você pensou?

É por aí.

E no hover, exibiria que tipo de detalhes sobre os votos? +1 | -1 ou também exibiria a quantidade de TabCash de impulsionamento (no exemplo acima, 10)?

Para as publicidades, acho melhor não mostrar a quantidade de votos negativos. Uma opção seria mostrar apenas a quantidade de votos positivos e o saldo de TabCash. O pior caso para uma publicidade seria chegar em 0 TabCash (quando sairá do ar) sem ter saído de 1 Tabcoin, ou seja, ela só teve votos negativos.

Na situação ideal de competição das publicidades, em que haja algumas mais bem recebidas do que outras, esse pior caso nunca deveria ser atingido, já que o alcance seria bem reduzido antes de chegar nesse poço, dando a oportunidade do autor rever sua estratégia.

Será que quem vota em anúncios deveria ganhar TabCash? ... Continuo achando que votos em anúncios não devem consumir TabCoins, pois isso restringe menos os usuários que podem votar, e não compete com as qualificações dos conteúdos. É importante incentivar mais os votos em anúncios, pois enquanto não estivermos computando as visualizações, o alcance será medido/cobrado (TabCash) pelas qualificações.

Enxergo dois problemas em dar TabCash e não cobrar TabCoins:

  1. Isso incentivará o usuário a votar em todos os anúncios, mesmo sem prestar atenção, apenas para ganhar 1 TabCash.
  2. Isso pode desequilibrar o sistema, de forma que alguém que nunca fez uma publicação consiga acumular TabCash até conseguir fazer uma publicação patrocinada.

Acho que precisamos exigir algum saldo de TabCoins (talvez 2) para poder qualificar as publicidades, mesmo que não consuma o saldo. Mas também serão necessárias outras medidas contra abuso, que só saberemos ao certo quando eles começarem a ocorrer.

Acho positivo limitar a um voto por usuário, mas continuamos com os problemas acima. Lembrando o issue #352, o fluxo completo imaginado na época era:

  1. Você gera TabCoins através de conteúdos com valor concreto.
  2. Depois gasta essas TabCoins qualificando outros conteúdos, e com isso gerando TabCash.
  3. Depois gasta esses TabCash em anúncios (e no futuro outras coisas, como features, ou qualquer outra coisa massa que conseguirmos inventar).

O fluxo pensado incialmente é uma idealização, é a base que estamos evoluindo para chegar em algo real e viável. Quanto mais evoluirmos, mais coisas diferentes teremos que lidar. Não aparecia na ideia original a necessidade de incentivar a qualificação de publicidades, assim como não era visível que precisamos de uma quantidade muito maior de qualificações do que de criação de conteúdos.

Se formos deixar sem custo de TabCoins para votar, acredito que a pessoa deva ter algum tipo de reputação (digamos, uma quantidade mínima de TabCoins ou TabCash), mas talvez isso limite ainda mais a quantidade de pessoas que podem interagir do que se mantivéssemos a cobrança de 2 TabCoins. Podemos considerar cobrar 1 TabCoin. O que acha de tudo o que mencionei aqui? Te fez pensar em algo diferente?

Quanto mais ideias para estudarmos, melhor.

Uma outra ideia é o usuário votante ganhar 1 TabCoin (e não TabCash), assim ele ainda precisará participar pelo menos da qualificação dos demais conteúdos antes de ganhar TabCash.

Rafatcb commented 4 months ago

Chegou a pensar em armazenar os comentários das patrocinadas na tabela de conteúdos normais? Isso pode exigir alguma mudança na tabela.

Não havia pensado nesse ponto. Creio que as publicações patrocinadas devam receber comentários sim. Uma possível diferença desses comentários para os realizados em "publicações normais" é que talvez eles não devessem entrar no cálculo de "prestígio" do usuário, já que ficarão visíveis por menos tempo. Faz sentido? Se formos considerar no cálculo de prestígio, suspeito que não teríamos problemas em armazenar na tabela contents.

A pesquisa seria para responder qual dúvida?

Foi só um exemplo de situação que o próprio autor gostaria de investir o TabCash sem colocar um link numa publicação patrocinada. Podemos deixar o link opcional.

Acho que precisamos exigir algum saldo de TabCoins (talvez 2) para poder qualificar as publicidades, mesmo que não consuma o saldo. Mas também serão necessárias outras medidas contra abuso, que só saberemos ao certo quando eles começarem a ocorrer.

Sim, podemos começar de um jeito simples e acompanhar as interações.

aprendendofelipe commented 4 months ago

Chegou a pensar em armazenar os comentários das patrocinadas na tabela de conteúdos normais? Isso pode exigir alguma mudança na tabela.

Não havia pensado nesse ponto. Creio que as publicações patrocinadas devam receber comentários sim. Uma possível diferença desses comentários para os realizados em "publicações normais" é que talvez eles não devessem entrar no cálculo de "prestígio" do usuário, já que ficarão visíveis por menos tempo. Faz sentido? Se formos considerar no cálculo de prestígio, suspeito que não teríamos problemas em armazenar na tabela contents.

Independente desses comentários contarem ou não para o "prestígio", não é só isso que exigiria adaptar a tabela contents, mas também o fato de que parent_id e path podem passar a conter ids que nem sempre serão de outros itens de contens. Isso pode tornar mais complexas as consultas das diferentes listas de conteúdos.

Acho que vai compensar criar uma tabela só para os comentários das publicidades. Uma vantagem de deixar para criar a tabela separada é que dá para isolar bem a implementação dos comentários nas publicidades, assim como as publicidades em si já estarão bem isoladas dos conteúdos normais.

Rafatcb commented 4 months ago

@aprendendofelipe as publicações patrocinadas aparecerão entre as normais, então acredito que o GET /api/v1/contents deva retornar elas em todas as estratégias (ou seja, mesmo ao listar por "Recentes" e em GET /api/v1/contents/rss). Concorda?

Continuando o raciocínio, os seguintes endpoints devem também funcionar para uma publicação patrocinada, visando facilitar a compatibilidade dos aplicativos e interfaces existentes hoje?

Ou acredita que essas funcionalidades devem funcionar para publicações patrocinadas apenas em /api/v1/sponsored_contents/...? Minha opinião é de que essa compatibilidade é um ponto positivo, mesmo precisando de um tratamento no lado do servidor para verificar se o conteúdo [username]/[slug] é uma publicação patrocinada ou uma publicação comum.

Como a publicação patrocinada tem alguns dados específicos que podem ser alterados, como por exemplo até quando ela será exibida, podemos ter a rota PATCH /api/v1/sponsored_contents/[username]/[slug] mesmo se aceitarmos atualizações de título, corpo e fonte pelo PATCH /api/v1/contents/[username]/[slug]. Edit: se formos criar apenas os status active e deactivated como mencionei em outro comentário, podemos tratar a atualização para deleted, ou acha melhor criar um terceiro tipo para deleted? E o published é motivo de preocupação aqui?

No caso de criação da publicação patrocinada, imagino que a rota mais adequada seja POST /api/v1/sponsored_contents por causa dos campos necessários que não existem numa publicação normal, por isso não mencionei na lista acima.


Edit: Existe algum motivo para ter originator_type nas tabelas de saldo? Estava avaliando para ver o que a tabela sponsored_content_tabcoin_operations precisará, mas me parece que o originator_type sempre é event (a não ser em algumas funções de teste, que fica orchestrator).

Edit 2: Me parece que, mesmo criando uma tabela para os comentários de publicações patrocinadas, podemos usar a tabela content_tabcoin_operations para armazenar os saldos deles. Faz sentido?

aprendendofelipe commented 4 months ago

@aprendendofelipe as publicações patrocinadas aparecerão entre as normais, então acredito que o GET /api/v1/contents deva retornar elas em todas as estratégias (ou seja, mesmo ao listar por "Recentes" e em GET /api/v1/contents/rss). Concorda?

Quando rascunhei a ideia, pensava em devolver as patrocinadas no meio dos conteúdos "normais" também pela API. Pensei isso justamente para dificultar o bloqueio das promovidas.

Agora que a ideia tomou o caminho de as promovidas serem um pouco diferentes das normais (CTA ao invés de fonte), e por querer deixar claro que são promovidas, isso vai exigir adaptar as interfaces dos Apps, então não deve ser interessante retornar elas no mesmo endpoint (pelo menos não como default).

Por isso, para as primeiras versões, eu não acho necessário se preocupar em como devolver as patrocinadas em forma de lista pela API (e nem no feed RSS). Elas podem começar aparecendo apenas na home (relevantes), e depois vemos como posicionar nas outras interfaces.

Aproveitando que meu usuário foi marcado... Para não afastar ninguém do debate, vamos tentar evitar marcar usuários específicos nos pedidos de ideias e opiniões. 🤝

Continuando o raciocínio, os seguintes endpoints devem também funcionar para uma publicação patrocinada, visando facilitar a compatibilidade dos aplicativos e interfaces existentes hoje?

  • GET /api/v1/contents/[username]/[slug]
  • PATCH /api/v1/contents/[username]/[slug]
  • POST /api/v1/contents/[username]/[slug]: apenas para criação de comentários (falo sobre criação da publicação em outro parágrafo). Também tem a ver com a compatibilidade com UIs existentes, e o dado de um comentário numa publicação patrocinada é o mesmo de uma publicação normal (o corpo).

Quis dizer POST /api/v1/contents, certo? Ou está pensando em adicionar essa forma de criar comentários?

  • GET /api/v1/contents/[username]/[slug]/children
  • GET /api/v1/contents/[username]/[slug]/parent
  • GET /api/v1/contents/[username]/[slug]/root
  • GET /api/v1/contents/[username]/[slug]/thumbnail
  • POST /api/v1/contents/[username]/[slug]/tabcoins

Ou acredita que essas funcionalidades devem funcionar para publicações patrocinadas apenas em /api/v1/sponsored_contents/...? Minha opinião é de que essa compatibilidade é um ponto positivo, mesmo precisando de um tratamento no lado do servidor para verificar se o conteúdo [username]/[slug] é uma publicação patrocinada ou uma publicação comum.

Vai facilitar bastante se pudermos usar os mesmos endpoints, mas um problema é ter de fazer verificações extras em todos os GETs, mas também nos POSTs/PATCHs, já que não poderíamos permitir a criação de uma publicação normal e outra patrocinada do mesmo usuário/slug. Hoje usamos o erro UNIQUE_CONSTRAINT_VIOLATION do banco (UNIQUE ("owner_id", "slug")), mas isso não seria mais suficiente, já que estariam em tabelas diferentes.

Será que então compensa deixar os conteúdos patrocinados na mesma tabela? Talvez criar um status sponsored e criar outra tabela com os demais campos específicos dos patrocinados?

Existe algum motivo para ter originator_type nas tabelas de saldo? Estava avaliando para ver o que a tabela sponsored_content_tabcoin_operations precisará, mas me parece que o originator_type sempre é event (a não ser em algumas funções de teste, que fica orchestrator).

Não sei se essa coluna foi criada pensando em algo que acabou não sendo implementado. Não parece necessária nem para os testes.

Me parece que, mesmo criando uma tabela para os comentários de publicações patrocinadas, podemos usar a tabela content_tabcoin_operations para armazenar os saldos deles. Faz sentido?

Dependendo até podemos, mas não sei se faz sentido.

Rafatcb commented 4 months ago

Para não afastar ninguém do debate, vamos tentar evitar marcar usuários específicos nos pedidos de ideias e opiniões. 🤝

Certo.

Agora que a ideia tomou o caminho de as promovidas serem um pouco diferentes das normais (CTA ao invés de fonte), e por querer deixar claro que são promovidas, isso vai exigir adaptar as interfaces dos Apps, então não deve ser interessante retornar elas no mesmo endpoint (pelo menos não como default).

Entendo que o ideal é ressaltar quando a publicação é patrocinada e quando não é, mas tenho a impressão que não retornar as publicações patrocinadas por padrão, juntos dos conteúdos, faz com que os consumidores das APIs precisem "aprender" que "devem exibir as publicações patrocinadas".

Quis dizer POST /api/v1/contents, certo? Ou está pensando em adicionar essa forma de criar comentários?

Sim, acabei me confundindo enquanto editava a lista.

(...) já que não poderíamos permitir a criação de uma publicação normal e outra patrocinada do mesmo usuário/slug (...)

Será que então compensa deixar os conteúdos patrocinados na mesma tabela? Talvez criar um status sponsored e criar outra tabela com os demais campos específicos dos patrocinados?

Pensei sobre isso também. Uma solução que encontrei para continuar mantendo em duas tabelas separadas é ter uma VIEW que consolida ambas, algo similar ao proposto nessa resposta do Stack Overflow. Não fui mais a fundo para ver o quão viável isso é ou se faz sentido no nosso caso.

Acredito que ter um status sponsored pode ser uma boa alternativa, e permitiria manter os comentários de publicações patrocinadas na mesma tabela (contents), certo?

Me parece que, mesmo criando uma tabela para os comentários de publicações patrocinadas, podemos usar a tabela content_tabcoin_operations para armazenar os saldos deles. Faz sentido?

Dependendo até podemos, mas não sei se faz sentido.

Mas como você pensa que faz sentido? Manter três tabelas de "tabcoins" separadas (conteúdos normais, publicações patrocinadas e comentários em publicações patrocinadas) ou duas, uma para os conteúdos normais e outra para as publicações patrocinadas e seus comentários? Ou ainda uma outra opção que não pensei?

E, se os comentários de publicações patrocinadas ficarem em contents com status que já temos hoje, complicará identificar qual função deve ser chamada para calcular o saldo de TabCoins e os créditos e débitos.

Na minha cabeça, os comentários de publicações patrocinadas me parecem "a mesma coisa" de comentários de publicações comuns. Não sei se você pensou em comportamentos diferentes.

Rafatcb commented 3 months ago

Criei o PR #1719 com a implementação da API. Algumas partes da implementação ficaram diferentes do que foi discutido, como o fato de eu não ter criado uma tabela para os comentários de publicações patrocinadas, já que do meu ponto de vista, não teria nada para armazenar lá ou dificultaria a implementação sem um benefício que eu tenha visualizado. De toda forma, com a implementação fica mais fácil de identificar os pontos a serem melhorados.

Quem quiser, pode revisar o PR, mesmo que parcialmente, visto que ele ficou grande.

filipedeschamps commented 2 months ago

Turma, eu reservei a tarde de hoje para ler tanto essa issue, quanto o PR original em #1719 e depois o PR fatiado em #1739.

Considerando que esta issue foi aberta em Agosto de 2023, mesmo com os avanços dos últimos PRs do @Rafatcb, estamos com um ratio entre ideias e código em produção bastante longe do que considero um desenvolvimento orgânico (me inspirando na aula Programação "Orgânica" versus "Impressora 3D").

Dado a isso, gostaria de pedir a permissão de vocês para dar uma sugestão completamente contrastada do que foi discutido e implementado até então. Na verdade "completamente contrastada" não, pois é apenas uma ideia para iniciar uma jornada que ficará bem mais complexa ao longo do desenvolvimento e naturalmente acabar tendo overlap com tudo que foi discutido. De qualquer forma, é daquelas ideias onde o trajeto é maior, mas o tempo é menor, sabe? É super contraintuitivo, mas peço a permissão e confiança assim como escrevi nesta publicação na wiki (2022), neste trecho em específico (mais para o final, deixei em negrito):

Gostaria de ser o Guia, e não o Mentor (52:15) - Peço a permissão para, ao invés de no projeto eu ser um Mentor, eu ser um Guia. A diferença é que um Mentor fica afastado e você vai até a ele para se consultar. Já um Guia está junto com você, junto na trilha, enfrentando e vivenciando o que der e vier ao longo da trajetória. Se aparecer um Leão na trilha, eu quero estar lá junto, e sinceramente, eu quero que apareça um Leão (por exemplo o site cair), pois isso vai ser uma ótima oportunidade para nos juntarmos numa Live, investigar o que aconteceu e trocar muita experiência e conhecimento. E a permissão que eu peço é de ser o Guia mais chato que vai existir, para manter a gente na trilha da simplicidade para conseguirmos causar um contraste na área que estamos entrando (portal de notícias e conteúdos).

Sugiro ver o trecho da Live ali, ela está unlisted.

Isso se conecta com este outro trecho (também destaque em negrito):

Relação entre Desenvolver Pouco e Aprender Muito (59:32) - Conectado com o item anterior, de fazer coisas simples, eu proponho a gente sair um pouco da velocidade de desenvolvimento que é esperada quando você está trabalhando em um ambiente corporativo. Para esse projeto, para quem está vivenciado isso em tempo-real, eu sugiro a gente desenvolver pouco, e como consequência aprender muito.

Dado a isso, peço permissão para dar minha ideia sendo de novo o "Guia mais chato que vai existir", e mesmo que ela pareça errada e que nos causará problemas atuais e futuros (o que irá), peço confiança para seguir com ela 🤝

Rafatcb commented 2 months ago

Bom, ninguém precisa pedir permissão para dar uma ideia/sugestão aqui :sweat_smile:

Pode continuar, @filipedeschamps .

filipedeschamps commented 2 months ago

Show 😍 Então a ideia é uma estratégia para atingir duas coisas:

  1. Primeiro tirar o peso das costas dessa issue. Isso acontecia muito no Pagar.me, tem muita coisa em cima dela e isso dificulta muito o avanço.
  2. Segundo, e talvez o mais importante, fazer a feature financiar o seu próprio desenvolvimento. Então eu vou elaborar uma pequena sequência de passos para atingir isso de uma forma mais rápida.

Mas já adianto que será angustiante passar por esse caminho, por isso peço a confiança para executar ele. E eu irei escrever agora apenas o primeiro passo que, depois de executado, vamos conectar ele com o próximo passo.

Então o primeiro passo é: adicionar um novo campo type na modelagem de Content onde por padrão este valor é content. Este campo é uma string que poderá receber os seguintes valores: content, ad e pitch.

E pronto, mais nada. Com isso em produção, vou descrever o próximo passo 🤝

filipedeschamps commented 2 months ago

Com o deploy do PR #1740 vamos para o segundo passo que é:

Habilitar que seja possível passar para o POST /api/v1/contents o parâmetro type e no momento em que um usuário criar um conteúdo enviando type: ad, debitar 100 TabCash da conta dele.

Depois disso, o terceiro passo já irá financiar o desenvolvimento do restante da feature 🤝

filipedeschamps commented 2 months ago

Que massa!!! To MUITO feliz com o avanço da feature 😍 Então com o deploy do PR #1742 vamos para o terceiro passo que é um pouco mais longo, mas que já vai servir para financiar o restante da feature (que ainda ficará incompleta, então teremos novos passos para fazer mais sentido, natural):

  1. Atualizar a interface da criação de conteúdo para escolher o type do content (Conteúdo, Pitch e Anúncio), onde por padrão, o valor é Conteúdo.
  2. Nas seções Relevantes ou Recentes, apenas retonar contents do type content ou pitch. Da mesma forma, ser possível retornar contents que tenham apenas o type ad. Colocar isso como filtro no endpoint GET /api/v1/contents?
  3. Criar uma seção nova no menu principal chamada de Classificados e apenas listar os contents que for do type ad. Eles podem ser ordenados inicialmente por data de criação, mas no quarto passo vou sugerir ordenar por outra coisa.
  4. Abrir um espaço na Home e Recentes, onde randomicamente pega um content de type ad que esteja published e mostra o title e o username na qual este ad está beneficiando. O click no title levar o usuário diretamente para o source_url do content e por conta disso, precisamos mostrar o pedaço inicial da URL, como no exemplo da imagem abaixo o (curso.dev). O clique no username deveria ir para a página de perfil dele. [edit] É importante este espaço respeitar as regras principais de texto da lista de conteúdo abaixo.
image

Opcional

Esta é uma implementação opcional, mas irá facilitar o quarto passo e evitar da gente ter que marretar dados no banco de dados depois:

  1. Ao criar um content com type ad, fazer o credit de 100 tabcash no content que foi criado. Isso é possível depois da refatoração das tabelas de balance?
aprendendofelipe commented 2 months ago
  1. Atualizar a interface da criação de conteúdo para escolher o type do content (Conteúdo, Pitch e Anúncio), onde por padrão, o valor é Conteúdo.

Legal, então no backend ainda precisamos liberar a criação com o tipo pitch.


  1. Nas seções Relevantes ou Recentes, apenas retonar contents do type content ou pitch. Da mesma forma, ser possível retornar contents que tenham apenas o type ad. Colocar isso como filtro no endpoint GET /api/v1/contents?

Para evitarmos uma quase certa breaking change em /contents, sugiro devolver em um endpoint específico de anúncios. Além de ser mais fácil de implementar o controller separado.


  1. Criar uma seção nova no menu principal chamada de Classificados e apenas listar os contents que for do type ad. Eles podem ser ordenados inicialmente por data de criação, mas no quarto passo vou sugerir ordenar por outra coisa.

Acabei de reservar a palavra classificados para o novo caminho. 👍

Para adicionar "Classificados" no menu principal precisamos remodelar a versão de tela pequena do header, pois não cabe mais nada sem fazer ele quebrar. Vamos adotar como na imagem abaixo, que foi estudado no PR #1279?

Header Mobile
  1. Abrir um espaço na Home e Recentes, onde randomicamente pega um content de type ad que esteja published e mostra o title e o username na qual este ad está beneficiando. O click no title levar o usuário diretamente para o source_url do content e por conta disso, precisamos mostrar o pedaço inicial da URL...

Isso ficou um pouco estranho. O conteúdo markdown desse ad só será acessível indo em classificados e procurando pelo anúncio? Ou lá também ao clicar no título o usuário será levado diretamente para o source_url?

Está me parecendo uma mistura de dois tipos de anúncios diferentes que podemos ter, com e sem markdown, mas se o anunciante optou por adicionar markdown, clicar no link deveria levar para ele. Ou não?

Chegou a ver essa imagem abaixo e as outras relacionadas? No exemplo, apenas a segunda é uma patrocinada.

Conteúdo patrocinado

Opcional

Esta é uma implementação opcional, mas irá facilitar o quarto passo e evitar da gente ter que marretar dados no banco de dados depois:

  1. Ao criar um content com type ad, fazer o credit de 100 tabcash no content que foi criado. Isso é possível depois da refatoração das tabelas de balance?

Esse seria provavelmente o próximo passo após o PR #1739. Criar a tabela de TabCash dos anúncios. 👍

filipedeschamps commented 2 months ago

Legal, então no backend ainda precisamos liberar a criação com o tipo pitch.

Vamos então por hora só mostrar Conteúdo e Anúncios, até porque, a ideia é mostrar o Pitch separado no menu também, mas eu não traria para o passo 3 essa complexidade. Então apesar do estudo feito em #1279 foi ótimo, novamente, não faria para o passo 3 (o que não tem problema, não vamos parar a feature aqui).

Para evitarmos uma quase certa breaking change em /contents, sugiro devolver em um endpoint específico de anúncios. Além de ser mais fácil de implementar o controller separado.

Tem certeza que seria uma breaking change? Seria um filtro na query string. De qualquer forma, não é nem preciso ter um menu Classificados agora, seria só interessante duas coisas: não deixar os anúncios vazarem nas listas de conteúdo e ter alguma forma do usuário conseguir editar o conteúdo do anúncio (então ele teria que ter a lista deles em algum lugar). Se eu não me engano, o @Rafatcb tinha desenhado uma aba em que listava os anúncios do usuário, não me recordo tecnicamente qual seria a abordagem. Queria reaproveitar o máximo que desse tudo que temos de content para ser mais fácil. Então apenas no passo 3, na tela de perfil do usuário, pode até listar os anúncios lá... vai ser temporário.

Isso ficou um pouco estranho. O conteúdo markdown desse ad só será acessível indo em classificados e procurando pelo anúncio?

Correto 🤝 Nas posições mais prestigiadas (por exemplo a do print que enviei), vamos mirar para uma alta conversão, então o clique precisa ir direto para o anunciante.

Ou lá também ao clicar no título o usuário será levado diretamente para o source_url?

O clique em algum item da lista deverá ter o mesmo comportamento da lista de conteúdos, então irá levar o usuário para o conteúdo em markdown e a aba Classificados irá servir mais para consulta/curiosidade/SEO. No quarto passo ela poderá talvez ter uma participação melhor no retorno ao anunciante, mas duvido que qualquer coisa que seja feita nessa aba chegue perto da conversão das posições mais prestigiadas que levem o clique direto para o anunciante, então prioridade baixa para essa aba no momento se tecnicamente é complicado filtrar os dados para ela.

Está me parecendo uma mistura de dois tipos de anúncios diferentes que podemos ter, com e sem markdown, mas se o anunciante optou por adicionar markdown, clicar no link deveria levar para ele. Ou não?

Por hora, como tudo é um content, precisa sempre ter um body e sugiro o usuário preencher com um bom conteúdo, porque isso irá ajudar no SEO (considerando que a aba Classificados fique exposta ou o crawler do Google encontre o conteúdo de alguma forma, como na página de perfil do usuário). De qualquer forma, o anúncio em posições mais prestigiadas, levar o clique para esse conteúdo atrapalha o retorno em comparação ao clique direto, pois justamente se adiciona mais um clique/ação.

Chegou a ver essa imagem abaixo e as outras relacionadas? No exemplo, apenas a segunda é uma patrocinada.

Eu vi! Gostei bastante 🤝 Ao mesmo tempo, morro de medo da credibilidade da lista ficar deturpada por influência ou ruído causado por anúncios (que é o que está acontecendo com a busca do Google). Então sugiro que o primeiro passo seja separar o que é conteúdo de anúncio. Mas mais para frente podemos e devemos testar outros modelos para entender o que funciona melhor no ecossistema, incluindo esse da sugestão. Acredito que o combo title+link consegue ser encaixado em vários lugares 🤝

aprendendofelipe commented 2 months ago

Massa, o que realmente importa já é ponto pacífico! 🎉

E dado que já é possível criar as patrocinadas pela API, e editar elas tanto pela API como pela versão web, acho que agora só falta um pequeno passo para a Revenue Share se tornar realidade para quem souber usar a API.

Temos estas sub-fases, que podem ser PRs separados, mas que o primeiro já revoluciona ao exibir as primeiras patrocinadas (uma especie de versão beta criando só pela API):

Os demais passos podem ser ainda na fase 3, mas acredito que saber o que vem na fase 4 vai ajudar.


No item 3a, caso a patrocinada não possua source_url, então direcionar para /[username]/[slug]. Não só por isso, mas também abre uma possibilidade para quem realmente quiser mostrar primeiro o markdown, por qualquer motivo que seja.

No item 3b, acho que pode aproveitar este outro estudo:

Conteúdo Patrocinado

Para evitarmos uma quase certa breaking change em /contents, sugiro devolver em um endpoint específico de anúncios. Além de ser mais fácil de implementar o controller separado.

Tem certeza que seria uma breaking change? Seria um filtro na query string.

Certeza absoluta, não. Mas é mais fácil adicionar futuramente o filtro, se alguma necessidade surgir, do que o caminho contrário.

Alterar o /api/v1/contents não é requisito para nenhum dos passos acima, mas criar um /api/v1/sponsored_contents é muito similar ao que será feito na UI no passo 3c, então opcionalmente pode ser feito junto.

Se adicionar o filtro em /contents fosse o mais simples de implementar, ou se tivesse algum outro benefício, talvez valesse o risco, mas não acredito que seja o caso.

Já a edição das publicidades está funcionando pelo /api/v1/contents/[username]/[slug].

Ainda sobre a edição dos anúncios... Por enquanto a única diferença com relação aos demais conteúdos é que não existe o crédito e débito de TabCoins do usuário no PATCH para published ou deleted. Mas é possível editar normalmente o título, o corpo e a URL. Só não é possível alterar o tipo de conteúdo, e acho que faz sentido manter assim, pelo menos por enquanto, certo?

Acho que a única ponta solta é que, se for criado o conteúdo com o tipo ad, mas com status draft, o TabCash será debitado já na criação. Precisa debitar já na criação porque não seria debitado TabCash ao editar de draft para published. Ninguém usa o draft, então não tinha porque lidar com isso agora.

...a aba Classificados irá servir mais para consulta/curiosidade/SEO.

Sobre SEO, acho que é uma ideia ruim deixar os anúncios serem indexados. É um ponto que vai precisar ser melhor analisado, mas já me preocupa que pode não ser fácil reverter uma provável queda na nossa relevância e nas indicações do Discover.


No quarto passo ela poderá talvez ter uma participação melhor no retorno ao anunciante, mas duvido que qualquer coisa que seja feita nessa aba chegue perto da conversão das posições mais prestigiadas que levem o clique direto para o anunciante, então prioridade baixa para essa aba no momento se tecnicamente é complicado filtrar os dados para ela.

Zero complicação filtrar os dados. A preocupação não é técnica 😅


Está me parecendo uma mistura de dois tipos de anúncios diferentes que podemos ter, com e sem markdown, mas se o anunciante optou por adicionar markdown, clicar no link deveria levar para ele. Ou não?

Por hora, como tudo é um content, precisa sempre ter um body e sugiro o usuário preencher com um bom conteúdo, porque isso irá ajudar no SEO (considerando que a aba Classificados fique exposta ou o crawler do Google encontre o conteúdo de alguma forma, como na página de perfil do usuário).

Precisamos manter um bom SEO para trazer visitantes para o TabNews, e mais visitantes no TabNews implica em mais visitantes para os anúncios.

Por isso a indexação deveria ser apenas dos "melhores" conteúdos.

Se trabalhar com foco em trazer visitantes diretamente para os anúncios, logo nossa relevância acaba. Não podemos esquecer que a maioria dos visitantes diários vem pelo Google.


De qualquer forma, o anúncio em posições mais prestigiadas, levar o clique para esse conteúdo atrapalha o retorno em comparação ao clique direto, pois justamente se adiciona mais um clique/ação.

Concordo totalmente. Por isso penso no conteúdo patrocinado apenas como o primeiro experimento dos anúncios. Mas ele seria apenas a alternativa para quem realmente quer impulsionar a divulgação de algo no próprio TabNews.

Pra quem possui uma landing page, as outras formas de anúncio que teremos serão melhores.


Chegou a ver essa imagem abaixo e as outras relacionadas? No exemplo, apenas a segunda é uma patrocinada.

Eu vi! Gostei bastante 🤝 Ao mesmo tempo, morro de medo da credibilidade da lista ficar deturpada por influência ou ruído causado por anúncios (que é o que está acontecendo com a busca do Google). Então sugiro que o primeiro passo seja separar o que é conteúdo de anúncio. Mas mais para frente podemos e devemos testar outros modelos para entender o que funciona melhor no ecossistema, incluindo esse da sugestão. Acredito que o combo title+link consegue ser encaixado em vários lugares 🤝

Também acredito que o combo title+link, ou um banner, tenham retornos melhores para os anunciantes. Posso ter cometido um erro ao sugerir começarmos pelas publicações patrocinadas, pois alguma facilidade que ganhamos pelo que existe em comum entre conteúdos e patrocinadas pode não ter compensado a confusão criada entre essas coisas tão diferentes 😖

filipedeschamps commented 2 months ago

E dado que já é possível criar as patrocinadas pela API, e editar elas tanto pela API como pela versão web, acho que agora só falta um pequeno passo para a Revenue Share se tornar realidade para quem souber usar a API.

Total 🎉 🎉 🎉

Temos estas sub-fases, que podem ser PRs separados

Topo total fazer PR separados e ótima separação em todos os 3x 🤝

Os demais passos podem ser ainda na fase 3, mas acredito que saber o que vem na fase 4 vai ajudar.

Justo! Sobre o f relacionada a tabela do balanço de tabcash, a ideia é na página Classificados ordenar de forma decrescente a publicação que possui uma maior quantidade de tabcash. Em paralelo a isso, devemos criar um cron na Vercel que todo dia passa por todas as publicações do tipo ad e debita uma quantidade x do saldo de tabcash da publicação, por exemplo: 10 tabcash debitados por dia, das publicações que possuem um saldo maior do que 1 tabcash, não podendo deixar ficar com saldo negativo naturalmente. Junto disso, ao criar uma publicação do tipo ad, o usuário pode escolher quantos tabcash quer usar do seu saldo, caso queira alterar o padrão de 100.

Isto irá fazer a página Classificados mostrar os anúncios que os usuários estão investindo mais tabcash.

Depois disso tudo, não sei se no passo 4 ainda, poderíamos usar essa mesma mecânica para calcular a probabilidade de aparecer um anúncio, sendo que os anúncios com maior saldo de tabcash teriam uma chance maior de aparecer.

No item 3a, caso a patrocinada não possua source_url, então direcionar para /[username]/[slug]. Não só por isso, mas também abre uma possibilidade para quem realmente quiser mostrar primeiro o markdown, por qualquer motivo que seja.

Excelente ponto! Concordo 100%. Daí nesse caso teria que tirar o ícone de link externo e o preview do source_url.

Alterar o /api/v1/contents não é requisito para nenhum dos passos acima, mas criar um /api/v1/sponsored_contents é muito similar ao que será feito na UI no passo 3c, então opcionalmente pode ser feito junto.

Se adicionar o filtro em /contents fosse o mais simples de implementar, ou se tivesse algum outro benefício, talvez valesse o risco, mas não acredito que seja o caso.

Entendo. Bom, em questão de interface e modelagem (content), faz muito mais sentido ao invés de trabalhar com algo como /api/v1/sponsored_contents trabalhar com algo /api/v1/contents?type=content,pitch e /api/v1/contents?type=ad. Para mim faz tão mais sentido, que eu pagaria esse custo agora. Pode ser outro formato também como /api/v1/contents?type=content&type=pitch (mas não sei como isso entra no Next.js)

Só não é possível alterar o tipo de conteúdo, e acho que faz sentido manter assim, pelo menos por enquanto, certo?

Certo 🤝

Sobre SEO, acho que é uma ideia ruim deixar os anúncios serem indexados. É um ponto que vai precisar ser melhor analisado, mas já me preocupa que pode não ser fácil reverter uma provável queda na nossa relevância e nas indicações do Discover.

Hmm bom ponto, não tinha pensado por esse lado.

aprendendofelipe commented 2 months ago

Avisando aqui apenas para evitar trabalho redundante...

Estou fazendo uma parte da 3a, responsável por devolver uma quantidade escolhida de publicidades aleatórias.

Daí nas páginas estáticas relevantes e recentes só precisa fazer um ad.getRandom(1) para obter os anúncios. Pode até buscar uma quantidade maior, dependendo de como for ficar a UI. Não estou trabalhando na UI.

Vou criar o /sponsored-beta apenas para poder criar testes para o novo model. Não vale a pena colocar isso no /contents, pois a ideia é o model servir para anúncios, não necessariamente os que se parecem com conteúdos, além do /contents já ser estável e precisamos de uma liberdade maior para estudar o que um GET anúncios precisa devolver.

Rafatcb commented 1 month ago

A página Classificados também deve ter um banner no topo? Notei agora que é a única em "Recentes" que não tem o anúncio destacado.

aprendendofelipe commented 1 month ago

Pelo menos por enquanto que não temos quase anúncios publicados, acho melhor não... Pois será garantido o anúncio aparecer duas vezes

filipedeschamps commented 1 month ago

O passo 3 foi concluído ontem de noite com o merge dos seguintes PRs:


E apesar de que passou pouco tempo, eu considero que o passo 3 foi concluído com sucesso por conta da primeira publicação como anúncio: https://www.tabnews.com.br/filipericardo/agora-e-possivel-usar-seus-tabchash

image

Esta publicação foi extremamente bem aceita e dá até pena de criar um outro anúncio, porque ela está servindo perfeitamente para divulgar a existência dessa nova feature 😅

Bom, agora vamos deixar maturar e aprender o que irá acontecer daqui para frente para dar o passo 4. Parabéns @aprendendofelipe e @Rafatcb pelo envolvimento, ficou excelente e só vai melhorar 🤝

Rafatcb commented 3 weeks ago

Me parece que usar noindex nas publicações de anúncio e buscar o anúncio pela API ao invés de buscar no getStaticProps seriam boas melhorias. O motivo é que a indexação acabou piorando a busca no TabNews, caso eu queira procurar por algo que esteja presente em um título de anúncio.

No exemplo abaixo, estou buscando exatamente pelo título de um anúncio, apenas para deixar claro o problema.

Busca por um título de anúncio retorna diversos resultados.

A busca no Google não ficou tão ruim nesse exemplo, só trouxe dois resultados, mas na parte de imagens, trouxe vários. Outros exemplos ficam bem pior:

Busca: site:tabnews.com.br "testes-next-analytics.vercel.app"

10 páginas de resultados

aprendendofelipe commented 3 weeks ago

Me parece que usar noindex nas publicações de anúncio e buscar o anúncio pela API ao invés de buscar no getStaticProps seriam boas melhorias.

Considero que são melhorias sim. Até já tinha comentado sobre as duas.

Sobre não indexar os anúncios, comentei nessa issue mesmo:

Sobre SEO, acho que é uma ideia ruim deixar os anúncios serem indexados

Já a parte da API, acho que será obrigatória essa mudança, pois logo não estaremos revalidando as páginas que não tiverem recebido nenhuma atualização, então elas ficariam com um anúncio fixo se ele estiver presente na página estática.

Não lembro em qual PR falei sobre isso, mas lembro que citei que precisamos evitar o layout shift que pode ocorrer nessa abordagem.

Rafatcb commented 3 weeks ago

Considero que são melhorias sim. Até já tinha comentado sobre as duas.

Sim, eu quis reforçar/relembrar, já que isso me atrapalhou hoje hehe.

Não lembro em qual PR falei sobre isso, mas lembro que citei que precisamos evitar o layout shift que pode ocorrer nessa abordagem.

Estou trabalhando no loading do #1778 com a biblioteca que você citou, react-content-loader. Usar esse tipo de skeleton loading pode ajudar a não ter o deslocamento após o carregamento, ou ter um deslocamento menor.

aprendendofelipe commented 3 weeks ago

Estou trabalhando no loading do #1778 com a biblioteca que você citou, react-content-loader. Usar esse tipo de skeleton loading pode ajudar a não ter o deslocamento após o carregamento, ou ter um deslocamento menor.

Boa! Pode se inspirar em como é usado em https://github.com/filipedeschamps/curso.dev