{"id":15198800,"url":"https://github.com/gvozdenkov/wish-magic","last_synced_at":"2026-03-07T16:33:52.610Z","repository":{"id":246230295,"uuid":"789878627","full_name":"gvozdenkov/wish-magic","owner":"gvozdenkov","description":"Wishlist \u0026 crowdfunding service / backend + frontend","archived":false,"fork":false,"pushed_at":"2024-07-15T14:45:26.000Z","size":1910,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-10T19:26:12.604Z","etag":null,"topics":["nest","postgresql","typeorm","typescript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/gvozdenkov.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}},"created_at":"2024-04-21T19:47:31.000Z","updated_at":"2024-07-15T14:49:43.000Z","dependencies_parsed_at":"2024-07-13T20:01:15.072Z","dependency_job_id":"19f9d367-df15-42ba-a714-47937f10a1ca","html_url":"https://github.com/gvozdenkov/wish-magic","commit_stats":{"total_commits":27,"total_committers":2,"mean_commits":13.5,"dds":0.03703703703703709,"last_synced_commit":"576314e6e4470a66a6b1718e63f858a669377e42"},"previous_names":["gvozdenkov/web-plus-docker-and-compose","gvozdenkov/wish-magic"],"tags_count":0,"template":false,"template_full_name":"yandex-praktikum/web-plus-docker-and-compose","purl":"pkg:github/gvozdenkov/wish-magic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvozdenkov%2Fwish-magic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvozdenkov%2Fwish-magic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvozdenkov%2Fwish-magic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvozdenkov%2Fwish-magic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gvozdenkov","download_url":"https://codeload.github.com/gvozdenkov/wish-magic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvozdenkov%2Fwish-magic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30221511,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T14:02:48.375Z","status":"ssl_error","status_checked_at":"2026-03-07T14:02:43.192Z","response_time":53,"last_error":"SSL_read: 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":["nest","postgresql","typeorm","typescript"],"created_at":"2024-09-28T01:41:30.402Z","updated_at":"2026-03-07T16:33:52.581Z","avatar_url":"https://github.com/gvozdenkov.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wish magic\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#\" target=\"blank\"\u003e\u003cimg src=\"README_static/logo.svg\" width=\"150\" alt=\"gifty logo\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\" style='font-weight: bold;'\u003ewishlist and crowdfunding service\u003c/p\u003e\n\n## Описание\n\nУчебыный cрвис создания листов желаний. Каждый участник может создавать свои желания и скидываться\nна желания других участников.\n\n- Бэкенд на `Nest`\n- `TypeORM` для работы с базой\n- База данных `PostgreSQL`\n- Фронтенд `React` разрабатывался другой командой\n\n![swagger docs](README_static/swagger.png)\n\n## Техники\n\n:boom: Применил подход `Contract first` в работе с API (вдохновило\n[видео Глеба Михеева](https://www.youtube.com/watch?v=-mzzT0b9K54)). Подход понравился тем, что\nкоманды бэкенда, фронтенда и QA могут вести работу параллельно, потому что у них единый контракт\nAPI.\n\n:boom: Погрузился в спецификацию `OpenAPI`. Создал в онлайн редакторе\n[swagger editor](https://editor-next.swagger.io/) файл с описанием API\n[`openapi.yaml`](https://github.com/gvozdenkov/wish-magic/blob/main/backend/docs/openapi.yaml). По\nнему создал REST API бэкенда и ручки фронтенда. Бэкенд на `Nest` автоматически хостит файл\nспецификации по адресу http://localhost:4000/api/v1/docs. Декораторы `Nest` не очень понравились,\nпотому что замусоривают код. К тому же файл `openapi.yaml` можно довольно легко автоматически\nлокализовать на несколько языков, для интернациональных команд.\n\n:boom: `entities` являются единым источником истины. Вся валидация происходит в `entities`. Все\n`DTO` схемы только используют части `entities` для описания набора необходимых полей.\n\n:boom: Везде использую `DTO` для описания структур передаваемых данных. Использовал подход при\nкотором в ответ сервера могут попасть только те поля, которые специально указаны в `DTO`. Это\nдополнительная защита от того, чтобы в ответе случайно не оказались лишние поля:\n\n```ts\n// Every property is excluded by default unless you mark it as exposed\napp.useGlobalInterceptors(\n  new ClassSerializerInterceptor(app.get(Reflector), {\n    strategy: 'excludeAll',\n    excludeExtraneousValues: true,\n  }),\n);\n```\n\n:boom: Использую валидацию `.env` переменных с помощью схем `joi` в `ConfigModule`. Тоже\nдополнительная защита от запуска приложения с неправильным набором переменных окружения.\n\n:boom: Вынес подкючение к базе данных в отдельный модуль и настроил использование валидированных\nпеременных окружения.\n\n:boom: Сервис докеризован. При запуске стартует 4 контейнера: бэкенд, база, фронтед и `adminer` для\nмониторинга базы. Настроены 2 файла `docker compose`: для локальной разработки `compose.dev.yaml` и\nдля деплоя `compose.prod.yaml`. Версия для деплоя использует `volume` для хранения данных базы на\nдиске сервера. Также настроены сети для лучшей безопасности.\n\n```ts\n@Module({\n  imports: [\n    TypeOrmModule.forRootAsync({\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (configService: ConfigService) =\u003e ({\n        type: 'postgres',\n        host: configService.get('POSTGRES_HOST'),\n        port: configService.get('POSTGRES_PORT'),\n        username: configService.get('POSTGRES_USER'),\n        password: configService.get('POSTGRES_PASSWORD'),\n        database: configService.get('POSTGRES_DB'),\n        synchronize: true,\n        autoLoadEntities: true,\n      }),\n    }),\n  ],\n})\nexport class DatabaseModule {}\n```\n\n## Local Development with Docker\n\n```bash\ngit clone git@github.com:gvozdenkov/wish-magic.git\n\ncd wish-magic\n\ncp backend/.env.development.example backend/.env.development\n\ndocker compose -f compose.dev.yaml up --build\n# or with Makefile\nmake run-dev\n```\n\n## Планы по улучшению\n\n- [ ] Выпилить `pm2` из продакшен пайплайна. Подъём упавших контейнеров переложить на `docker`\n\n- [ ] Внедрить монорепозиторий на [`pnpm worksapce`](https://pnpm.io/workspaces) и\n      [`Nx`](https://nx.dev/getting-started/intro)\n\n- [ ] Переписать фронтенд с устаревшего `create react app` на [`remix.run`](https://remix.run/)\n\n- [ ] Внедрить [`FSD`](https://feature-sliced.design/ru/docs) архитектуру на фронтенде для лучшей\n      масштабируемости и лучшего разделения кода.\n\n- [ ] Написать unit и e2e API тесты.\n\n- [ ] Настроить `CI/CD` на `GitHub Actions` для автоматизации деплоя продакшн образов в хранилище\n      образов `GitHub` или `DockerHub` для автоматизации деплоя на сервер.\n\n## Контакты\n\n- Author - Arty Gvozdenkov\n- Telegram - [@gvozdenkov](https://t.me/gvozdenkov)\n\n## License\n\n[MIT licensed](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvozdenkov%2Fwish-magic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgvozdenkov%2Fwish-magic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvozdenkov%2Fwish-magic/lists"}