{"id":51188081,"url":"https://github.com/shurshick/shopping-list","last_synced_at":"2026-06-27T12:03:22.960Z","repository":{"id":363871194,"uuid":"1265246720","full_name":"shurshick/shopping-list","owner":"shurshick","description":"Android-приложение и сервер синхронизации для совместных списков покупок","archived":false,"fork":false,"pushed_at":"2026-06-20T17:22:31.000Z","size":2717,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-20T19:12:27.294Z","etag":null,"topics":["android","docker","fastapi","kotlin","postgresql","shopping-list"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shurshick.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-10T15:44:41.000Z","updated_at":"2026-06-20T17:22:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/shurshick/shopping-list","commit_stats":null,"previous_names":["shurshick/shopping-list-truenas","shurshick/shopping-list"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/shurshick/shopping-list","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shurshick%2Fshopping-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shurshick%2Fshopping-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shurshick%2Fshopping-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shurshick%2Fshopping-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shurshick","download_url":"https://codeload.github.com/shurshick/shopping-list/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shurshick%2Fshopping-list/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34852292,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","docker","fastapi","kotlin","postgresql","shopping-list"],"created_at":"2026-06-27T12:03:22.480Z","updated_at":"2026-06-27T12:03:22.953Z","avatar_url":"https://github.com/shurshick.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Список покупок\n\nAndroid-приложение и сервер синхронизации для совместных списков покупок. Сервер можно запустить на обычном Docker-сервере, VPS, домашнем Linux-сервере, NAS с Docker или через TrueNAS Custom App.\n\nПроект рассчитан на самостоятельное размещение: ваши списки, пользователи и настройки хранятся на вашем сервере, а Android-приложение синхронизируется с ним при запуске и после изменений.\n\n## Скриншоты\n\n\u003cp\u003e\n  \u003cimg src=\"docs/screenshots/android-main-dark.png\" alt=\"Главный экран Android-приложения\" width=\"180\" /\u003e\n  \u003cimg src=\"docs/screenshots/android-main-menu-dark.png\" alt=\"Основное меню Android-приложения\" width=\"180\" /\u003e\n  \u003cimg src=\"docs/screenshots/android-list-menu-dark.png\" alt=\"Меню управления списком\" width=\"180\" /\u003e\n  \u003cimg src=\"docs/screenshots/android-list-picker-dark.png\" alt=\"Выбор списка покупок\" width=\"180\" /\u003e\n  \u003cimg src=\"docs/screenshots/android-about-dark.png\" alt=\"О приложении\" width=\"180\" /\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n  \u003cimg src=\"docs/screenshots/admin-dashboard.png\" alt=\"Веб-интерфейс администратора\" width=\"620\" /\u003e\n\u003c/p\u003e\n\n## Основные возможности\n\n- регистрация и вход пользователей;\n- быстрый выбор тестового сервера `https://rust.bghitech.ru` на экране входа Android;\n- обязательное создание администратора при первом запуске сервера;\n- несколько списков покупок у одного пользователя;\n- общий доступ к спискам между зарегистрированными пользователями;\n- просмотр участников конкретного списка;\n- история действий по каждому списку с очисткой истории;\n- приглашение в список по одноразовой ссылке;\n- срок действия ссылки-приглашения, по умолчанию 7 дней;\n- переименование, копирование, очистка и удаление списков;\n- удаление списка у не-владельца отключает только его доступ;\n- добавление, редактирование, отметка и удаление товаров;\n- быстрое добавление товаров через Done/Enter на клавиатуре без закрытия поля ввода;\n- офлайн-очередь изменений для действий со списком и товарами;\n- идемпотентная отправка offline-операций, чтобы повтор после сетевого сбоя не создавал дубликаты;\n- внутренняя архитектура backend и Android разделена на более понятные слои без изменения UX и API;\n- понятный статус офлайн-режима, последней синхронизации и ожидающих действий;\n- отмена удаления товара;\n- разделение товаров на блоки \"Купить\" и \"Куплено\";\n- очистка, возврат купленных товаров или полная очистка списка;\n- справочник товаров с автопоиском и автоматическим пополнением при ручном добавлении позиции;\n- экран настроек Android-приложения с текущим сервером, темой оформления, безопасной сменой сервера и выходом из аккаунта;\n- основной список, который локально открывается первым при запуске приложения;\n- экран диагностики Android-приложения в настройках: проверка сервера, health endpoints, версия backend, состояние синхронизации и безопасное копирование отчёта;\n- светлая, тёмная и системная тема Android-приложения;\n- окно \"О приложении\" с версией, ссылкой на проект и проверкой обновлений;\n- проверка обновлений Android-приложения через GitHub Releases при запуске: если доступна новая APK-версия, показывается компактное уведомление со ссылкой на релиз;\n- отображение в админке версии Android-приложения, которую пользователь использовал при последней синхронизации;\n- защищенное хранение токена входа в Android через EncryptedSharedPreferences;\n- синхронизация при запуске приложения и после действий пользователя;\n- веб-мастер настройки сервера по адресу `/setup`;\n- CSRF-защита веб-мастера `/setup` и базовое ограничение частоты входа, регистрации и настройки;\n- автоматические миграции базы данных при запуске контейнера API;\n- расширенный `/health`, веб-страница администратора `/admin`, административная статистика `/admin/status` и очистка истории;\n- улучшенная админ-панель с общей навигацией, поиском, фильтрами, адаптивными таблицами и безопасными действиями над пользователями, списками и приглашениями;\n- публичная конфигурация сервера по адресу `/server-config`;\n- готовые Docker Compose-файлы для разных сценариев запуска.\n\n## Требования\n\n### Android\n\n- Минимальная версия Android: **Android 8.0 Oreo**.\n- Минимальный API: **26** (`minSdk = 26`).\n- Целевая версия сборки: **Android 15**, API **35** (`targetSdk = 35`).\n- Установка выполняется APK-файлом из раздела Releases.\n\n### Сервер\n\n- Docker и Docker Compose.\n- Доступ к порту API, по умолчанию `8000`.\n- Для доступа из интернета рекомендуется домен и HTTPS через reverse proxy.\n- Для хранения данных используется PostgreSQL.\n\nСервер можно запустить несколькими способами:\n\n- локальная сборка из исходников через `docker-compose.yml`;\n- сборка backend напрямую из GitHub через `docker-compose.github-build.yml`;\n- готовый GHCR-образ через `docker-compose.ghcr.yml`;\n- TrueNAS 25.04 Custom App через `docker-compose.truenas-custom.yml` с готовым GHCR-образом.\n\n## Состав проекта\n\n- `backend` - серверная часть на FastAPI и PostgreSQL.\n- `android` - Android-приложение на Kotlin и Jetpack Compose Material 3.\n- `docker-compose.yml` - локальный запуск сервера со сборкой из текущих файлов.\n- `docker-compose.github-build.yml` - запуск со сборкой backend напрямую из GitHub.\n- `docker-compose.ghcr.yml` - запуск готового backend-образа из GitHub Container Registry.\n- `docker-compose.truenas-custom.yml` - YAML для TrueNAS 25.04 Custom App без отдельного `.env`, использует готовый GHCR-образ API.\n- `docs` - подробные инструкции по API и вариантам развертывания.\n\n## Быстрый запуск через Docker Compose\n\n```bash\ngit clone https://github.com/shurshick/shopping-list.git\ncd shopping-list\ncp .env.example .env\n```\n\nЗаполните `.env`:\n\n```env\nPOSTGRES_PASSWORD=long-random-postgres-password\nJWT_SECRET=long-random-jwt-secret\nAPI_PORT=8000\nINVITE_TOKEN_HOURS=168\n```\n\nЗапустите:\n\n```bash\ndocker compose up -d --build\n```\n\nОткройте мастер настройки:\n\n```text\nhttp://server-ip:8000/setup\n```\n\n## Запуск через готовый Docker-образ\n\nЕсли нужен запуск без сборки backend на сервере, используйте `docker-compose.ghcr.yml`.\n\nСоздайте `.env` рядом с compose-файлом:\n\n```env\nPOSTGRES_PASSWORD=long-random-postgres-password\nJWT_SECRET=long-random-jwt-secret\nAPI_PORT=8000\nAPP_VERSION=latest\nINVITE_TOKEN_HOURS=168\n```\n\nЗапустите:\n\n```bash\ndocker compose -f docker-compose.ghcr.yml up -d\n```\n\nОбраз сервера публикуется в GitHub Container Registry:\n\n```text\nghcr.io/shurshick/shopping-list-api\n```\n\n## Запуск со сборкой напрямую из GitHub\n\nЭтот вариант удобен, если на сервере можно собирать Docker-образ:\n\n```bash\nmkdir -p shopping-list\ncd shopping-list\ncurl -L \\\n  -o docker-compose.yml \\\n  https://raw.githubusercontent.com/shurshick/shopping-list/main/docker-compose.github-build.yml\n```\n\nСоздайте `.env`:\n\n```env\nPOSTGRES_PASSWORD=long-random-postgres-password\nJWT_SECRET=long-random-jwt-secret\nAPI_PORT=8000\nINVITE_TOKEN_HOURS=168\n```\n\nЗапустите:\n\n```bash\ndocker compose up -d --build\n```\n\nПодробности: [docs/github-deploy.md](docs/github-deploy.md).\n\n## Запуск на TrueNAS\n\nДля TrueNAS 25.04.2.6 можно использовать Custom App или Install via YAML:\n\n1. Откройте в TrueNAS раздел приложений.\n2. Выберите Custom App или Install via YAML.\n3. Вставьте содержимое файла `docker-compose.truenas-custom.yml`.\n4. Запустите приложение.\n5. Откройте мастер настройки:\n\n```text\nhttp://truenas-ip:8000/setup\n```\n\nПодробная инструкция: [docs/truenas-custom-app.md](docs/truenas-custom-app.md).\n\n## Первичная настройка сервера\n\nПосле запуска откройте:\n\n```text\nhttp://server-ip:8000/setup\n```\n\nПри первом запуске сервер обязательно попросит создать администратора. Нужно указать email и пароль администратора, название приложения, внешний HTTPS-адрес и режим регистрации новых пользователей.\n\nПозже настройки можно менять на той же странице `/setup`, введя email и пароль администратора.\n\n## Android-приложение\n\nAPK публикуется в разделе [Releases](https://github.com/shurshick/shopping-list/releases).\n\nПри запуске Android-приложение проверяет последний релиз GitHub. Если опубликована новая APK-версия, вверху главного экрана появляется компактное уведомление с кнопкой открытия страницы релиза. Если GitHub недоступен, сеть отключена или ответ не удалось разобрать, приложение ничего не показывает и продолжает работать как обычно. APK не скачивается и не устанавливается автоматически.\n\nПри первом запуске приложения укажите адрес сервера, например:\n\n```text\nhttps://shopping.example.com\n```\n\nНа экране входа и регистрации можно включить чек-бокс `Использовать тестовый сервер`. В этом режиме приложение использует `https://rust.bghitech.ru`, а ручной адрес временно блокируется, но не теряется.\n\nЕсли пользователь уже вошёл в аккаунт, сервер нельзя незаметно переключить внутри активной сессии. В настройках показываются текущий адрес и тип сервера, а кнопка `Сменить сервер` сначала предупреждает о завершении текущей сессии и только потом выполняет выход из аккаунта.\n\nПосле входа приложение покажет выбранный список покупок. Кнопка `+` в верхней панели создает новый список, шестеренка открывает меню текущего списка, а основное меню содержит выбор списка, справочник товаров, настройки и сведения о приложении.\n\nВ меню списка доступны участники, переименование, копирование, очистка купленных товаров, возврат купленных товаров, полная очистка, удаление, доступ по email и одноразовая ссылка-приглашение. Нажатие на название товара открывает редактирование названия и количества.\n\nЕсли сервер временно недоступен, приложение сохраняет изменения в локальную очередь и отправляет их при следующей синхронизации. Внизу списка отображается количество действий, ожидающих отправки на сервер.\n\nНовые операции offline-очереди получают `client_operation_id`. Если сервер применил действие, но телефон не получил ответ, повторная отправка вернет прежний результат без создания дубликатов.\n\nПри синхронизации Android-приложение передает серверу версию клиента. В `/admin/users` видно последнюю версию приложения, код версии, платформу и время последней синхронизации пользователя. Старые клиенты без этих заголовков продолжают работать, для них поля остаются пустыми.\n\nТокен входа хранится в защищенном хранилище Android. При обновлении со старой версии приложение переносит ранее сохраненный токен из обычных настроек в защищенное хранилище и удаляет старое значение. Пароль после входа или регистрации не сохраняется.\n\nAPK из публичных релизов подписывается постоянным ключом проекта. Если на телефоне установлена ранняя сборка и Android сообщает о конфликте пакетов, удалите старую сборку один раз и установите свежий APK. Последующие публичные версии должны устанавливаться поверх.\n\n## Проверка Android-сборки\n\nAndroid-сборка проверяется в GitHub Actions workflow `Android CI`. Workflow сам устанавливает JDK 17, использует Gradle cache, делает Gradle wrapper исполняемым и запускает:\n\n```bash\n./gradlew assembleDebug --stacktrace\n```\n\nОтсутствие Java/JDK в локальном окружении разработчика не считается ошибкой исходного кода. Если нужно собрать приложение локально, установите JDK 17 и запустите команду из папки `android`.\n\n## Проверка серверной части\n\nBackend проверяется отдельным GitHub Actions workflow `Backend CI`: устанавливается Python 3.12, зависимости сервера и тестов, запускаются pytest-тесты и Docker-сборка backend-образа.\n\nЛокальная проверка:\n\n```bash\npython -m pytest backend/tests\ndocker build backend\n```\n\nТесты покрывают первичную настройку, запрет регистрации до настройки, вход с неверным паролем, rate limit, права администратора, запрет доступа к чужому списку, одноразовые приглашения, replay offline-операций, публичную конфигурацию без секретов и CSRF-защиту `/setup`.\n\n## Доступ из интернета\n\nДля доступа извне рекомендуется использовать домен и HTTPS через reverse proxy: Nginx Proxy Manager, Caddy, Traefik или аналогичный инструмент.\n\nНе публикуйте API в интернет без HTTPS: приложение передает email, пароль и токены авторизации.\n\nСервер содержит базовое in-memory ограничение частоты запросов для входа, регистрации и мастера настройки. Оно помогает от случайного перебора паролей и повторных попыток, но сбрасывается при перезапуске контейнера. Для домашнего сервера этого достаточно как первого уровня защиты, а для публичного нагруженного сервера лучше дополнительно использовать HTTPS, reverse proxy и внешние ограничения на уровне прокси.\n\nВеб-мастер `/setup` использует CSRF-токен и проверку `Origin`/`Referer` для HTML-формы. Мобильный API с Bearer-токеном CSRF-токен не требует.\n\n## Обновление\n\nЕсли сервер запущен через готовый образ:\n\n```bash\ndocker compose -f docker-compose.ghcr.yml pull\ndocker compose -f docker-compose.ghcr.yml up -d\n```\n\nЕсли сервер собирается из GitHub:\n\n```bash\ndocker compose build --pull\ndocker compose up -d\n```\n\nДля TrueNAS Custom App обновите YAML при необходимости и перезапустите приложение.\n\nКонтейнер API применяет миграции базы данных автоматически перед запуском сервера.\n\n## Эксплуатация и диагностика v1.4.0\n\nВ релизе `v1.4.0` добавлены отдельные инструменты для обслуживания self-hosted сервера:\n\nВ актуальных версиях эти разделы доступны прямо из веб-интерфейса `/admin` после входа администратором.\n\n- `GET /health/live` - быстрая проверка, что процесс API запущен.\n- `GET /health/ready` - проверка готовности API, подключения к БД и состояния миграций.\n- `GET /health/db` - безопасная проверка БД без раскрытия строки подключения.\n- `GET /metrics` - безопасные счетчики в JSON без email, токенов и секретов.\n- `GET /admin/users` - список пользователей, блокировка, разблокировка и смена пароля.\n- `GET /admin/lists` - просмотр списков, архивирование и восстановление.\n- `GET /admin/invites` - просмотр и отзыв invite-ссылок.\n- `GET /admin/system` - версия backend, БД, Alembic revision, uptime и режим регистрации.\n- `GET /admin/logs` и `GET /admin/diagnostics` - последние события и диагностическая сводка.\n\nCLI-команды обслуживания:\n\n```bash\npython -m app.cli backup --output backup.json\npython -m app.cli backup --output backup-with-auth.json --include-auth-hashes\npython -m app.cli restore --input backup.json\npython -m app.cli db-status\n```\n\nПеред обновлением сервера рекомендуется сделать backup, обновить Docker image, перезапустить API и проверить `/health/ready` и `/admin/system`.\n\nПодробные инструкции:\n\n- [Эксплуатация сервера](docs/operations.md)\n- [Backup и restore](docs/backup_restore.md)\n\n## Полезные ссылки\n\n- [Развертывание серверной части с GitHub](docs/github-deploy.md)\n- [Развертывание через TrueNAS Custom App](docs/truenas-custom-app.md)\n- [Эксплуатация сервера](docs/operations.md)\n- [Backup и restore](docs/backup_restore.md)\n- [Описание API](docs/api.md)\n- [Архитектура проекта](docs/architecture.md)\n- [Безопасность](SECURITY.md)\n- [Релизы Android APK и серверных архивов](https://github.com/shurshick/shopping-list/releases)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshurshick%2Fshopping-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshurshick%2Fshopping-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshurshick%2Fshopping-list/lists"}