Appearance
GET /app/versions
Resumo
Informa ao app mobile se há uma atualização publicada para a plataforma do dispositivo e se a atualização é obrigatória. O app consulta este endpoint ao abrir e ao voltar para foreground, antes mesmo de autenticar.
Auth
Rota pública (@Public() + @SkipCompany()). Não exige token JWT nem header x-company-id. O app pode chamar antes do login.
Query params
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
currentVersion | string (semver) | Sim | Versão nativa instalada |
platform | ios | android | Sim | Plataforma do dispositivo |
runtimeVersion | string | Não | Runtime do Expo Updates |
updateId | string | Não | ID do bundle OTA atual |
Resposta
json
{
"data": {
"updateAvailable": true,
"version": {
"id": "uuid",
"version": "1.2.0",
"launchAt": "2026-06-20T12:00:00.000Z",
"type": "feature",
"forceUpdate": false,
"title": "Nova atualização disponível",
"description": "Texto exibido no modal",
"storeUrl": "https://apps.apple.com/br/app/contrasync/id6782732793",
"delivery": "store",
"minSupportedVersion": "1.0.0",
"deprecatedAt": null,
"platform": "ios",
"createdAt": "2026-06-20T12:00:00.000Z"
}
}
}Quando não houver atualização pendente:
json
{
"data": {
"updateAvailable": false,
"version": null
}
}typescript
interface AppVersionCheckResponse {
data: {
updateAvailable: boolean;
version: AppVersion | null;
};
}
interface AppVersion {
id: string;
version: string;
launchAt: string;
type: 'feature' | 'bug_fix' | 'release';
forceUpdate: boolean;
title: string;
description: string;
storeUrl: string | null;
delivery: 'store' | 'ota';
minSupportedVersion: string;
deprecatedAt: string | null;
platform: 'ios' | 'android';
createdAt: string;
}Resolução no backend
- Seleciona as versões da
platformrecebida que já foram lançadas (launchAt <= agora) e não estão removidas (deletedAt = null). - Escolhe a maior
versionpor comparação semver. updateAvailable = maiorVersao > currentVersion. Se a instalada já for a maior, respondeupdateAvailable: falseeversion: null.- Calcula o
forceUpdateefetivo da versão retornada (ver abaixo).
Cálculo do forceUpdate
O campo forceUpdate da resposta é computado pelo backend, não simplesmente copiado do registro:
type = bug_fix→true.currentVersion < minSupportedVersion→true(versão instalada abaixo do mínimo suportado).deprecatedAtdefinido e já no passado →true.- Caso contrário → o
forceUpdatearmazenado no registro (falseparafeature;falseparareleaseenquanto suportada).
Tabela app_versions
| Coluna | Tipo | Nullable | Notas |
|---|---|---|---|
id | UUID | não | PK |
version | text | não | Semver exibida ao usuário |
platform | AppPlatform (ios | android) | não | Um registro por plataforma |
type | AppVersionType (feature | bug_fix | release) | não | |
delivery | AppVersionDelivery (store | ota) | não | default store |
forceUpdate | boolean | não | default false; base do cálculo efetivo |
title | text | não | Título do modal |
description | text | não | Texto do modal |
storeUrl | text | sim | URL da loja correspondente à plataforma |
minSupportedVersion | text | não | Versão mínima ainda suportada |
runtimeVersion | text | sim | Runtime do bundle (Expo Updates) |
updateId | text | sim | ID do bundle OTA |
launchAt | timestamptz | não | Data de publicação |
deprecatedAt | timestamptz | sim | A partir desta data, versões antigas deixam de ser aceitas |
createdAt | timestamptz | não | |
updatedAt | timestamptz | não | |
deletedAt | timestamptz | sim | soft delete |
Índice: (platform, launchAt).
Regras de negócio
As regras de produto (tipos de atualização, persistência do adiamento, revalidação no foreground) estão em business/app-versions.md.