{"id":28053371,"url":"https://github.com/fshmidt/game-site","last_synced_at":"2026-04-08T11:32:13.338Z","repository":{"id":147208600,"uuid":"599206549","full_name":"fshmidt/Game-Site","owner":"fshmidt","description":"6 containerized services (Go backend, Postgres DB, Redis DB, Vue3 Account client, html/js/css Game App \u0026  Traefik)  work together for Autentificate, Authorize, Update Profile details,  Save profile picture in Google Cloud Storage \u0026 Edit it at Frontend side.  Now there's a second gaming Front-end.","archived":false,"fork":false,"pushed_at":"2023-02-25T07:16:47.000Z","size":24068,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-12T03:15:30.055Z","etag":null,"topics":["api","css","docker-compose","full-stack","gin","golang","google-cloud-storage","html","javascript","jwt-authentication","makefile","postgresql","redis","rsa-cryptography","unit-testing","validation","vue3","vue3-component"],"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/fshmidt.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":"2023-02-08T17:10:48.000Z","updated_at":"2023-02-21T16:39:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"239ad8e5-7cef-491d-8776-d071eab58a69","html_url":"https://github.com/fshmidt/Game-Site","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fshmidt/Game-Site","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fshmidt%2FGame-Site","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fshmidt%2FGame-Site/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fshmidt%2FGame-Site/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fshmidt%2FGame-Site/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fshmidt","download_url":"https://codeload.github.com/fshmidt/Game-Site/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fshmidt%2FGame-Site/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31554090,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T10:21:54.569Z","status":"ssl_error","status_checked_at":"2026-04-08T10:21:38.171Z","response_time":54,"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":["api","css","docker-compose","full-stack","gin","golang","google-cloud-storage","html","javascript","jwt-authentication","makefile","postgresql","redis","rsa-cryptography","unit-testing","validation","vue3","vue3-component"],"created_at":"2025-05-12T03:15:25.927Z","updated_at":"2026-04-08T11:32:13.294Z","avatar_url":"https://github.com/fshmidt.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Мини-игра с регистрацией Eugenes.world\n\n\u003c!-- ToC start --\u003e\n# Содержание\n\n1. [Описание](#Описание)\n1. [Реализация](#Реализация)\n1. [Endpoints](#Endpoints)\n1. [Запуск](#Запуск)\n1. [Примеры](#Примеры)\n\u003c!-- ToC end --\u003e\n\n# Описание\n\nСайт с игрой на зрительную память, написанной на JavaScript, Сервисом Аутентификации и Авторизации, написанном на Vue3, backend-ом, написанном на Golang, через который оба фронта подключаются к контейнезированной бд на Postgres, а так же Vue3 подключается к контейнезированному Redis  и облачному хранилищу Google Cloud. Все 6 контейнеров общаются через reverse-proxy.\nПосмотреть и поиграть: [eugenes.world](http://eugenes.world).\n\n# Реализация\n\n- Следование дизайну REST API.\n- Подход \"Чистой Архитектуры\" и техника внедрения зависимости.\n- Частичное покрытие юнит-тестами.\n- Работа с фреймворком [gin-gonic/gin](https://github.com/gin-gonic/gin).\n- Работа с СУБД Postgres с использованием библиотеки [sqlx](https://github.com/jmoiron/sqlx) и написанием SQL запросов.\n- Работа с Redis для хранения токенов авторизации.\n- Реализация коротких одноразовых и долгих обновляемых токенов авторизации.\n- Работа с JWT.\n- Работа с API Google Cloud.\n- SPA-приложение для авторизации и редактирования аватарки с использованием фрейворка Vue3.\n- Запуск из Docker.\n**Структура проекта:**\n```\n.\n├── pkg\n│   ├── handler         // обработчики запросов\n│   │   └── middleware  // middleware для отслеживания авторизации\n│   ├── service         // бизнес-логика\n│   └── repository      // взаимодействие с БД и облачным хранилищем\n├── cmd                 // точка входа в приложение\n├── migrations          // SQL файлы с миграциями\n├── models              // модели и интерфейсы\n│   ├── apperrors       // обработчики ошибок\n│   └── mocks           // моки\n├── account-client      // SPA-приложение для Авторизации на Vue3\n├── parallax            // html/Js/CSS игра-сайт и использованием эффекта parallax\n\n```\n\n# Endpoints\n\n- GET /api/account/me - получение сведений о пользователе\n    - Тело запроса:\n        - email - почта пользователя\n        - password - хешированный пароль пользователя\n- GET /api/account/topscorers - получение списка ТОП-7 пользователей по результатам игры\n\n- PUT /api/account/details - изменение данных пользователя\n    - Тело запроса:\n        - email - почта пользователя(обязательно)\n        - username - имя пользователя\n        - score - результат пользователя\n        - image_url - ссылка на аватар пользователя\n        - website - сайт пользователя\n        - password - хэшированный пароль пользователя\n\n- POST /api/account/tokens - обновление 3-хдневного токена\n    - Тело запроса:\n        - refreshToken - 3-хдневный обновляемый авторизационный токен\n- POST /api/account/image - загрузка картинки пользователя\n    - Тело запроса:\n        - form-data - imageFile - файл картинки\n- POST /api/account/signout - выход пользователя с сайта, удаление всех текущих авторизационных токенов\n    - Тело запроса:\n        - refreshToken - 3-хдневный обновляемый авторизационный токен\n- POST /api/account/signup - регистратрация нового пользователя\n    - Тело запроса:\n        - email - почта пользователя\n        - username - имя пользователя\n        - password - хэшированный пароль пользователя\n- POST /api/account/signin - вход пользователя в свою учетную запись\n    - Тело запроса:\n        - email - почта пользователя\n        - password - хэшированный пароль пользователя\n\n- DELETE /api/account/image - удаление картинки пользователя\n\n# Запуск\n\n```\ndocker compose up\n```\n\nЕсли приложение запускается впервые, необходимо инициировать создание приватного и публичного ключа и запустить миграции к базе данных:\n\n```\nmake init\n```\n\n\n# Примеры\n\nЗапросы сгенерированы из Postman.\n\n### 1. GET /api/account/me\n**Тело ответа:**\n```\n{\n    \"user\": {\n        \"uid\": \"7327af01-c8bc-466c-9bfa-fa144bdb2f77\",\n        \"email\": \"bob@bob.com\",\n        \"username\": \"dob\",\n        \"imageUrl\": \"\",\n        \"website\": \"\",\n        \"score\": 0\n    }\n}\n```\n### 2. GET /api/account/topscorers\n**Запрос:**\n\n**Тело ответа:**\n```\n{\n    \"topscorers\": [\n        {\n            \"uid\": \"00000000-0000-0000-0000-000000000000\",\n            \"email\": \"\",\n            \"username\": \"bob\",\n            \"imageUrl\": \"\",\n            \"website\": \"\",\n            \"score\": 42\n        },\n        {\n            \"uid\": \"00000000-0000-0000-0000-000000000000\",\n            \"email\": \"\",\n            \"username\": \"tom\",\n            \"imageUrl\": \"\",\n            \"website\": \"\",\n            \"score\": 20\n        },\n        {\n            \"uid\": \"00000000-0000-0000-0000-000000000000\",\n            \"email\": \"\",\n            \"username\": \"dob\",\n            \"imageUrl\": \"\",\n            \"website\": \"\",\n            \"score\": 8\n        }\n    ]\n}\n```\n\n### 3. PUT /api/account/details\n**Тело запроса:**\n```\n{\n    \"email\": \"bob@bob.com\",\n     \"score\" : 100\n}\n```\n\n**Тело ответа:**\n```\n{\n    \"user\": {\n        \"uid\": \"7327af01-c8bc-466c-9bfa-fa144bdb2f77\",\n        \"email\": \"bob@bob.com\",\n        \"username\": \"\",\n        \"imageUrl\": \"\",\n        \"website\": \"\",\n        \"score\": 100\n    }\n}\n```\n\n### 3. POST /api/account/signup\n\n**Тело запроса:**\n```\n{\n    \"username\": \"bob\",\n    \"email\": \"bob@bob.com\",\n    \"password\":\"password\"\n}\n```\n\n**Тело ответа:**\n```\n{\n    \"tokens\": {\n        \"idToken\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVpZCI6IjczMjdhZjAxLWM4YmMtNDY2Yy05YmZhLWZhMTQ0YmRiMmY3NyIsImVtYWlsIjoiYm9iQGJvYi5jb20iLCJ1c2VybmFtZSI6ImRvYiIsImltYWdlVXJsIjoiIiwid2Vic2l0ZSI6IiIsInNjb3JlIjowfSwiZXhwIjoxNjc3MzA4Nzc5LCJpYXQiOjE2NzczMDc4Nzl9.gV8X4FrOW1KmFq4h-J2vGyPQio0zb2bNmZCLZxZCoierwL9BFf9_f3e0DqoT-D3X6rVLmsZigrIw94nmbqdLO66Niil69c6oCR1gWA4aJNAdJZ38d3BgXaABvRsmgwTvAXcbqahA3nU7vObm9oEL5Dg6ENBInybFPhY6rJUb_nNT7yuEWmjOKyxbb9yorqDFYSRMdWOWddQ0netS2xJCW4S382dC_g6InJlCdfSdLABFNavXEpIgsMf0O0KKWsPTJ_JlatIQIZpLfu-ItJER5NHzivXCLJpMWjGjUqEX7RnGBLzIhZ75Ecl3euqbW4Nbt8VrOYHP4VW8m3dUmmi4pw\",\n        \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI3MzI3YWYwMS1jOGJjLTQ2NmMtOWJmYS1mYTE0NGJkYjJmNzciLCJleHAiOjE2Nzc1NjcwNzksImp0aSI6Ijc5Y2ZlNTViLTM5M2YtNDY3MS1iNDNhLWU5MDY4YzNjN2EzNCIsImlhdCI6MTY3NzMwNzg3OX0.k9uEVIovZulwAr3pw0-2EerHaaPS7-wZV0Diat86LPE\"\n    }\n}\n```\n\n### 4. POST /api/account/signout\n\n**Тело ответа:**\n```\n{\n    \"message\": \"user signed out successfully!\"\n}\n```\n\n### 5. POST /api/account/signin\n\n**Тело запроса:**\n```\n{\n    \"email\": \"bob@bob.com\",\n    \"password\":\"password\"\n}\n```\n\n**Тело ответа:**\n```\n{\n    \"tokens\": {\n        \"idToken\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVpZCI6IjczMjdhZjAxLWM4YmMtNDY2Yy05YmZhLWZhMTQ0YmRiMmY3NyIsImVtYWlsIjoiYm9iQGJvYi5jb20iLCJ1c2VybmFtZSI6IiIsImltYWdlVXJsIjoiIiwid2Vic2l0ZSI6IiIsInNjb3JlIjoxMDB9LCJleHAiOjE2NzczMDk2NTAsImlhdCI6MTY3NzMwODc1MH0.Kl6FFDaomn3I0N6o9Bp10kAo3PfTOKMGWpkiEomW9ocFuNQdvdaR35CjyJ6bzQSTCtOp_iZ8-gVFzIwQ1R_CIufsYqhwEgvxk6wLNkis8sEDDW64wgSU93hbN91TJ-RI8ElDnCmkBtRHlHHVjJjWp5EjkEs9uZM8gmCydMgJp1ML9mkgaKdq6tnjpDCQDDsjx_f21XoPmSeU8B-j1ZInCUPY4h-Xl2xZeNYwzbHn7-QDrRbiAFxjaEWbRs7DRaKOlevctRybtyjVMex23_f_yTelWip7XwYB1yu6F37cculjF_Zn6d_aveAb0ptTiLVK5AWPzkr7aUwYcEtvavFTmA\",\n        \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI3MzI3YWYwMS1jOGJjLTQ2NmMtOWJmYS1mYTE0NGJkYjJmNzciLCJleHAiOjE2Nzc1Njc5NTAsImp0aSI6IjEwZjE1MzAwLWZlYTctNGIzNC05MTdmLTkzMzZkM2FmM2Y2YSIsImlhdCI6MTY3NzMwODc1MH0.DWRyzwl35IipuyfJ6-oz0GnXm6Bvz-JD5lxpRhp_jX0\"\n    }\n}\n```\n\n### 6. POST /api/account/tokens\n\n**Тело запроса:**\n```\n{\n    \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI3MzI3YWYwMS1jOGJjLTQ2NmMtOWJmYS1mYTE0NGJkYjJmNzciLCJleHAiOjE2Nzc1Njc5NTAsImp0aSI6IjEwZjE1MzAwLWZlYTctNGIzNC05MTdmLTkzMzZkM2FmM2Y2YSIsImlhdCI6MTY3NzMwODc1MH0.DWRyzwl35IipuyfJ6-oz0GnXm6Bvz-JD5lxpRhp_jX0\"\n}\n```\n**Тело ответа:**\n```\n{\n    \"tokens\": {\n        \"idToken\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVpZCI6IjczMjdhZjAxLWM4YmMtNDY2Yy05YmZhLWZhMTQ0YmRiMmY3NyIsImVtYWlsIjoiYm9iQGJvYi5jb20iLCJ1c2VybmFtZSI6IiIsImltYWdlVXJsIjoiIiwid2Vic2l0ZSI6IiIsInNjb3JlIjoxMDB9LCJleHAiOjE2NzczMDk3ODAsImlhdCI6MTY3NzMwODg4MH0.OQW0MPD3QLf58RB404vVWMpbhaJPy0-E36wHVof25YYK9MDVnDLmJ6Vyv3WAeV6Byjq1XgDE23bT6rv7gn8MQXNPiVdpIqdWLEorgwerd4Af35OGcITrInRyCHG02jGBqpShXmMGDqLDZLDkuaUVA4X1ed1b_0OydmuenanY4nDFxAzPYmjWcjIOKdvERvLpCGGjbj4b2FtRnlxETdSdjdEUTs4dnA-HjTuMVX-bIII1SbT6ii6wTnZRjkp8MDfgXCzycVI5ndjt-iL_ce8aXsz-F3RXh7kyOTCwu9gUsAr9V2hVH2dxc-ojyyIiXNPHEtgCSe1DDe1GBsevbY4IFA\",\n        \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI3MzI3YWYwMS1jOGJjLTQ2NmMtOWJmYS1mYTE0NGJkYjJmNzciLCJleHAiOjE2Nzc1NjgwODAsImp0aSI6IjgzYzgzN2YxLTNkNDMtNDhjOC05NDUyLTk1ZjEyNTQ0NjM4MiIsImlhdCI6MTY3NzMwODg4MH0.6V-IAKAxzSRS2RupOg29iTHzKzNTCNK_9mxIAaVeYVY\"\n    }\n}\n\n```\n\n### 7. POST /api/account/image\n\n**Тело запроса:**\n```\nform-data - imageFile\n```\n**Тело ответа:**\n```\n{\n    \"imageUrl\": \"https://storage.googleapis.com/gamesite_profile_images/d0b377db-f504-40ea-9866-130bc410a48c\",\n    \"message\": \"success\"\n}\n```\n\n### 8. DELETE /api/account/image\n\n**Тело ответа:**\n```\n{\n    \"message\": \"success\"\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffshmidt%2Fgame-site","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffshmidt%2Fgame-site","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffshmidt%2Fgame-site/lists"}