Criando SPA/PWA com Jumentix
Este guia descreve como usar Jumentix para planejar e entregar aplicativos frontend (SPA/PWA) integrados com serviços backend.
Responsabilidade no escopo
- Responsável por: Jornada frontend/offline para apps no estilo Service Management
- Usado com: designer-core, cana, hub do app service-management
- Não responsável por: Repositórios de banco server-side ou clientes gRPC Node
Glossário
- Guia — documento de jornada; siga os passos em ordem antes de pular para mapas de API.
- Composition root — startup que liga env → adapters → use-cases.
O que é
Construa uma SPA/PWA com designer-core para o modelo e Cana para persistência offline.
1. Modele primeiro os domínios de negócios
Use o Designer de Domínio para definir:
- domínios e contextos limitados
- entidades de dados e objetos de valor
- relacionamentos e restrições
- Contratos de API e eventos
Isso mantém o estado do front-end e os contratos de back-end alinhados desde a primeira iteração.
2. Definir contratos de comunicação
Utilize o Communication Interface Designer para escolher:
- Consumo somente REST
- Tempo real com WebSocket
- Tempo real com gRPC (para consumidores de back-end baseados em Node)
Os contratos se tornam a fonte da integração SDK/cliente.
3. Configurar o tempo de execução do serviço
Na configuração do serviço:
- escolha o tipo de serviço (
RESTAPI,websocketAPI + RESTAPI,grpcAPI + RESTAPI) - configurar o tempo de execução e o destino de implantação
- edite chaves de ambiente como
JUMENTIX_HTTP_FRAMEWORK,JUMENTIX_REALTIME_API,JUMENTIX_REALTIME_API_PROTOCOL
4. Crie um PWA com capacidade offline
Para arquitetura PWA/offline-first:
- use IndexedDB local no frontend
- sincronizar com contratos de back-end de forma assíncrona
- manter as estratégias de conflito explícitas (last-write-wins ou mesclagem específica de domínio)
5. Validar a disponibilidade de entrega
- verificações de contrato de OpenAPI/AsyncAPI
- portas CI de back-end
- construção de front-end e verificações de fumaça offline
6. Offline com Cana + designs
Validar um design
Normalize o modelo de exemplo e colete issues de validação (API real do designer-core).
### Validar um design
```ts
const raw = api.buildSampleModelPayload();
const state = api.normalizeStatePayload(raw);
const issues = api.collectModelIssues(state);
const errors = issues.filter((issue) => issue.severity === 'error');
return {
ok: errors.length === 0,
issueCount: issues.length,
errorCount: errors.length,
sample: issues.slice(0, 3)
};
```const raw = api.buildSampleModelPayload();
const state = api.normalizeStatePayload(raw);
const issues = api.collectModelIssues(state);
const errors = issues.filter((issue) => issue.severity === 'error');
return {
ok: errors.length === 0,
issueCount: issues.length,
errorCount: errors.length,
sample: issues.slice(0, 3)
};Primeiros passos
Abra um client, crie registros Category e Task, depois leia de volta.
### Primeiros passos
```ts
const client = cana.createClient({
name: dbName,
schema: {
version: 1,
stores: [
{ name: 'categories', keyPath: 'id', indexes: [{ name: 'byName', keyPath: 'name', unique: true }] },
{
name: 'tasks',
keyPath: 'id',
indexes: [
{ name: 'byCategory', keyPath: 'categoryId' },
{ name: 'byCompleted', keyPath: 'completed' },
{ name: 'byUpdatedAt', keyPath: 'updatedAt' }
]
}
]
}
});
await client.open();
await client.table('categories').add({
id: 'work',
name: 'Work',
color: '#2563eb',
createdAt: Date.now(),
updatedAt: Date.now()
});
await client.table('tasks').add({
id: 'task-1',
title: 'Write the Cana tutorial',
categoryId: 'work',
completed: false,
priority: 'high',
createdAt: Date.now(),
updatedAt: Date.now()
});
return {
backend: client.backend,
category: await client.table('categories').get('work'),
task: await client.table('tasks').get('task-1')
};
```const client = cana.createClient({
name: dbName,
schema: {
version: 1,
stores: [
{ name: 'categories', keyPath: 'id', indexes: [{ name: 'byName', keyPath: 'name', unique: true }] },
{
name: 'tasks',
keyPath: 'id',
indexes: [
{ name: 'byCategory', keyPath: 'categoryId' },
{ name: 'byCompleted', keyPath: 'completed' },
{ name: 'byUpdatedAt', keyPath: 'updatedAt' }
]
}
]
}
});
await client.open();
await client.table('categories').add({
id: 'work',
name: 'Work',
color: '#2563eb',
createdAt: Date.now(),
updatedAt: Date.now()
});
await client.table('tasks').add({
id: 'task-1',
title: 'Write the Cana tutorial',
categoryId: 'work',
completed: false,
priority: 'high',
createdAt: Date.now(),
updatedAt: Date.now()
});
return {
backend: client.backend,
category: await client.table('categories').get('work'),
task: await client.table('tasks').get('task-1')
};Próximos passos
Referências
- Pacotes: /docs/pt-BR/jumentix/packages
Checklist júnior (“Eu consigo …”)
- Explico o objetivo deste guia em uma frase
- Completei o primeiro sucesso sem adivinhar jargão
- Sei a próxima página de docs a abrir