All checks were successful
continuous-integration/drone/push Build is passing
617 lines
22 KiB
Markdown
617 lines
22 KiB
Markdown
# Полные схемы данных для мобильного приложения Women's Safety App
|
||
|
||
## 📋 Содержание
|
||
1. [Схемы авторизации](#схемы-авторизации)
|
||
2. [Схемы пользователей](#схемы-пользователей)
|
||
3. [Схемы экстренных ситуаций](#схемы-экстренных-ситуаций)
|
||
4. [Схемы местоположения](#схемы-местоположения)
|
||
5. [Схемы уведомлений](#схемы-уведомлений)
|
||
6. [Схемы календаря](#схемы-календаря)
|
||
7. [TypeScript интерфейсы](#typescript-интерфейсы)
|
||
|
||
---
|
||
|
||
## 🔐 Схемы авторизации
|
||
|
||
### UserRegister
|
||
```json
|
||
{
|
||
"username": "string", // Имя пользователя (уникальное)
|
||
"email": "string", // Email (уникальный)
|
||
"password": "string", // Пароль (мин 8 символов)
|
||
"full_name": "string?", // Полное имя
|
||
"phone": "string?", // Номер телефона
|
||
"date_of_birth": "date?", // Дата рождения (YYYY-MM-DD)
|
||
"bio": "string?" // Биография (макс 500 символов)
|
||
}
|
||
```
|
||
|
||
### UserLogin
|
||
```json
|
||
{
|
||
"username": "string?", // Имя пользователя ИЛИ
|
||
"email": "string?", // Email (один из двух обязателен)
|
||
"password": "string" // Пароль
|
||
}
|
||
```
|
||
|
||
### TokenResponse
|
||
```json
|
||
{
|
||
"access_token": "string", // JWT токен
|
||
"token_type": "bearer" // Тип токена
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 👤 Схемы пользователей
|
||
|
||
### UserProfile (полная информация)
|
||
```json
|
||
{
|
||
"id": 123, // int, ID пользователя
|
||
"uuid": "8ed4fb51-8a90-4b22...", // string, UUID пользователя
|
||
"username": "testuser", // string, имя пользователя
|
||
"email": "test@example.com", // string, email
|
||
"phone": "+1234567890", // string?, телефон
|
||
"first_name": "John", // string?, имя
|
||
"last_name": "Doe", // string?, фамилия
|
||
"date_of_birth": "1990-01-01", // date?, дата рождения
|
||
"bio": "Краткая биография", // string?, биография
|
||
"avatar_url": "https://...", // string?, URL аватара
|
||
"location_sharing_enabled": true, // bool, разрешение на геолокацию
|
||
"emergency_notifications_enabled": true, // bool, экстренные уведомления
|
||
"push_notifications_enabled": true, // bool, push уведомления
|
||
"email_verified": false, // bool, email подтвержден
|
||
"phone_verified": true, // bool, телефон подтвержден
|
||
"is_active": true, // bool, активен ли аккаунт
|
||
"created_at": "2024-01-01T10:00:00Z", // datetime, дата регистрации
|
||
"updated_at": "2024-01-15T10:00:00Z" // datetime, последнее обновление
|
||
}
|
||
```
|
||
|
||
### UserDashboard
|
||
```json
|
||
{
|
||
"user_info": { // Краткая информация о пользователе
|
||
"id": 123,
|
||
"username": "testuser",
|
||
"email": "test@example.com",
|
||
"first_name": "John",
|
||
"last_name": "Doe"
|
||
},
|
||
"recent_alerts": [ // Последние оповещения (макс 5)
|
||
{
|
||
"id": 456,
|
||
"alert_type": "general",
|
||
"message": "Нужна помощь",
|
||
"created_at": "2024-01-15T09:30:00Z",
|
||
"is_resolved": false,
|
||
"responded_users_count": 2
|
||
}
|
||
],
|
||
"emergency_contacts": [ // Экстренные контакты
|
||
{
|
||
"id": 789,
|
||
"name": "Мама",
|
||
"phone_number": "+1234567890",
|
||
"relationship": "mother"
|
||
}
|
||
],
|
||
"safety_stats": { // Статистика безопасности
|
||
"total_alerts_created": 5,
|
||
"total_responses_given": 12,
|
||
"safety_checks_count": 45,
|
||
"last_safety_check": "2024-01-15T08:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
### EmergencyContact
|
||
```json
|
||
{
|
||
"id": 789, // int, ID контакта
|
||
"uuid": "8ed4fb51-8a90-4b22...", // string, UUID контакта
|
||
"user_id": 123, // int, ID владельца
|
||
"name": "Мама", // string, имя контакта
|
||
"phone_number": "+1234567890", // string, телефон
|
||
"relationship": "mother", // string?, отношение (mother, father, spouse, friend, etc.)
|
||
"notes": "Основной контакт", // string?, заметки
|
||
"is_active": true, // bool, активен ли контакт
|
||
"created_at": "2024-01-01T10:00:00Z", // datetime, дата создания
|
||
"updated_at": "2024-01-15T10:00:00Z" // datetime, последнее обновление
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🆘 Схемы экстренных ситуаций
|
||
|
||
### EmergencyAlert (полная схема)
|
||
```json
|
||
{
|
||
"id": 123, // int, ID оповещения
|
||
"uuid": "8ed4fb51-8a90-4b22...", // string, UUID оповещения
|
||
"user_id": 26, // int, ID создателя
|
||
"latitude": 55.7558, // float, широта (-90 до 90)
|
||
"longitude": 37.6176, // float, долгота (-180 до 180)
|
||
"address": "Красная площадь, Москва", // string?, адрес
|
||
"alert_type": "general", // AlertType, тип оповещения
|
||
"status": "active", // AlertStatus, текущий статус
|
||
"message": "Нужна помощь", // string?, описание ситуации
|
||
"is_resolved": false, // bool, решено ли
|
||
"resolved_at": null, // datetime?, время решения
|
||
"resolved_by": null, // int?, кем решено
|
||
"resolved_notes": null, // string?, заметки о решении
|
||
"contact_emergency_services": true, // bool, связаться со службами
|
||
"notify_emergency_contacts": true, // bool, уведомить контакты
|
||
"notified_users_count": 5, // int, количество уведомленных
|
||
"responded_users_count": 2, // int, количество откликнувшихся
|
||
"created_at": "2024-01-15T10:30:00Z", // datetime, время создания
|
||
"updated_at": "2024-01-15T10:35:00Z" // datetime, последнее обновление
|
||
}
|
||
```
|
||
|
||
### EmergencyResponse (отклик на оповещение)
|
||
```json
|
||
{
|
||
"id": 456, // int, ID отклика
|
||
"uuid": "8ed4fb51-8a90-4b22...", // string, UUID отклика
|
||
"alert_id": 123, // int, ID оповещения
|
||
"user_id": 27, // int, ID откликнувшегося
|
||
"response_type": "help_on_way", // ResponseType, тип отклика
|
||
"message": "Еду к вам!", // string?, сообщение
|
||
"eta_minutes": 15, // int?, время прибытия в минутах
|
||
"location_sharing": true, // bool, делиться местоположением
|
||
"created_at": "2024-01-15T10:32:00Z" // datetime, время создания
|
||
}
|
||
```
|
||
|
||
### EmergencyReport (отчет о происшествии)
|
||
```json
|
||
{
|
||
"id": 789, // int, ID отчета
|
||
"uuid": "8ed4fb51-8a90-4b22...", // string, UUID отчета
|
||
"user_id": 26, // int?, ID автора (null для анонимных)
|
||
"latitude": 55.7558, // float, широта
|
||
"longitude": 37.6176, // float, долгота
|
||
"address": "Тверская улица", // string?, адрес
|
||
"report_type": "harassment", // string, тип происшествия
|
||
"description": "Подробное описание...", // string, описание (10-1000 символов)
|
||
"is_anonymous": false, // bool, анонимный отчет
|
||
"severity": 4, // int, серьезность (1-5)
|
||
"status": "pending", // string, статус (pending/investigating/resolved)
|
||
"created_at": "2024-01-15T10:45:00Z" // datetime, время создания
|
||
}
|
||
```
|
||
|
||
### SafetyCheck (отметка безопасности)
|
||
```json
|
||
{
|
||
"id": 101, // int, ID отметки
|
||
"uuid": "8ed4fb51-8a90-4b22...", // string, UUID отметки
|
||
"user_id": 26, // int, ID пользователя
|
||
"message": "Добрался домой безопасно", // string?, сообщение
|
||
"location_latitude": 55.7600, // float?, широта
|
||
"location_longitude": 37.6100, // float?, долгота
|
||
"created_at": "2024-01-15T22:00:00Z" // datetime, время создания
|
||
}
|
||
```
|
||
|
||
### EmergencyStatistics
|
||
```json
|
||
{
|
||
"total_alerts": 150, // int, общее количество оповещений
|
||
"active_alerts": 12, // int, активные оповещения
|
||
"resolved_alerts": 138, // int, решенные оповещения
|
||
"total_responders": 89, // int, всего откликнувшихся
|
||
"avg_response_time_minutes": 8.5 // float, среднее время отклика
|
||
}
|
||
```
|
||
|
||
### NearbyAlert (ближайшие оповещения)
|
||
```json
|
||
{
|
||
"id": 123, // int, ID оповещения
|
||
"alert_type": "medical", // string, тип оповещения
|
||
"latitude": 55.7558, // float, широта
|
||
"longitude": 37.6176, // float, долгота
|
||
"address": "Больница №1", // string?, адрес
|
||
"distance_km": 2.5, // float, расстояние в километрах
|
||
"created_at": "2024-01-15T09:15:00Z", // datetime, время создания
|
||
"responded_users_count": 3 // int, количество откликов
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📍 Схемы местоположения
|
||
|
||
### LocationUpdate
|
||
```json
|
||
{
|
||
"latitude": 55.7558, // float, широта (-90 до 90)
|
||
"longitude": 37.6176, // float, долгота (-180 до 180)
|
||
"accuracy": 10.0, // float?, точность в метрах
|
||
"altitude": 150.0, // float?, высота в метрах
|
||
"speed": 0.0, // float?, скорость м/с
|
||
"heading": 90.0, // float?, направление (0-360 градусов)
|
||
"timestamp": "2024-01-15T10:30:00Z" // datetime?, время получения координат
|
||
}
|
||
```
|
||
|
||
### NearbyUser
|
||
```json
|
||
{
|
||
"user_id": 27, // int, ID пользователя
|
||
"distance_meters": 500.0, // float, расстояние в метрах
|
||
"latitude": 55.7568, // float, широта (может быть приблизительной)
|
||
"longitude": 37.6186, // float, долгота (может быть приблизительной)
|
||
"last_seen": "2024-01-15T10:25:00Z", // datetime, последнее обновление местоположения
|
||
"is_available": true // bool, готов ли помочь
|
||
}
|
||
```
|
||
|
||
### GeocodeResult
|
||
```json
|
||
{
|
||
"address": "Красная площадь, 1, Москва, Россия", // string, полный адрес
|
||
"street": "Красная площадь", // string?, улица
|
||
"house_number": "1", // string?, номер дома
|
||
"city": "Москва", // string?, город
|
||
"state": "Москва", // string?, регион/область
|
||
"country": "Россия", // string?, страна
|
||
"postal_code": "109012", // string?, почтовый индекс
|
||
"latitude": 55.7558, // float, широта
|
||
"longitude": 37.6176 // float, долгота
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔔 Схемы уведомлений
|
||
|
||
### NotificationCreate
|
||
```json
|
||
{
|
||
"user_id": 123, // int, ID получателя
|
||
"title": "Экстренное оповещение", // string, заголовок
|
||
"message": "Новое оповещение рядом с вами", // string, текст сообщения
|
||
"type": "emergency_alert", // string, тип уведомления
|
||
"data": { // object?, дополнительные данные
|
||
"alert_id": 456,
|
||
"latitude": 55.7558,
|
||
"longitude": 37.6176
|
||
},
|
||
"priority": "high", // string?, приоритет (low/normal/high/urgent)
|
||
"schedule_at": null // datetime?, время отправки (null = сейчас)
|
||
}
|
||
```
|
||
|
||
### PushTokenRegistration
|
||
```json
|
||
{
|
||
"token": "fcm_or_apns_token_here", // string, токен устройства
|
||
"platform": "ios", // string, платформа (ios/android)
|
||
"app_version": "1.0.0", // string?, версия приложения
|
||
"device_info": { // object?, информация об устройстве
|
||
"model": "iPhone 14",
|
||
"os_version": "17.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
### NotificationHistory
|
||
```json
|
||
{
|
||
"id": 789, // int, ID уведомления
|
||
"user_id": 123, // int, ID получателя
|
||
"title": "Экстренное оповещение", // string, заголовок
|
||
"message": "Текст уведомления", // string, сообщение
|
||
"type": "emergency_alert", // string, тип
|
||
"status": "delivered", // string, статус (sent/delivered/read/failed)
|
||
"sent_at": "2024-01-15T10:30:00Z", // datetime, время отправки
|
||
"delivered_at": "2024-01-15T10:30:05Z", // datetime?, время доставки
|
||
"read_at": null // datetime?, время прочтения
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📅 Схемы календаря
|
||
|
||
### CalendarEntry
|
||
```json
|
||
{
|
||
"id": 456, // int, ID записи
|
||
"user_id": 123, // int, ID пользователя
|
||
"date": "2024-01-15", // date, дата записи (YYYY-MM-DD)
|
||
"entry_type": "period_start", // string, тип записи
|
||
"notes": "Болезненные ощущения", // string?, заметки
|
||
"mood_score": 3, // int?, настроение (1-5)
|
||
"energy_level": 4, // int?, уровень энергии (1-5)
|
||
"symptoms": [ // array?, симптомы
|
||
"headache",
|
||
"fatigue",
|
||
"cramps"
|
||
],
|
||
"flow_intensity": "medium", // string?, интенсивность (light/medium/heavy)
|
||
"temperature": 36.6, // float?, температура тела
|
||
"weight": 65.5, // float?, вес
|
||
"created_at": "2024-01-15T08:00:00Z", // datetime, время создания
|
||
"updated_at": "2024-01-15T08:05:00Z" // datetime, последнее обновление
|
||
}
|
||
```
|
||
|
||
### CalendarAnalytics
|
||
```json
|
||
{
|
||
"cycle_length": 28, // int?, средняя длина цикла
|
||
"period_length": 5, // int?, средняя длина месячных
|
||
"next_period_prediction": "2024-02-10", // date?, прогноз следующих месячных
|
||
"fertility_window": { // object?, окно фертильности
|
||
"start": "2024-01-20",
|
||
"end": "2024-01-25"
|
||
},
|
||
"mood_trends": { // object?, тренды настроения
|
||
"average_score": 3.5,
|
||
"lowest_day": 2,
|
||
"highest_day": 12
|
||
},
|
||
"symptoms_frequency": { // object?, частота симптомов
|
||
"headache": 0.3,
|
||
"cramps": 0.8,
|
||
"fatigue": 0.6
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📱 TypeScript интерфейсы
|
||
|
||
```typescript
|
||
// Перечисления
|
||
export enum AlertType {
|
||
GENERAL = 'general',
|
||
MEDICAL = 'medical',
|
||
VIOLENCE = 'violence',
|
||
HARASSMENT = 'harassment',
|
||
UNSAFE_AREA = 'unsafe_area',
|
||
ACCIDENT = 'accident',
|
||
FIRE = 'fire',
|
||
NATURAL_DISASTER = 'natural_disaster'
|
||
}
|
||
|
||
export enum AlertStatus {
|
||
ACTIVE = 'active',
|
||
RESOLVED = 'resolved',
|
||
CANCELLED = 'cancelled',
|
||
INVESTIGATING = 'investigating'
|
||
}
|
||
|
||
export enum ResponseType {
|
||
HELP_ON_WAY = 'help_on_way',
|
||
CONTACTED_AUTHORITIES = 'contacted_authorities',
|
||
SAFE_NOW = 'safe_now',
|
||
FALSE_ALARM = 'false_alarm',
|
||
INVESTIGATING = 'investigating',
|
||
RESOLVED = 'resolved'
|
||
}
|
||
|
||
// Интерфейсы авторизации
|
||
export interface UserRegister {
|
||
username: string;
|
||
email: string;
|
||
password: string;
|
||
full_name?: string;
|
||
phone?: string;
|
||
date_of_birth?: string;
|
||
bio?: string;
|
||
}
|
||
|
||
export interface UserLogin {
|
||
username?: string;
|
||
email?: string;
|
||
password: string;
|
||
}
|
||
|
||
export interface TokenResponse {
|
||
access_token: string;
|
||
token_type: string;
|
||
}
|
||
|
||
// Интерфейсы пользователя
|
||
export interface UserProfile {
|
||
id: number;
|
||
uuid: string;
|
||
username: string;
|
||
email: string;
|
||
phone?: string;
|
||
first_name?: string;
|
||
last_name?: string;
|
||
date_of_birth?: string;
|
||
bio?: string;
|
||
avatar_url?: string;
|
||
location_sharing_enabled: boolean;
|
||
emergency_notifications_enabled: boolean;
|
||
push_notifications_enabled: boolean;
|
||
email_verified: boolean;
|
||
phone_verified: boolean;
|
||
is_active: boolean;
|
||
created_at: string;
|
||
updated_at?: string;
|
||
}
|
||
|
||
export interface EmergencyContact {
|
||
id: number;
|
||
uuid: string;
|
||
user_id: number;
|
||
name: string;
|
||
phone_number: string;
|
||
relationship?: string;
|
||
notes?: string;
|
||
is_active: boolean;
|
||
created_at: string;
|
||
updated_at?: string;
|
||
}
|
||
|
||
// Интерфейсы экстренных ситуаций
|
||
export interface EmergencyAlertCreate {
|
||
latitude: number;
|
||
longitude: number;
|
||
alert_type: AlertType;
|
||
message?: string;
|
||
address?: string;
|
||
contact_emergency_services?: boolean;
|
||
notify_emergency_contacts?: boolean;
|
||
}
|
||
|
||
export interface EmergencyAlert {
|
||
id: number;
|
||
uuid: string;
|
||
user_id: number;
|
||
latitude: number;
|
||
longitude: number;
|
||
address?: string;
|
||
alert_type: AlertType;
|
||
status: AlertStatus;
|
||
message?: string;
|
||
is_resolved: boolean;
|
||
resolved_at?: string;
|
||
resolved_by?: number;
|
||
resolved_notes?: string;
|
||
contact_emergency_services: boolean;
|
||
notify_emergency_contacts: boolean;
|
||
notified_users_count: number;
|
||
responded_users_count: number;
|
||
created_at: string;
|
||
updated_at?: string;
|
||
}
|
||
|
||
export interface EmergencyResponseCreate {
|
||
response_type: ResponseType;
|
||
message?: string;
|
||
eta_minutes?: number;
|
||
location_sharing?: boolean;
|
||
}
|
||
|
||
export interface EmergencyResponse {
|
||
id: number;
|
||
uuid: string;
|
||
alert_id: number;
|
||
user_id: number;
|
||
response_type: ResponseType;
|
||
message?: string;
|
||
eta_minutes?: number;
|
||
location_sharing: boolean;
|
||
created_at: string;
|
||
}
|
||
|
||
export interface EmergencyStatistics {
|
||
total_alerts: number;
|
||
active_alerts: number;
|
||
resolved_alerts: number;
|
||
total_responders: number;
|
||
avg_response_time_minutes: number;
|
||
}
|
||
|
||
export interface NearbyAlert {
|
||
id: number;
|
||
alert_type: string;
|
||
latitude: number;
|
||
longitude: number;
|
||
address?: string;
|
||
distance_km: number;
|
||
created_at: string;
|
||
responded_users_count: number;
|
||
}
|
||
|
||
// Интерфейсы местоположения
|
||
export interface LocationUpdate {
|
||
latitude: number;
|
||
longitude: number;
|
||
accuracy?: number;
|
||
altitude?: number;
|
||
speed?: number;
|
||
heading?: number;
|
||
timestamp?: string;
|
||
}
|
||
|
||
export interface NearbyUser {
|
||
user_id: number;
|
||
distance_meters: number;
|
||
latitude: number;
|
||
longitude: number;
|
||
last_seen: string;
|
||
is_available: boolean;
|
||
}
|
||
|
||
// Интерфейсы уведомлений
|
||
export interface PushTokenRegistration {
|
||
token: string;
|
||
platform: 'ios' | 'android';
|
||
app_version?: string;
|
||
device_info?: {
|
||
model?: string;
|
||
os_version?: string;
|
||
};
|
||
}
|
||
|
||
// API клиент
|
||
export interface APIClient {
|
||
setToken(token: string): void;
|
||
login(username: string, password: string): Promise<TokenResponse>;
|
||
register(userData: UserRegister): Promise<UserProfile>;
|
||
getProfile(): Promise<UserProfile>;
|
||
createAlert(alertData: EmergencyAlertCreate): Promise<EmergencyAlert>;
|
||
getNearbyAlerts(lat: number, lng: number, radius?: number): Promise<NearbyAlert[]>;
|
||
respondToAlert(alertId: number, response: EmergencyResponseCreate): Promise<EmergencyResponse>;
|
||
updateLocation(location: LocationUpdate): Promise<void>;
|
||
createSafetyCheck(data: { message?: string; location_latitude?: number; location_longitude?: number }): Promise<any>;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 Валидация данных
|
||
|
||
### Ограничения полей
|
||
- **Координаты**: latitude (-90 до 90), longitude (-180 до 180)
|
||
- **Пароль**: минимум 8 символов, максимум 70 (для совместимости с bcrypt)
|
||
- **Email**: валидный формат email
|
||
- **Телефон**: рекомендуется международный формат (+1234567890)
|
||
- **Сообщения**: максимум 500 символов для alert message, 200 для safety check
|
||
- **Описания**: 10-1000 символов для emergency reports
|
||
|
||
### Обязательные поля
|
||
- При регистрации: username, email, password
|
||
- При создании оповещения: latitude, longitude, alert_type
|
||
- При отклике: response_type
|
||
- При обновлении местоположения: latitude, longitude
|
||
|
||
### Рекомендации по обработке ошибок
|
||
```typescript
|
||
interface APIError {
|
||
detail: string;
|
||
status_code: number;
|
||
field_errors?: {
|
||
[field: string]: string[];
|
||
};
|
||
}
|
||
|
||
// Обработка ошибок валидации
|
||
try {
|
||
await api.createAlert(alertData);
|
||
} catch (error) {
|
||
if (error.status_code === 422) {
|
||
// Показать ошибки валидации для каждого поля
|
||
Object.entries(error.field_errors || {}).forEach(([field, errors]) => {
|
||
console.error(`${field}: ${errors.join(', ')}`);
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
Эти схемы данных обеспечивают полную интеграцию мобильного приложения с Women's Safety App API. |