Mobile - Contratos API¶
Endpoints Utilizados pelo Mobile¶
O mobile consome a mesma API REST do backend documentada em API - Documentação Completa. Este documento destaca os endpoints mais relevantes para o mobile.
Autenticação¶
Login¶
POST /api/auth/login
Uso no mobile:
const response = await api.post('/auth/login', {
email,
password
})
const { token, refresh_token } = response.data
await SecureStore.setItemAsync('token', token)
await SecureStore.setItemAsync('refresh_token', refresh_token)
Refresh Token¶
POST /api/auth/refresh
Uso no mobile:
const response = await api.post('/auth/refresh', {
refresh_token: await SecureStore.getItemAsync('refresh_token')
})
const { token } = response.data
await SecureStore.setItemAsync('token', token)
Registro Diário¶
Criar Observação¶
POST /api/observations
Payload:
{
"date": "2024-01-15",
"symbol_id": 1,
"sensation_id": 2,
"appearance_id": 3,
"had_intercourse": false,
"is_first_day_of_menstruation": false
}
Uso no mobile:
await api.post('/observations', {
date: formatDate(new Date()),
symbol_id: selectedSymbolId,
sensation_id: selectedSensationId,
appearance_id: selectedAppearanceId,
had_intercourse: false,
is_first_day_of_menstruation: isFirstDay
})
Listar Observações¶
GET /api/observations?cycle_id=1&start_date=2024-01-01&end_date=2024-01-31
Status de Fertilidade¶
Obter Status¶
GET /api/client/fertility-status?date=2024-01-15
Resposta:
{
"is_fertile": false,
"intercourse_status": "allowed_no_risk",
"days_after_peak": null,
"has_bleeding": false,
"peak_date": null
}
Uso no mobile:
const { data: fertilityStatus } = useQuery({
queryKey: ['fertility-status', date],
queryFn: () => api.get('/client/fertility-status', {
params: { date: formatDate(date) }
}).then(res => res.data)
})
Ciclos¶
Listar Ciclos¶
GET /api/cycles
Obter Ciclo Ativo¶
GET /api/cycles/active
Criar Ciclo¶
POST /api/cycles
Payload:
{
"start_date": "2024-01-01"
}
Sincronização¶
Push (Enviar Dados)¶
POST /api/sync/push
Payload:
{
"cycles": [
{
"sync_id": "uuid-local",
"start_date": "2024-01-01",
"is_active": true
}
],
"observations": [
{
"sync_id": "uuid-local",
"date": "2024-01-15",
"symbol_id": 1
}
]
}
Uso no mobile:
// Coletar dados locais (offline)
const localCycles = await getLocalCycles()
const localObservations = await getLocalObservations()
// Enviar para servidor
await api.post('/sync/push', {
cycles: localCycles,
observations: localObservations
})
Pull (Buscar Atualizações)¶
GET /api/sync/pull?last_sync=2024-01-15T10:00:00Z
Resposta:
{
"cycles": [...],
"observations": [...],
"last_sync": "2024-01-15T10:00:00Z"
}
Uso no mobile:
const lastSync = await getLastSyncTimestamp()
const { data } = await api.get('/sync/pull', {
params: { last_sync: lastSync }
})
// Salvar dados localmente
await saveLocalCycles(data.cycles)
await saveLocalObservations(data.observations)
await saveLastSyncTimestamp(data.last_sync)
Símbolos Permitidos¶
Obter Símbolos Permitidos¶
GET /api/symbols/allowed
Resposta:
{
"allowed_symbols": [1, 2, 3],
"restricted_symbols": [4, 5],
"cycle_day": 16
}
Uso no mobile:
const { data: allowedSymbols } = useQuery({
queryKey: ['allowed-symbols'],
queryFn: () => api.get('/symbols/allowed').then(res => res.data)
})
// Filtrar símbolos disponíveis para seleção
const availableSymbols = symbols.filter(s =>
allowedSymbols?.allowed_symbols.includes(s.id)
)
Dados do Método Billings¶
Sensações¶
GET /api/billings/sensations
Aparências¶
GET /api/billings/appearances
Símbolos¶
GET /api/billings/symbols
Fluxos Críticos¶
1. Registro Diário Completo¶
// 1. Verificar ciclo ativo
const { data: activeCycle } = await api.get('/cycles/active')
if (!activeCycle) {
// Criar novo ciclo
await api.post('/cycles', { start_date: formatDate(new Date()) })
}
// 2. Obter símbolos permitidos
const { data: allowedSymbols } = await api.get('/symbols/allowed')
// 3. Criar observação
await api.post('/observations', {
date: formatDate(new Date()),
symbol_id: selectedSymbolId,
sensation_id: selectedSensationId,
appearance_id: selectedAppearanceId
})
// 4. Atualizar status de fertilidade
queryClient.invalidateQueries(['fertility-status'])
2. Sincronização Offline¶
// Quando voltar online
const syncData = async () => {
try {
// Push: enviar dados locais
const localData = await getLocalPendingData()
if (localData.cycles.length > 0 || localData.observations.length > 0) {
await api.post('/sync/push', localData)
await clearLocalPendingData()
}
// Pull: buscar atualizações
const lastSync = await getLastSyncTimestamp()
const { data } = await api.get('/sync/pull', {
params: { last_sync: lastSync }
})
// Atualizar dados locais
await mergeLocalData(data)
await saveLastSyncTimestamp(data.last_sync)
} catch (error) {
console.error('Erro na sincronização:', error)
}
}
3. Dashboard¶
// Buscar dados do dashboard
const { data: statistics } = useQuery({
queryKey: ['client-statistics'],
queryFn: () => api.get('/client/statistics').then(res => res.data)
})
// statistics contém:
// - active_cycle
// - fertility_status
// - total_cycles
// - average_cycle_length
Payloads Esperados¶
Criar Observação¶
Request:
{
"date": "2024-01-15",
"symbol_id": 1,
"sensation_id": 2,
"appearance_id": 3,
"had_intercourse": false,
"is_first_day_of_menstruation": false
}
Response (201):
{
"id": 123,
"user_id": 1,
"cycle_id": 1,
"date": "2024-01-15",
"symbol_id": 1,
"sensation_id": 2,
"appearance_id": 3,
"fertility_status": {
"is_fertile": false,
"intercourse_status": "allowed_no_risk"
}
}
Sincronização Push¶
Request:
{
"cycles": [
{
"sync_id": "local-uuid-1",
"start_date": "2024-01-01",
"is_active": true
}
],
"observations": [
{
"sync_id": "local-uuid-2",
"date": "2024-01-15",
"symbol_id": 1
}
]
}
Response (200):
{
"synced_count": 2,
"conflicts": []
}
Dependência Direta da API¶
O mobile depende completamente da API documentada em API - Documentação Completa. Qualquer mudança na API deve ser refletida no mobile.