{"id":33332396,"url":"https://github.com/iiivanpopov/beger","last_synced_at":"2026-04-13T04:08:54.188Z","repository":{"id":324560951,"uuid":"1060192760","full_name":"iiivanpopov/beger","owner":"iiivanpopov","description":"Beger Application Monorepo","archived":false,"fork":false,"pushed_at":"2025-11-16T15:23:21.000Z","size":1583,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-16T17:23:28.264Z","etag":null,"topics":["bun","docker","docker-compose","hono","postgresql","react","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":false,"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/iiivanpopov.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":"2025-09-19T14:16:58.000Z","updated_at":"2025-11-16T15:23:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/iiivanpopov/beger","commit_stats":null,"previous_names":["iiivanpopov/beger"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/iiivanpopov/beger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iiivanpopov%2Fbeger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iiivanpopov%2Fbeger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iiivanpopov%2Fbeger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iiivanpopov%2Fbeger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iiivanpopov","download_url":"https://codeload.github.com/iiivanpopov/beger/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iiivanpopov%2Fbeger/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31739118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T03:27:07.512Z","status":"ssl_error","status_checked_at":"2026-04-13T03:26:53.610Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["bun","docker","docker-compose","hono","postgresql","react","typescript"],"created_at":"2025-11-20T21:02:53.141Z","updated_at":"2026-04-13T04:08:54.181Z","avatar_url":"https://github.com/iiivanpopov.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Beger\n\n## PREVIEW\n\n[Youtube](https://youtu.be/rrAxZSjM4gM)\n\n`Beger` - внутрішня система для обліку тестування друкованих плат і їх ремонту.\n\nПроєкт оцифровує звичний робочий процес: внесення результатів тестування, фіксацію ремонтів та керування користувачами в одному місці.\n\n## Призначення\n\nСистема потрібна для того, щоб не вести записи вручну в різних джерелах, а зберігати їх у спільній структурованій базі з розмежуванням доступу.\n\n## Ключові можливості\n\n- вхід до системи за обліковим записом;\n- розмежування ролей `admin` і `user`;\n- внесення результатів тестування плат;\n- внесення записів про ремонт плат;\n- перегляд останніх власних записів;\n- керування працівниками для адміністратора;\n- використання Google Sheets для зручного редагування варіантів плат;\n- локалізація інтерфейсу: `uk`, `en`, `ru`.\n\n## Ключові моменти в роботі системи\n\n- результати тестування та ремонти ведуться окремо, бо це різні робочі сценарії;\n- звичайний робочий працює лише зі своїми записами;\n- адміністратор бачить загальні списки та керує користувачами;\n- у формах використовуються довідники назв плат і дефектів;\n- для щоденної роботи користувачеві показуються його останні 10 записів за останню добу, а для адміністратора є окремі загальні списки з посторінковим переглядом.\n\n## Стек проєкту\n\n### Клієнтська частина\n\n- React 19\n- TypeScript\n- Vite\n- TanStack Router\n- TanStack Query\n- React Hook Form\n- Valibot\n- React Intl\n- Ky\n- CSS Modules\n\n### Серверна частина\n\n- Bun\n- Hono\n- Drizzle ORM\n- Valibot\n\n### Інфраструктура\n\n- PostgreSQL 18\n- Redis 8\n- Nginx\n- Docker Compose\n\n## Проблемні місця і прийняті рішення\n\n1. Єдиний набір типів між клієнтською і серверною частинами. Проблема: у таких проєктах легко отримати розбіжності між типами даних на клієнті та на сервері. Рішення: типи й схеми експортуються з серверної частини через `apps/backend/public`, а пакет `apps/shared` використовує їх і в клієнтській частині.\n\n2. Робота з таблицями через Google Sheets без зашивання значень у код. Проблема: назви плат і дефекти змінюються, а тримати їх у коді незручно. Рішення: сервер отримує CSV з Google Sheets, перетворює його на довідники й віддає клієнтові готові значення для автодоповнення.\n\n3. Кешування довідників у Redis. Проблема: звернення до Google Sheets при кожному запиті було б повільним і залежним від зовнішнього сервісу. Рішення: довідники кешуються на сервері, тому інтерфейс отримує їх швидко, а навантаження на зовнішнє джерело зменшується.\n\n4. Безпечне видалення записів. Проблема: звичайний користувач не повинен видаляти чужі записи або довільно змінювати історію. Рішення: для ролі `user` застосовано окремі безпечні сценарії видалення лише власних записів за останню добу, тоді як `admin` має повний доступ.\n\n5. Автоматизація початкового запуску. Проблема: після розгортання потрібно не забути застосувати міграції та створити адміністратора. Рішення: у робочому середовищі сервер під час запуску виконує міграції та додає адміністратора, якщо його ще немає.\n\n## Структура репозиторію\n\n```text\napps/\n  backend/   API, авторизація, бізнес-логіка, схема бази даних, міграції\n  frontend/  інтерфейс, сторінки, форми, маршрутизація\n  shared/    спільні типи й контракти між частинами системи\nassets/      зображення для документації\n```\n\n## Які дані зберігає система\n\n### Результати тестування\n\n- `pcbName` - назва плати\n- `date` - дата запису\n- `firstTry` - кількість плат, що пройшли з першого разу\n- `failed` - кількість браку\n- `total` - загальна кількість\n\n### Ремонти\n\n- `pcbName` - назва плати\n- `defect` - дефект\n- `note` - примітка\n- `date` - дата запису\n\n## Запуск\n\n### 1. Створити `.env`\n\n```bash\ncp .env.example .env\n```\n\nПотрібно заповнити щонайменше такі змінні:\n\n- `PORT`\n- `JWT_ACCESS_SECRET`\n- `JWT_REFRESH_SECRET`\n- `ADMIN_PASSWORD`\n- `DB_USER`\n- `DB_PASSWORD`\n- `SHEET_URL`\n\n### 2. Запустити контейнери\n\n```bash\ndocker compose up --build -d\n```\n\nПісля запуску будуть доступні:\n\n- веб-інтерфейс: `http://localhost`\n- API: `http://localhost:\u003cPORT\u003e/api`\n\nТипове значення `PORT` у прикладі - `5333`.\n\nЯкщо змінюєте `PORT`, потрібно також оновити `apps/frontend/nginx.conf`, бо Nginx переспрямовує запити до API саме на цей порт.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiiivanpopov%2Fbeger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiiivanpopov%2Fbeger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiiivanpopov%2Fbeger/lists"}