- Remove hardcoded database credentials from all scripts - Remove hardcoded Legacy API tokens from backend scripts - Remove hardcoded MQTT credentials from mqtt-test.js - Update backend/.env.example with DB_HOST, DB_USER, DB_PASSWORD, DB_NAME - Update backend/.env.example with LEGACY_API_TOKEN and MQTT credentials - Add dotenv config to all scripts requiring credentials - Create comprehensive documentation: - scripts/README.md - Root scripts usage - backend/scripts/README.md - Backend scripts documentation - MQTT_TESTING.md - MQTT testing guide - SECURITY_CREDENTIALS_CLEANUP.md - Security changes summary All scripts now read credentials from backend/.env instead of hardcoded values. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
9.4 KiB
PRD — WellNuo Full Audit & Bug Fixes
❓ Вопросы для уточнения
❓ Вопрос 1: Формат серийного номера
Какой regex pattern должен валидировать serial number устройства? Сейчас проверяется только длина >= 8.
Ответ: Использовать regex /^[A-Za-z0-9]{8,16}$/ — буквенно-цифровой, 8-16 символов.
❓ Вопрос 2: Demo credentials configuration
Куда вынести hardcoded demo credentials (anandk)? В .env файл, SecureStore или отдельный config?
Ответ: anandk — устаревший аккаунт. Нужно заменить на robster/rob2 (актуальный аккаунт для Legacy API). Вынести в .env файл как LEGACY_API_USER=robster и LEGACY_API_PASSWORD=rob2.
❓ Вопрос 3: Максимальное количество beneficiaries
Сколько beneficiaries может быть у одного пользователя? Нужна ли пагинация для списка? Ответ: Максимум ~5 beneficiaries. Пагинация не нужна.
Цель
Исправить критические баги, улучшить безопасность и стабильность приложения WellNuo перед production release.
Контекст проекта
- Тип: Expo / React Native приложение
- Стек: expo 53, react-native 0.79, typescript, expo-router, livekit, stripe, BLE
- API: WellNuo (wellnuo.smartlaunchhub.com) + Legacy (eluxnetworks.net)
- БД: PostgreSQL через WellNuo API
- Навигация: Expo Router + NavigationController.ts
Задачи
Phase 1: Критические исправления
-
@backend Заменить устаревшие credentials (anandk → robster) и вынести в .env
- Файлы для замены:
services/api.ts:1508-1509— основной API клиентbackend/src/services/mqtt.js:20-21— MQTT сервисWellNuoLite/app/(tabs)/chat.tsx:37-38— текстовый чатWellNuoLite/contexts/VoiceContext.tsx:27-28— голосовой контекстWellNuoLite/julia-agent/julia-ai/src/agent.py:31-32— Python агентwellnuo-debug/debug.html:728-733— debug консольmqtt-test.js:15-16— тестовый скрипт
- Что сделать:
- Заменить
anandk/anandk_8наrobster/rob2везде - Вынести в
.env:LEGACY_API_USER=robster,LEGACY_API_PASSWORD=rob2 - Читать через
process.env/ Expo Constants
- Заменить
- Готово когда: Все файлы используют
robster, credentials в.env
- Файлы для замены:
-
@backend Fix displayName undefined в API response
- Файл:
services/api.ts:698-714 - Что сделать: Добавить fallback в функцию
getBeneficiariesFromResponse:displayName: item.customName || item.name || item.email || 'Unknown User' - Готово когда: BeneficiaryCard никогда не показывает undefined
- Файл:
-
@frontend BLE cleanup при logout
- Файл:
contexts/BLEContext.tsx - Переиспользует:
services/ble/BLEManager.ts - Что сделать: В функции logout добавить вызов
bleManager.disconnectAll()перед очисткой состояния - Готово когда: При logout все BLE соединения отключаются
- Файл:
-
@frontend Fix race condition с AbortController
- Файл:
app/(tabs)/index.tsx:207-248 - Что сделать: В
loadBeneficiariesсоздать AbortController, передать signal в API вызовы, отменить в useEffect cleanup - Готово когда: Быстрое переключение экранов не вызывает дублирующих запросов
- Файл:
-
@backend Обработка missing deploymentId
- Файл:
services/api.ts:1661-1665 - Что сделать: Вместо
return []выбросить Error с кодом 'MISSING_DEPLOYMENT_ID' и message 'No deployment configured for user' - Готово когда: UI показывает понятное сообщение об ошибке
- Файл:
Phase 2: Безопасность
-
@frontend WiFi password в SecureStore
- Файл:
app/(tabs)/beneficiaries/[id]/setup-wifi.tsx - Переиспользует:
services/storage.ts - Что сделать: Заменить
AsyncStorage.setItemнаstorage.setItemдля WiFi credentials, добавить ключwifi_${beneficiaryId} - Готово когда: WiFi пароли сохраняются в зашифрованном виде
- Файл:
-
@backend Проверить equipmentStatus mapping
- Файл:
services/api.ts:113,services/NavigationController.ts:89-95 - Что сделать: Убедиться что API возвращает точно 'demo', не 'demo_mode'. Добавить debug логи в BeneficiaryDetailController
- Готово когда: Demo beneficiary корректно определяется в навигации
- Файл:
Phase 3: UX улучшения
-
@frontend Fix avatar caching после upload
- Файл:
app/(tabs)/profile/index.tsx - Переиспользует:
services/api.tsметодgetMe() - Что сделать: После успешного upload avatar вызвать
api.getMe()и обновить state, не использовать локальный imageUri - Готово когда: Avatar обновляется сразу после upload
- Файл:
-
@frontend Retry button в error state
- Файл:
app/(tabs)/index.tsx:317-327 - Переиспользует:
components/ui/Button.tsx - Что сделать: В error блоке добавить
<Button onPress={loadBeneficiaries}>Retry</Button>под текстом ошибки - Готово когда: При ошибке загрузки есть кнопка повтора
- Файл:
-
@frontend Улучшить serial validation
- Файл:
app/(auth)/activate.tsx:33-48 - Что сделать: Добавить regex validation перед API вызовом, показывать ошибку "Invalid serial format" в real-time
- Готово когда: Некорректный формат serial показывает ошибку до отправки
- Файл:
-
@frontend Role-based UI для Edit кнопки
- Файл:
app/(tabs)/index.tsx:133-135 - Что сделать: Обернуть Edit кнопку в условие
{beneficiary.role === 'custodian' && <TouchableOpacity>...} - Готово когда: Caretaker не видит кнопку Edit у beneficiary
- Файл:
-
@frontend Debouncing для refresh button
- Файл:
app/(tabs)/index.tsx:250-254 - Что сделать: Добавить state
isRefreshing, disable кнопку на 1 секунду после нажатия - Готово когда: Нельзя spam нажимать refresh
- Файл:
Phase 4: Очистка кода
-
@backend Удалить mock data из getBeneficiaries
- Файл:
services/api.ts:562-595 - Что сделать: Удалить функцию
getBeneficiariesполностью, оставить толькоgetAllBeneficiaries - Готово когда: Функция не существует в коде
- Файл:
-
@backend Константы для magic numbers
- Файл:
services/api.ts:608-609 - Что сделать: Создать
const ONLINE_THRESHOLD_MS = 30 * 60 * 1000в начале файла, использовать в коде - Готово когда: Нет magic numbers в логике online/offline
- Файл:
-
@backend Удалить console.logs
- Файл:
services/api.ts:1814-1895 - Что сделать: Удалить все
console.logв функцииattachDeviceToBeneficiary - Готово когда: Нет console.log в production коде
- Файл:
-
@frontend Null safety в navigation
- Файл:
app/(tabs)/index.tsx:259 - Что сделать: Добавить guard
if (!beneficiary?.id) return;передrouter.push - Готово когда: Нет crash при нажатии на beneficiary без ID
- Файл:
-
@frontend BLE scanning cleanup
- Файл:
services/ble/BLEManager.ts:64-80 - Переиспользует:
useFocusEffectиз React Navigation - Что сделать: Добавить
stopScan()в cleanup функцию всех экранов с BLE scanning - Готово когда: BLE scanning останавливается при уходе с экрана
- Файл:
Критерии готовности
- Нет hardcoded credentials в коде
- BLE соединения отключаются при logout
- WiFi пароли зашифрованы
- Нет race conditions при быстром переключении
- Console.logs удалены
- Avatar caching исправлен
- Role-based доступ работает корректно
✅ Статус
15 задач распределены между @backend (6) и @frontend (9). Готов к запуску после ответа на 3 вопроса выше.