[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBJWYMTJWTSNJ05X7HTZYF":3,"skill-same:01M6CBJWYMTJWTSNJ05X7HTZYF":89},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":13,"repositoryHtmlUrl":27,"repositoryHomepageUrl":6,"ownerHtmlUrl":28,"ownerBlogUrl":6,"ownerDescription":29,"updatedAt":30,"install":31,"resources":44},"01M6CBJWYMTJWTSNJ05X7HTZYF","00-overview",null,"devwinsoft\u002Fdevian","devwinsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F22570160?v=4","01M6C6RR8W05NH8NPKQNCE3Q72","maoshy","01M6C6RRDJ5TJJCZXRTY801YDH",0,"MIT","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian-unity\u002F50-mobile-package\u002F28-shop-system\u002F00-overview\u002FSKILL.md",[],[18,19],"overview","00 overview","2026-11-10 10:12:30",false,"# 28-shop-system — Overview\n\nStatus: ACTIVE\nAppliesTo: v10\n\nShop System은 `SHOP_CATALOG_TYPE` 기반 카탈로그(`DAILY\u002FCHEST\u002FPURCHASE\u002FGOLD\u002FEVENT`)를 관리하고,\n`shop_item_id` 기준 구매\u002F제한\u002Frefresh 정책을 처리한다.\n카탈로그 인스턴스는 하드코딩이 아니라 `SHOP_CATALOG` 테이블 row를 읽어서 생성한다.\n일반 카탈로그의 자동 refresh는 `SHOP_CATALOG.auto_refresh_days`를 사용한다.\n`SHOP_CATALOG.unlock_msg_id`가 설정된 카탈로그는 초기 `IsLocked=true`로 시작하며,\n`unlock_op_type\u002Funlock_value` 조건을 `GameMessageManager` 누적 stat으로 평가해 해금한다.\n`SHOP_ITEM_DAILY`는 초기화\u002Frefresh 시 `currency_type=FREE\u002FADS` 상품을 항상 포함하고, 나머지 대상에서 `select_rate` 규칙으로 5개 상품을 선택해 최종 snapshot을 생성한다.\n`CHEST\u002FPURCHASE\u002FGOLD`는 각 `SHOP_*` 테이블의 모든 상품을 생성한다.\n`EVENT`는 `SHOP_ITEM_EVENT.start_time\u002Fend_time` 서버 UTC 시간 구간 안에 있는 상품만 생성한다.\n`SHOP_ITEM_DAILY`는 정적 row에 `amount_min\u002Famount_max`를 두고, 초기화\u002Frefresh 시 min\u002Fmax 범위에서 runtime `amount`를 뽑아 snapshot에 저장한다.\n`SHOP_ITEM_DAILY.unit_price`는 단가이며, 실제 구매 가격은 `unit_price * snapshot.amount`에 discount를 적용한 값이다.\n`SHOP_ITEM_DAILY`의 최종 snapshot(FREE\u002FADS 포함, remainCount\u002FdiscountType\u002Famount 포함)은 `daily.dailyCatalogProducts` 하나에 저장한다.\n일반 카탈로그의 구매 제한 자동 refresh는 카탈로그 저장 버킷의 `autoRefreshUtcMs`(다음 refresh 시각) + `auto_refresh_days` 규칙으로 처리된다.\n`EVENT`는 `auto_refresh_days` 대신 다음 `start_time\u002Fend_time` 경계 시각을 `autoRefreshUtcMs`로 저장해 refresh를 예약한다.\nADS\u002FFREE 상품 리필은 카탈로그별 저장 버킷의 `adsRefreshUtcMs`(다음 ADS\u002FFREE refill 시각)으로 별도 관리한다.\nADS\u002FFREE 구매 성공 시 `adsRefreshUtcMs`는 `serverNow + 1day`로 기록된다.\n`SHOP_ITEM_DAILY`는 광고 시청 성공 시 `ShopCatalogDaily.RefreshByAdsAsync()`로 수동 refresh할 수 있으며, rolling 24시간 기준 최대 5회(`manualRefreshUtcMs`, `manualRefreshRemainCount`)를 사용한다. `manualRefreshRemainCount`는 남은 횟수이며 초기값은 5다.\n`SHOP_ITEM_DAILY` 카탈로그 refresh 시에는 저장된 daily snapshot을 새 snapshot으로 교체한다.\n카탈로그별 남은 시간 조회는 catalog runtime 프로퍼티(`RemainAutoRefreshTimeMs`, `RemainAdsRefreshTimeMs`, `ManualRefreshRemainTimeMs`)를 사용한다.\n`ShopCatalogBase`는 storage-backed catalog runtime helper와 공통 refresh helper를 소유하고,\n`ShopCatalogDaily`는 manual refresh 상태 판단\u002F광고 시청\u002F성공 기록을 직접 처리한다.\n`ShopManager`는 global initialize\u002Fglobal refresh\u002Fproduct index\u002Flocal save queue만 담당한다.\n\n---\n\n## Start Here\n\n| Document | Description |\n|----------|-------------|\n| [03-ssot](..\u002F03-ssot\u002FSKILL.md) | Shop catalog initialize\u002Frefresh operation 정본 |\n| [10-shop-manager](..\u002F10-shop-manager\u002FSKILL.md) | ShopManager API\u002F구현 규약 |\n| [12-shop-storage](..\u002F12-shop-storage\u002FSKILL.md) | ShopStorage 저장 규약 |\n| [13-shop-catalog](..\u002F13-shop-catalog\u002FSKILL.md) | 카탈로그 구성\u002F선택 생성 규약 |\n| [14-shop-catalog-factory](..\u002F14-shop-catalog-factory\u002FSKILL.md) | ShopCatalogFactory 카탈로그 인스턴스 생성 |\n| [15-shop-product-factory](..\u002F15-shop-product-factory\u002FSKILL.md) | ShopProductFactory row→product 변환 |\n| [16-shop-catalog-chest](..\u002F16-shop-catalog-chest\u002FSKILL.md) | Chest catalog level\u002Fexp\u002Freward routing 규약 |\n\n---\n\n## Sub-skills\n\n- [03-ssot](..\u002F03-ssot\u002FSKILL.md)\n- [10-shop-manager](..\u002F10-shop-manager\u002FSKILL.md)\n- [11-shop-product](..\u002F11-shop-product\u002FSKILL.md)\n- [12-shop-storage](..\u002F12-shop-storage\u002FSKILL.md)\n- [13-shop-catalog](..\u002F13-shop-catalog\u002FSKILL.md)\n- [14-shop-catalog-factory](..\u002F14-shop-catalog-factory\u002FSKILL.md)\n- [15-shop-product-factory](..\u002F15-shop-product-factory\u002FSKILL.md)\n- [16-shop-catalog-chest](..\u002F16-shop-catalog-chest\u002FSKILL.md)\n",{},"main","8cb5bd877a3a7004867d2f55697cb9e4ff2f1734","skills\u002Fdevian-unity\u002F50-mobile-package\u002F28-shop-system\u002F00-overview","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft","Kim Hyong Joon","2026-04-12 18:44:10",{"source":7,"skillName":5,"commands":32,"prompt":42,"zipAvailable":43},[33,36,39],{"tool":34,"command":35},"npx","npx skills add devwinsoft\u002Fdevian --skill 00-overview",{"tool":37,"command":38},"bunx","bunx skills add devwinsoft\u002Fdevian --skill 00-overview",{"tool":40,"command":41},"pnpm","pnpm dlx skills add devwinsoft\u002Fdevian --skill 00-overview","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian-unity\u002F50-mobile-package\u002F28-shop-system\u002F00-overview\u002FSKILL.md",true,[45,51,55,59,63,67,71,77,81,85],{"path":46,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":49,"sourceHtmlUrl":50},"references\u002Fauth.md","REFERENCE","参考文档",9077,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Freferences\u002Fauth.md",{"path":52,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":53,"sourceHtmlUrl":54},"references\u002Fclient.md",8577,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Freferences\u002Fclient.md",{"path":56,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":57,"sourceHtmlUrl":58},"references\u002Fdeser-files.md",12410,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Freferences\u002Fdeser-files.md",{"path":60,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":61,"sourceHtmlUrl":62},"references\u002Finjection.md",10246,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Freferences\u002Finjection.md",{"path":64,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":65,"sourceHtmlUrl":66},"references\u002Frecon.md",8252,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Freferences\u002Frecon.md",{"path":68,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":69,"sourceHtmlUrl":70},"references\u002Ftooling.md",5176,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Freferences\u002Ftooling.md",{"path":72,"resourceType":73,"resourceTypeDesc":74,"sizeBytes":75,"sourceHtmlUrl":76},"scripts\u002Fdirquick.sh","SCRIPT","脚本",5924,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Fscripts\u002Fdirquick.sh",{"path":78,"resourceType":73,"resourceTypeDesc":74,"sizeBytes":79,"sourceHtmlUrl":80},"scripts\u002Fjwt-inspect.py",7453,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002Fscripts\u002Fjwt-inspect.py",{"path":82,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":83,"sourceHtmlUrl":84},"SOURCE.md",327,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002FSOURCE.md",{"path":86,"resourceType":47,"resourceTypeDesc":48,"sizeBytes":87,"sourceHtmlUrl":88},"TRUST.auto.yaml",2153,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fchains\u002Friegan-ctf-web\u002FTRUST.auto.yaml",[90,96,104,112,121,128],{"skillNo":91,"name":92,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":20},"01M6CBX3K2JJV38ANHVGCAT8A0","devian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002FSKILL.md",[],[92],{"skillNo":97,"name":98,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":101,"publishedAt":20},"01M6CBX210BFMM8AMN770J9WY8","90-project-archive","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F90-project-archive\u002FSKILL.md",[],[102,103],"archive","90 project archive",{"skillNo":105,"name":106,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":109,"publishedAt":20},"01M6CBWZSGRR9R3YJZB3177667","30-env-management","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F30-env-management\u002FSKILL.md",[],[110,111],"management","30 env management",{"skillNo":113,"name":114,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":20},"01M6CBWYD3TGWBQV7V35551THF","19-page-push-send","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F19-page-push-send\u002FSKILL.md",[],[118,119,120],"push","page","19 page push send",{"skillNo":122,"name":123,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":126,"publishedAt":20},"01M6CBWWRQ05A7604GHJKTPJTF","18-page-savedata","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F18-page-savedata\u002FSKILL.md",[],[119,127],"18 page savedata",{"skillNo":129,"name":130,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":133,"publishedAt":20},"01M6CBWVH4S2VF1V7B2GBTESCT","17-page-deobfuscate","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F17-page-deobfuscate\u002FSKILL.md",[],[119,134],"17 page deobfuscate"]