Design por História (Design by Story)
Construa um protótipo HTML de arquivo único de um produto, visualizável em vários dispositivos, e dividido por história de usuário da mesma forma que é dividido por dispositivo.
A barra superior tem dois seletores:
- Dispositivo: ex. Site · Android · iPhone. Mesmo produto, moldura diferente.
- História: "Todas as histórias" mais uma entrada por história de usuário. Selecionar uma história redefine os dados compartilhados para os dados iniciais daquela história, envia cada dispositivo para a tela inicial da história e abre um painel com a história, prioridade, status, critérios de aceitação, roteiro de demonstração e anotações.
Ambas as seleções residem no hash da URL (#historia=S2&dispositivo=iphone), para que um link para uma história em um dispositivo possa ser colado em uma revisão ou ticket.
Fluxo de Trabalho
-
Coletar entradas (pergunte apenas o que está faltando, em uma única mensagem):
- O que é o produto e quem o utiliza.
- Quais dispositivos mostrar. Padrão: Site + Android + iPhone. Tablet se for uso em campo/quiosque.
- As histórias de usuário, de qualquer forma (uma lista, uma exportação de backlog, documentos de funcionalidades).
- Formato do AC: Dado/Quando/Então, ou regras simples? Padrão para Dado/Quando/Então.
- Prioridade (MoSCoW) e status, se eles tiverem. Caso contrário, padrão para
should/draft. - O modelo de dados principal (registro principal + campos-chave), ou inferir a partir das histórias.
Normalize cada história para o formato de história. Se o usuário não tiver histórias, elabore 3–6 a partir da descrição do produto e confirme-as antes de construir.
-
Verificar as histórias de acordo com a lista de verificação de qualidade. Levante os problemas em uma lista curta. Não reescreva silenciosamente as palavras do usuário.
-
Planejar telas por história. Para cada história, liste as telas que ela toca em cada dispositivo e os dados iniciais necessários. Uma história pula um dispositivo apenas quando o produto realmente funciona dessa forma (ex. administrador apenas no site). Sua lista
devicesinforma isso, e o seletor desabilita os outros dispositivos enquanto ela estiver selecionada. -
Copiar
assets/shell.htmlpara o caminho escolhido pelo usuário (padrãodocs/reference/prototype.html) e preenchê-lo. Leiareferences/prototype-spec.mdpara as regras visuais (molduras, tokens, tipografia, cartões, pills, toasts, gavetas, ícones, tom de cópia). -
Construir telas, não histórias. As telas são compartilhadas; as histórias são pontos de entrada e dados iniciais para elas. Nunca duplique uma tela por história. Se uma história precisar de uma variação, conduza-a a partir dos dados iniciais.
-
Verificar em um navegador. Use uma ferramenta de navegador se tiver uma. Caso contrário, use Chrome headless:
--dump-dom "file://…/prototype.html#historia=S2&dispositivo=iphone"para verificar o que foi renderizado,--screenshotpara visualizá-lo e--enable-logging=stderrpara capturar erros de console. Verificar se:- cada história em cada dispositivo listado abre na tela correta;
- cada AC pode ser demonstrado e o roteiro pode ser clicado;
- alternar de dispositivo no meio de uma história mantém o estado;
- nenhum controle de uma história aparece sob outra história, e "Todas as histórias" tem todos os controles de todas as histórias funcionando juntos;
- o console está limpo.
-
Manter sincronizado. Quando uma história é adicionada ou alterada posteriormente, atualize sua entrada
#story-text, sua entradaBEHAVIOURe cada dispositivo que ela lista na mesma edição.
Formato de História
Uma história vive em dois lugares no shell, ambos indexados pelo seu id:
- seu texto no bloco JSON
#story-text, exibido como somente leitura no painel da história; - seu comportamento em
BEHAVIOUR, que é apenas código.
<script type="application/json" id="story-text">
{
"S1": {
"title": "Salvar uma pesquisa",
"story": "Como visitante, posso salvar uma pesquisa, para que eu seja notificado sobre novas correspondências sem pesquisar novamente.",
"priority": "must",
"status": "draft",
"ac": [
{ "id": "S1-AC1", "text": "Dado que pesquisei por \"mesa de carvalho\", quando tocar em Salvar pesquisa, então ela aparece em Salvos" },
{ "id": "S1-AC2", "text": "Dado que essa pesquisa já está salva, quando salvá-la novamente, então Salvos ainda a mostra uma vez" }
],
"acNext": 2,
"walkthrough": ["Pesquisar por \"mesa de carvalho\"", "Tocar em Salvar pesquisa", "Abrir Salvos"],
"outOfScope": ["Alertas por e-mail"],
"assumptions": ["Os visitantes devem estar logados para salvar"],
"questions": ["Há um limite de pesquisas salvas?"]
}
}
</script>
const BEHAVIOUR = {
S1: {
devices: ['web', 'android', 'iphone'], // a quais molduras esta história se aplica
start: { web: 'search', android: 'search', iphone: 'search' }, // tela por dispositivo
features: ['save-search'], // o que esta história ativa
seed: () => ({ user: LOGGED_IN, saved: [] }), // dados frescos para esta história
},
};
| Campo | Regras |
|---|---|
story | Como <persona>, posso <ação>, para que <benefício>. O benefício é o que o usuário ganha, não uma repetição da ação. |
priority | must · should · could · won't (MoSCoW). |
status | draft · in review · agreed. |
ac | Objetos { id, text }. IDs são <história>-AC<n>, nunca renumerados, nunca reutilizados. Veja abaixo. |
acNext | O maior número de AC já emitido para esta história. Um novo AC recebe acNext + 1, e acNext é atualizado para corresponder. Atualize-o sempre que adicionar um AC. |
walkthrough | O script de demonstração que um revisor clica. Não são critérios de aceitação; mantenha-o curto. |
outOfScope, assumptions, questions | Listas simples. Deixe vazio em vez de inventar preenchimento. Registre qualquer coisa sobre a qual o usuário não tem certeza como uma pergunta. |
seed() retorna um objeto novo a cada chamada, então reselecionar uma história sempre a reinicia limpa. "Todas as histórias" usa DEFAULT_SEED e a tela inicial de cada dispositivo.
Critérios de Aceitação
- Um comportamento testável por AC, no formato escolhido pelo usuário. Dado/Quando/Então é uma linha:
Dado <contexto>, quando <ação>, então <resultado observável>. - Cópia exata: quando um AC é sobre uma mensagem, cite a mensagem (
então vejo "Nada aberto no momento."), nunca "uma mensagem amigável". - Resultados, não estilização: "ele aparece como Concluído", não "um pill verde aparece". Um detalhe visual é um AC apenas quando é o requisito.
- Testável em um dispositivo. Não escreva ACs sobre outros dispositivos ("aparece em todos os dispositivos", "apenas na web", "os telefones não podem alterá-lo"). Quais dispositivos uma história cobre pertence a
devices, e a sincronização entre dispositivos é preocupação do backend. - IDs são permanentes.
S1-AC3mantém seu ID quando editado, movido ou dividido em uma história filha, para que possa ser rastreado até testes e tickets. Novos ACs recebemacNext + 1. IDs deletados nunca são reatribuídos, e nada é renumerado.
Lista de Verificação de Qualidade
Verifique cada história antes de construí-la e novamente sempre que ela mudar:
- A persona é uma função de usuário real, e o benefício é algo que eles diriam?
- Ela entrega valor por si só (independente) e é pequena o suficiente para ser demonstrada em menos de um minuto? Se não, divida-a.
- Cada AC tem um ID, um único comportamento e um resultado observável?
- Casos vazios, de erro e de limite são cobertos ou listados em
questions? - As dependências de outras histórias estão visíveis? (Uma chave de funcionalidade compartilhada, mais uma menção em
assumptions, ex. "Baseia-se em S2".)
A funcionalidade da história está desligada até que sua história seja selecionada
Cada interação que uma história introduz recebe uma chave de funcionalidade, listada no features da história. can('save-search') é verdadeiro apenas enquanto uma história que a lista estiver selecionada.
- Renderização: envolva os controles da história em
can(...)para que eles não existam de outra forma (nenhum botão, nenhum formulário, nenhum item de menu). Não os mostre desabilitados. Os revisores devem ver apenas o que a história selecionada adiciona. - Manipuladores: inicie cada manipulador de história com
if (!can('save-search')) return;para que nada dispare fora da história, mesmo a partir de um DOM obsoleto ou do console. - "Todas as histórias" ativa todas as funcionalidades de todas as histórias de uma vez: o produto completo como está, em
DEFAULT_SEED. Verifique se as histórias não entram em conflito (ex. dois controles no mesmo local). - Uma história que depende da interação de outra história lista ambas as chaves (ex. "Filtrar por status" lista
['filter', 'complete']para que marcar uma tarefa como concluída possa ser mostrado saindo da lista filtrada). - Dados que uma história apenas exibe (ex. as iniciais de um responsável) não são controlados; apenas a capacidade de alterá-los é.
Alterando Histórias
O protótipo apenas mostra histórias; nunca as edita ou salva. Todas as alterações de história passam pelo Claude, no chat:
- Nova história: elabore a história, ACs e perguntas, execute a lista de verificação de qualidade com o usuário, depois escreva a entrada
#story-texte a entradaBEHAVIOURe construa as telas em uma única edição. Uma história nunca existe apenas como texto. Se existisse, o shell a deixaria de fora do seletor e registraria um erro no console. - História alterada (redação, ACs, prioridade, status, anotações): edite
#story-text. Se a alteração modificar o que a história faz (um novo AC, um roteiro diferente), atualize as telas eBEHAVIOURpara corresponder na mesma edição. - Feedback de revisão: quando o usuário repassar os comentários dos revisores, transforme cada um em uma das alterações acima, ou em uma entrada em
questionsse ainda estiver em aberto. - Sempre diga o que você construiu ou alterou, por história e ID do AC.
Se o usuário mantiver histórias em um rastreador (Jira ou similar), o rastreador é a cópia mestre. Espelhe sua redação aqui, em vez de editar histórias apenas no protótipo.
Dividindo uma História
Quando o usuário pedir para dividir uma história, ou uma história tiver mais de cerca de 5 ACs, mais de uma chave de funcionalidade principal, ou ACs que poderiam ser enviados separadamente, divida-a.
-
Escolha um padrão de divisão e diga qual você usou:
- etapas do fluxo de trabalho (criar → revisar → publicar)
- operações (adicionar / editar / excluir)
- caminho feliz primeiro, depois casos de borda (vazio, duplicado, limite atingido)
- por dispositivo ou função (captura por telefone vs. gerenciamento no site)
- por variação de dados (um item → muitos, uma moeda → várias)
- simples primeiro, depois extras (ordenação simples → preferências de ordenação salvas)
Cada filho ainda deve ser um
Como um… posso… para que…completo, com valor próprio. -
Numere os filhos a partir do pai:
S3→S3.1,S3.2, … Remova o pai de#story-texteBEHAVIOURe coloque os filhos em seu lugar. OreadHashdo shell envia um link antigo#historia=S3paraS3.1, para que links compartilhados continuem funcionando. -
Particione, não duplique:
- Critérios de aceitação. Cada AC pai move-se para exatamente um filho com seu ID original (
S3-AC2permaneceS3-AC2dentro deS3.1). Se um AC abranger dois filhos, reescreva-o em dois novos ACs (S3.1-AC1,S3.2-AC1) e anote qual ID pai eles substituem. - Chaves de funcionalidade. Divida uma chave se sua interação for dividida (
filter→filter-status,filter-counts). Um filho também pode listar a chave de um irmão quando se baseia nela, como na regra de dependência acima. - Dispositivos. Cada filho lista apenas os dispositivos que ele realmente toca.
- Dados iniciais. O
seed()de um filho posterior começa a partir do estado que os filhos anteriores deixariam (ex. S3.2 já inicia com alguns itens salvos), para que cada filho possa ser revisado por conta própria. - Anotações. Dê a cada filho os itens fora do escopo, suposições e perguntas que se aplicam a ele. Os filhos herdam a prioridade do pai, a menos que o usuário diga o contrário.
- Critérios de aceitação. Cada AC pai move-se para exatamente um filho com seu ID original (
-
Atualize as telas: re-controle qualquer controle que mudou para uma chave diferente. Em seguida, verifique cada filho em cada dispositivo listado e verifique se o id do pai redireciona.
-
Relate a divisão como uma tabela curta (id do filho, história, prioridade, dispositivos, IDs dos ACs) para que o usuário possa verificar se todos os ACs pai foram parar em algum lugar. Espelhe a divisão no backlog ou nos documentos de funcionalidades, se eles mantiverem histórias lá.
Regras
- Um arquivo HTML, CSS/JS inline, sem etapa de build, sem framework, sem backend. Abra diretamente do disco.
- Todos os dados em um único
statecompartilhado na memória; cada dispositivo lê e escreve nele. - Funções de renderização recebem o id do dispositivo e redesenham a partir do
state(veja o shell). - Use dados de amostra inventados e neutros. Nunca copie nomes, marcas ou conteúdo de outros projetos para o protótipo.
- Molduras móveis renderizam a mesma marcação do aplicativo; diferenças entre Android e iPhone são cromadas (barra de status, entalhe/ilha, barra de gestos), não aplicativos separados, a menos que o usuário solicite uma interface de usuário específica da plataforma.