Repository: NoFxAiOS/nofx Branch: dev Commit: 79a513470b49 Files: 497 Total size: 4.2 MB Directory structure: gitextract_lfraba5v/ ├── .dockerignore ├── .github/ │ ├── CLA.md │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bounty_claim.md │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── PR_TITLE_GUIDE.md │ ├── PULL_REQUEST_TEMPLATE/ │ │ ├── README.md │ │ ├── backend.md │ │ ├── docs.md │ │ ├── frontend.md │ │ └── general.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── SECURITY.md │ ├── labeler.yml │ ├── labels.yml │ └── workflows/ │ ├── README.md │ ├── docker-build.yml │ ├── pr-checks-comment.yml │ ├── pr-checks-run.yml │ ├── pr-checks.yml │ ├── pr-docker-check.yml │ ├── pr-docker-compose-healthcheck.yml │ ├── pr-go-test-coverage.yml │ ├── pr-template-suggester.yml │ ├── scripts/ │ │ ├── calculate_coverage.py │ │ ├── comment_pr.py │ │ └── requirements.txt │ └── test.yml ├── .gitignore ├── .husky/ │ ├── _/ │ │ └── husky.sh │ └── pre-commit ├── CHANGELOG.md ├── CHANGELOG.zh-CN.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DISCLAIMER.md ├── Dockerfile.railway ├── ENCRYPTION_README.md ├── LICENSE ├── Makefile ├── README.ja.md ├── README.md ├── SECURITY.md ├── api/ │ ├── crypto_handler.go │ ├── errors.go │ ├── handler_ai_model.go │ ├── handler_competition.go │ ├── handler_exchange.go │ ├── handler_klines.go │ ├── handler_order.go │ ├── handler_telegram.go │ ├── handler_trader.go │ ├── handler_trader_config.go │ ├── handler_trader_status.go │ ├── handler_user.go │ ├── handler_wallet.go │ ├── route_registry.go │ ├── server.go │ ├── server_test.go │ ├── strategy.go │ ├── traderid_test.go │ ├── utils.go │ └── utils_test.go ├── auth/ │ └── auth.go ├── config/ │ └── config.go ├── crypto/ │ └── crypto.go ├── docker/ │ ├── Dockerfile.backend │ └── Dockerfile.frontend ├── docker-compose.prod.yml ├── docker-compose.stable.yml ├── docker-compose.yml ├── docs/ │ ├── Git工作流规范.md │ ├── MIGRATION_GUIDE.md │ ├── README.md │ ├── api/ │ │ └── API_REFERENCE.md │ ├── architecture/ │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── STRATEGY_MODULE.md │ │ ├── STRATEGY_MODULE.zh-CN.md │ │ └── X402_STREAMING_PAYMENT.md │ ├── community/ │ │ ├── HOW_TO_MIGRATE_YOUR_PR.md │ │ ├── HOW_TO_MIGRATE_YOUR_PR.zh-CN.md │ │ ├── MIGRATION_ANNOUNCEMENT.md │ │ ├── MIGRATION_ANNOUNCEMENT.zh-CN.md │ │ ├── OFFICIAL_ACCOUNTS.md │ │ ├── PR_COMMENT_TEMPLATE.md │ │ ├── README.md │ │ ├── bounty-aster.md │ │ ├── bounty-guide.md │ │ └── bounty-hyperliquid.md │ ├── getting-started/ │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── aster-api-wallet.md │ │ ├── binance-api.md │ │ ├── blockrun-base-wallet.md │ │ ├── blockrun-sol-wallet.md │ │ ├── bybit-api.md │ │ ├── custom-api.en.md │ │ ├── custom-api.md │ │ ├── hyperliquid-agent-wallet.md │ │ ├── lighter-agent-wallet.md │ │ └── okx-api.md │ ├── guides/ │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── TROUBLESHOOTING.md │ │ ├── TROUBLESHOOTING.zh-CN.md │ │ ├── faq.en.md │ │ └── faq.zh-CN.md │ ├── i18n/ │ │ ├── README.md │ │ ├── en/ │ │ │ ├── PRIVACY POLICY.md │ │ │ └── TERMS OF SERVICE.md │ │ ├── ja/ │ │ │ ├── PRIVACY POLICY.md │ │ │ ├── README.md │ │ │ └── TERMS OF SERVICE.md │ │ ├── ko/ │ │ │ └── README.md │ │ ├── ru/ │ │ │ ├── PRIVACY POLICY.md │ │ │ ├── README.md │ │ │ └── TERMS OF SERVICE.md │ │ ├── uk/ │ │ │ ├── PRIVACY POLICY.md │ │ │ ├── README.md │ │ │ └── TERMS OF SERVICE.md │ │ ├── vi/ │ │ │ └── README.md │ │ └── zh-CN/ │ │ ├── CONTRIBUTING.md │ │ ├── PRIVACY POLICY.md │ │ ├── README.md │ │ └── TERMS OF SERVICE.md │ ├── legal/ │ │ ├── AGPL-VIOLATION-REPORT-ChainOpera-EN.md │ │ └── AGPL-VIOLATION-REPORT-ChainOpera.md │ ├── maintainers/ │ │ ├── PROJECT_MANAGEMENT.md │ │ ├── PROJECT_MANAGEMENT.zh-CN.md │ │ ├── PR_REVIEW_GUIDE.md │ │ ├── PR_REVIEW_GUIDE.zh-CN.md │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── SETUP_GUIDE.md │ │ └── SETUP_GUIDE.zh-CN.md │ ├── market-regime-classification-en.md │ ├── market-regime-classification-zh.md │ ├── plans/ │ │ ├── 2026-01-14-grid-trading-fixes.md │ │ ├── 2026-01-17-grid-market-regime-design.md │ │ ├── 2026-01-17-grid-market-regime-impl.md │ │ ├── 2026-03-06-telegram-agent-redesign.md │ │ └── 2026-03-06-telegram-bot.md │ ├── pnl.md │ ├── prompt-guide.md │ ├── prompt-guide.zh-CN.md │ ├── research/ │ │ └── AI-Trader-Analysis-Report.md │ └── roadmap/ │ ├── README.md │ └── README.zh-CN.md ├── go.mod ├── go.sum ├── hook/ │ ├── README.md │ ├── hooks.go │ ├── http_client_hook.go │ ├── ip_hook.go │ └── trader_hook.go ├── install-stable.sh ├── install.sh ├── kernel/ │ ├── engine.go │ ├── engine_analysis.go │ ├── engine_position.go │ ├── engine_prompt.go │ ├── formatter.go │ ├── grid_engine.go │ ├── prompt_builder.go │ ├── prompt_builder_test.go │ ├── schema.go │ └── validate_test.go ├── logger/ │ ├── config.go │ └── logger.go ├── main.go ├── manager/ │ └── trader_manager.go ├── market/ │ ├── api_client.go │ ├── data.go │ ├── data_indicators.go │ ├── data_klines.go │ ├── data_test.go │ ├── historical.go │ ├── timeframe.go │ └── types.go ├── mcp/ │ ├── client.go │ ├── client_test.go │ ├── config.go │ ├── config_usage_test.go │ ├── context_guard.go │ ├── context_guard_test.go │ ├── examples_test.go │ ├── hooks.go │ ├── interface.go │ ├── intro/ │ │ ├── BUILDER_EXAMPLES.md │ │ ├── BUILDER_PATTERN_BENEFITS.md │ │ ├── LOGRUS_INTEGRATION.md │ │ ├── MIGRATION_GUIDE.md │ │ └── README.md │ ├── logger.go │ ├── mock_test.go │ ├── options.go │ ├── options_test.go │ ├── payment/ │ │ ├── blockrun_base.go │ │ ├── blockrun_sol.go │ │ ├── claw402.go │ │ └── x402.go │ ├── provider/ │ │ ├── claude.go │ │ ├── deepseek.go │ │ ├── gemini.go │ │ ├── grok.go │ │ ├── kimi.go │ │ ├── minimax.go │ │ ├── openai.go │ │ ├── options_test.go │ │ └── qwen.go │ ├── providers.go │ ├── registry.go │ ├── request.go │ ├── request_builder.go │ └── request_builder_test.go ├── nginx/ │ └── nginx.conf ├── provider/ │ ├── alpaca/ │ │ └── kline.go │ ├── coinank/ │ │ ├── base_coin.go │ │ ├── coinank_api/ │ │ │ ├── base_coin.go │ │ │ ├── base_coin_test.go │ │ │ ├── depth_ws.go │ │ │ ├── depth_ws_test.go │ │ │ ├── kline.go │ │ │ ├── kline_test.go │ │ │ ├── kline_ws.go │ │ │ └── kline_ws_test.go │ │ ├── coinank_enum/ │ │ │ ├── exchange.go │ │ │ ├── instrument_agg_sort_by.go │ │ │ ├── interval.go │ │ │ ├── product_type.go │ │ │ ├── side.go │ │ │ ├── sort_type.go │ │ │ └── url.go │ │ ├── coinank_http.go │ │ ├── instrument_agg_rank.go │ │ ├── instruments.go │ │ ├── kline.go │ │ ├── liquidation.go │ │ ├── net_positions.go │ │ └── open_interest.go │ ├── hyperliquid/ │ │ ├── coins.go │ │ ├── kline.go │ │ └── kline_test.go │ ├── nofxos/ │ │ ├── ai500.go │ │ ├── client.go │ │ ├── coin.go │ │ ├── netflow.go │ │ ├── oi.go │ │ ├── price.go │ │ └── util.go │ └── twelvedata/ │ └── kline.go ├── railway/ │ └── start.sh ├── railway.toml ├── security/ │ └── url_validator.go ├── start.sh ├── store/ │ ├── ai_model.go │ ├── decision.go │ ├── driver.go │ ├── equity.go │ ├── exchange.go │ ├── gorm.go │ ├── grid.go │ ├── order.go │ ├── position.go │ ├── position_builder.go │ ├── position_history.go │ ├── position_query.go │ ├── store.go │ ├── strategy.go │ ├── telegram_config.go │ ├── trader.go │ └── user.go ├── telegram/ │ ├── agent/ │ │ ├── agent.go │ │ ├── agent_test.go │ │ ├── apicall.go │ │ ├── manager.go │ │ └── prompt.go │ ├── bot.go │ └── session/ │ └── memory.go ├── telemetry/ │ └── experience.go ├── trader/ │ ├── aster/ │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ ├── trader_positions.go │ │ ├── trader_sync.go │ │ └── trader_test.go │ ├── auto_trader.go │ ├── auto_trader_decision.go │ ├── auto_trader_grid.go │ ├── auto_trader_grid_levels.go │ ├── auto_trader_grid_orders.go │ ├── auto_trader_grid_regime.go │ ├── auto_trader_loop.go │ ├── auto_trader_orders.go │ ├── auto_trader_risk.go │ ├── binance/ │ │ ├── futures.go │ │ ├── futures_account.go │ │ ├── futures_orders.go │ │ ├── futures_positions.go │ │ ├── futures_test.go │ │ ├── order_sync.go │ │ ├── order_sync_test.go │ │ ├── sync_e2e_test.go │ │ └── sync_verify_test.go │ ├── bitget/ │ │ ├── order_sync.go │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ └── trader_positions.go │ ├── bybit/ │ │ ├── order_sync.go │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ └── trader_positions.go │ ├── exchange_sync_test.go │ ├── gate/ │ │ ├── order_sync.go │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ └── trader_test.go │ ├── grid_regime.go │ ├── grid_regime_test.go │ ├── helpers.go │ ├── hyperliquid/ │ │ ├── order_sync.go │ │ ├── sync_test.go │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ ├── trader_positions.go │ │ ├── trader_race_test.go │ │ └── trader_sync.go │ ├── indodax/ │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ └── trader_test.go │ ├── interface.go │ ├── kucoin/ │ │ ├── order_sync.go │ │ ├── order_sync_test.go │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ └── trader_positions.go │ ├── lighter/ │ │ ├── account.go │ │ ├── integration_test.go │ │ ├── order_sync.go │ │ ├── orders.go │ │ ├── orders_test.go │ │ ├── trader.go │ │ ├── trading.go │ │ └── types.go │ ├── okx/ │ │ ├── order_sync.go │ │ ├── trader.go │ │ ├── trader_account.go │ │ ├── trader_orders.go │ │ └── trader_positions.go │ ├── position_rebuild.go │ ├── position_snapshot.go │ ├── testutil/ │ │ └── test_suite.go │ └── types/ │ └── interface.go └── web/ ├── .dockerignore ├── .husky/ │ └── pre-commit ├── .prettierignore ├── .prettierrc.json ├── CHANGELOG.md ├── README.md ├── eslint.config.js ├── index.html ├── package.json ├── postcss.config.js ├── src/ │ ├── App.tsx │ ├── components/ │ │ ├── auth/ │ │ │ ├── LoginPage.tsx │ │ │ ├── LoginRequiredOverlay.tsx │ │ │ ├── RegisterPage.test.tsx │ │ │ ├── RegisterPage.tsx │ │ │ ├── RegistrationDisabled.test.tsx │ │ │ ├── RegistrationDisabled.tsx │ │ │ └── ResetPasswordPage.tsx │ │ ├── charts/ │ │ │ ├── AdvancedChart.tsx │ │ │ ├── ChartTabs.tsx │ │ │ ├── ChartWithOrders.tsx │ │ │ ├── ChartWithOrdersSimple.tsx │ │ │ ├── ComparisonChart.tsx │ │ │ ├── EquityChart.tsx │ │ │ └── TradingViewChart.tsx │ │ ├── common/ │ │ │ ├── ConfirmDialog.tsx │ │ │ ├── Container.tsx │ │ │ ├── DeepVoidBackground.tsx │ │ │ ├── ExchangeIcons.tsx │ │ │ ├── Header.tsx │ │ │ ├── HeaderBar.tsx │ │ │ ├── MetricTooltip.tsx │ │ │ ├── ModelIcons.tsx │ │ │ ├── PunkAvatar.tsx │ │ │ ├── WebCryptoEnvironmentCheck.tsx │ │ │ └── WhitelistFullPage.tsx │ │ ├── faq/ │ │ │ ├── FAQContent.tsx │ │ │ ├── FAQLayout.tsx │ │ │ ├── FAQSearchBar.tsx │ │ │ └── FAQSidebar.tsx │ │ ├── landing/ │ │ │ ├── AboutSection.tsx │ │ │ ├── AnimatedSection.tsx │ │ │ ├── CommunitySection.tsx │ │ │ ├── FeaturesSection.tsx │ │ │ ├── FooterSection.tsx │ │ │ ├── HeroSection.tsx │ │ │ ├── HowItWorksSection.tsx │ │ │ ├── LoginModal.tsx │ │ │ ├── brand/ │ │ │ │ ├── AgentTerminal.tsx │ │ │ │ ├── BrandFeatures.tsx │ │ │ │ ├── BrandHero.tsx │ │ │ │ ├── BrandStats.tsx │ │ │ │ └── Marquee.tsx │ │ │ └── core/ │ │ │ ├── AgentGrid.tsx │ │ │ ├── DeploymentHub.tsx │ │ │ ├── LiveFeed.tsx │ │ │ └── TerminalHero.tsx │ │ ├── modals/ │ │ │ ├── SetupPage.tsx │ │ │ └── TwoStageKeyModal.tsx │ │ ├── strategy/ │ │ │ ├── CoinSourceEditor.tsx │ │ │ ├── GridConfigEditor.tsx │ │ │ ├── GridRiskPanel.tsx │ │ │ ├── IndicatorEditor.tsx │ │ │ ├── PromptSectionsEditor.tsx │ │ │ ├── PublishSettingsEditor.tsx │ │ │ └── RiskControlEditor.tsx │ │ ├── trader/ │ │ │ ├── AITradersPage.tsx │ │ │ ├── CompetitionPage.test.tsx │ │ │ ├── CompetitionPage.tsx │ │ │ ├── ConfigStatusGrid.tsx │ │ │ ├── DecisionCard.tsx │ │ │ ├── ExchangeConfigModal.tsx │ │ │ ├── ModelCard.tsx │ │ │ ├── ModelConfigModal.tsx │ │ │ ├── ModelStepIndicator.tsx │ │ │ ├── PositionHistory.tsx │ │ │ ├── TelegramConfigModal.tsx │ │ │ ├── Tooltip.tsx │ │ │ ├── TraderConfigModal.tsx │ │ │ ├── TraderConfigViewModal.tsx │ │ │ ├── TradersList.tsx │ │ │ ├── model-constants.ts │ │ │ └── utils.ts │ │ └── ui/ │ │ ├── alert-dialog.tsx │ │ └── input.tsx │ ├── constants/ │ │ └── branding.ts │ ├── contexts/ │ │ ├── AuthContext.tsx │ │ └── LanguageContext.tsx │ ├── hooks/ │ │ ├── useCounterAnimation.ts │ │ ├── useGitHubStats.ts │ │ └── useSystemConfig.ts │ ├── i18n/ │ │ ├── strategy-translations.ts │ │ └── translations.ts │ ├── index.css │ ├── lib/ │ │ ├── api/ │ │ │ ├── config.ts │ │ │ ├── data.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ ├── strategies.ts │ │ │ ├── telegram.ts │ │ │ └── traders.ts │ │ ├── apiGuard.test.ts │ │ ├── clipboard.ts │ │ ├── cn.ts │ │ ├── config.ts │ │ ├── crypto.ts │ │ ├── httpClient.ts │ │ ├── notify.tsx │ │ ├── registrationToggle.test.ts │ │ └── text.ts │ ├── main.tsx │ ├── pages/ │ │ ├── DataPage.tsx │ │ ├── FAQPage.tsx │ │ ├── LandingPage.tsx │ │ ├── PageNotFound.tsx │ │ ├── SettingsPage.tsx │ │ ├── StrategyMarketPage.tsx │ │ ├── StrategyStudioPage.tsx │ │ └── TraderDashboardPage.tsx │ ├── stores/ │ │ ├── index.ts │ │ ├── tradersConfigStore.ts │ │ └── tradersModalStore.ts │ ├── test/ │ │ └── setup.ts │ ├── types/ │ │ ├── config.ts │ │ ├── index.ts │ │ ├── strategy.ts │ │ └── trading.ts │ ├── utils/ │ │ ├── format.ts │ │ ├── indicators.ts │ │ └── traderColors.ts │ └── vite-env.d.ts ├── tailwind.config.js ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── vitest.config.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ # Git .git .gitignore .github # Docker Dockerfile docker-compose.yml .dockerignore # IDE .idea .vscode *.swp *.swo *~ # Build artifacts nofx nofx_test *.exe *.dll *.so *.dylib # Test files *_test.go test_* # Documentation *.md !README.md docs/ # Runtime data decision_logs/ *.log # Config files (should be mounted) config.json # Web build artifacts (but include source for multi-stage build) web/node_modules/ web/dist/ # Temporary files tmp/ temp/ *.tmp ================================================ FILE: .github/CLA.md ================================================ # NOFX Contributor License Agreement Thank you for your interest in contributing to NOFX. This Contributor License Agreement ("CLA") documents the rights granted by contributors to the Project. ## 1. Definitions - **"Contribution"** means any code, documentation, or other original work submitted to the Project. - **"You"** means the individual or entity submitting the Contribution. - **"Project"** means NOFX (https://github.com/NoFxAiOS/nofx). ## 2. Grant of Rights By submitting a Contribution, you grant the Project a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to: - Use, copy, modify, and distribute your Contribution - Sublicense your Contribution under the AGPL-3.0 license - Create derivative works from your Contribution ## 3. Patent License You grant the Project a perpetual, worldwide, non-exclusive, royalty-free, irrevocable patent license to make, use, sell, and distribute your Contribution. ## 4. Your Representations You represent that: - You have the legal right to grant this license - Your Contribution is your original work - Your Contribution does not violate any third-party rights - If you are employed, you have permission from your employer to make this Contribution ## 5. No Warranty Your Contribution is provided "AS IS" without any warranty of any kind. ## 6. Project License All Contributions will be distributed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**. ## 7. Applicable Law This Agreement is governed by international copyright treaties including: - Berne Convention - TRIPS Agreement (WTO) - WIPO Copyright Treaty (WCT) --- By signing this CLA, you acknowledge that you have read and agree to these terms. **Contact**: contact@vergex.trade ================================================ FILE: .github/CODEOWNERS ================================================ # CODEOWNERS # # This file defines code ownership and automatic reviewer assignment. # When a PR touches files matching these patterns, the listed users/teams # will be automatically requested for review. # # 此文件定义代码所有权和自动 reviewer 分配。 # 当 PR 涉及匹配这些模式的文件时,列出的用户/团队将自动被请求审查。 # # Syntax | 语法: # pattern @username @org/team-name # # More specific patterns override less specific ones # 更具体的模式会覆盖不太具体的模式 # # Documentation: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners # ============================================================================= # Global Owners | 全局所有者 # These users will be requested for review on ALL pull requests # 这些用户将被请求审查所有 PR # ============================================================================= * @NoFxAiOS @hzb1115 @tangmengqiu @mykelio1001 @Icyoung @SkywalkerJi # ============================================================================= # Specific Component Owners | 特定组件所有者 # Additional reviewers based on file paths (in addition to global owners) # 基于文件路径的额外 reviewers(在全局 owners 之外) # ============================================================================= # Backend / Go Code | 后端 / Go 代码 # Go files and backend logic *.go @SkywalkerJi @hzb1115 @Icyoung @tangmengqiu go.mod @SkywalkerJi @hzb1115 @Icyoung @tangmengqiu go.sum @SkywalkerJi @hzb1115 @Icyoung @tangmengqiu # Frontend / Web | 前端 / Web # React/TypeScript frontend code /web/ @0xEmberZz @hzb1115 @tangmengqiu /web/src/ @0xEmberZz @hzb1115 @tangmengqiu *.tsx @0xEmberZz @hzb1115 @tangmengqiu *.ts @0xEmberZz @hzb1115 @tangmengqiu (frontend TypeScript only) *.jsx @0xEmberZz @hzb1115 @tangmengqiu *.css @0xEmberZz @hzb1115 @tangmengqiu *.scss @0xEmberZz @hzb1115 @tangmengqiu # Configuration Files | 配置文件 *.json @0xEmberZz @hzb1115 @tangmengqiu *.yaml @0xEmberZz @hzb1115 @tangmengqiu *.yml @0xEmberZz @hzb1115 @tangmengqiu *.toml @0xEmberZz @hzb1115 @tangmengqiu *.ini @0xEmberZz @hzb1115 @tangmengqiu # Documentation | 文档 # Markdown and documentation files *.md @hzb1115 @tangmengqiu /docs/ @hzb1115 @tangmengqiu README.md @hzb1115 @tangmengqiu # GitHub Workflows & Actions | GitHub 工作流和 Actions # CI/CD configuration and automation /.github/ @hzb1115 /.github/workflows/ @hzb1115 /.github/workflows/*.yml @hzb1115 # Docker | Docker 配置 Dockerfile @tangmengqiu docker-compose.yml @tangmengqiu .dockerignore @tangmengqiu # Database | 数据库 # Database migrations and schemas /migrations/ @SkywalkerJi @hzb1115 @Icyoung @tangmengqiu /db/ @SkywalkerJi @hzb1115 @Icyoung @tangmengqiu *.sql @SkywalkerJi @hzb1115 @Icyoung @tangmengqiu # Scripts | 脚本 /scripts/ @hzb1115 @tangmengqiu *.sh @hzb1115 @tangmengqiu *.bash @hzb1115 @tangmengqiu *.py @hzb1115 @tangmengqiu (if Python scripts exist) # Tests | 测试 # Test files require review from component owners *_test.go @SkywalkerJi @heronsbillC /tests/ @SkywalkerJi @Icyoung @heronsbillC /web/tests/ @Icyoung @hzb1115 @heronsbillC # Security & Dependencies | 安全和依赖 # Security-sensitive files require extra attention .env.example @hzb1115 @tangmengqiu .gitignore @hzb1115 @tangmengqiu go.sum @hzb1115 @tangmengqiu package-lock.json @Icyoung @hzb1115 @tangmengqiu yarn.lock @Icyoung @hzb1115 @tangmengqiu # Build Configuration | 构建配置 Makefile @hzb1115 @tangmengqiu /build/ @hzb1115 @tangmengqiu /dist/ @hzb1115 @tangmengqiu # License & Legal | 许可证和法律文件 LICENSE @hzb1115 COPYING @hzb1115 # ============================================================================= # Notes | 注意事项 # ============================================================================= # # 1. All PRs will be assigned to the 5 global owners # 所有 PR 都会分配给这 5 个全局 owners # # 2. Specific paths may add additional reviewers # 特定路径可能会添加额外的 reviewers # # 3. PR author will NOT be requested for review (GitHub handles this) # PR 作者不会被请求审查(GitHub 自动处理) # # 4. You can adjust patterns and owners as needed # 你可以根据需要调整模式和 owners # # 5. To require multiple approvals, configure branch protection rules # 要求多个批准,请配置分支保护规则 # # ⚠️ IMPORTANT - Permission Requirements | 重要 - 权限要求: # - Users listed here will ONLY be auto-requested if they have Write+ permission # 这里列出的用户只有在拥有 Write 或以上权限时才会被自动请求 # - GitHub will silently skip users without proper permissions # GitHub 会静默跳过没有适当权限的用户 # - See CODEOWNERS_PERMISSIONS.md for details # 详见 CODEOWNERS_PERMISSIONS.md # # ============================================================================= ================================================ FILE: .github/ISSUE_TEMPLATE/bounty_claim.md ================================================ --- name: Bounty Claim about: Claim a bounty task or propose a new bounty title: '[BOUNTY CLAIM] ' labels: bounty assignees: '' --- ## 💰 Bounty Information **Claiming existing bounty?** - Issue #: - Bounty amount: **OR proposing new bounty?** - Proposed feature/fix: - Estimated effort: [Small / Medium / Large] --- ## 👤 About You **Name/Username:** **Contact:** - GitHub: @your_username - Telegram: @your_telegram (optional) - Email: your@email.com (optional) **Relevant Experience:** - - - --- ## 📋 Implementation Plan ### 1. Approach - How will you implement this? - What components will be affected? - Any dependencies or libraries needed? ### 2. Timeline - **Start date:** - **Estimated completion:** - **Milestones:** - [ ] Week 1: ... - [ ] Week 2: ... - [ ] Week 3: ... ### 3. Deliverables - [ ] Working code (merged PR) - [ ] Unit tests (if applicable) - [ ] Documentation updates - [ ] Demo video/screenshots --- ## 🔍 Questions for Maintainers 1. 2. 3. --- ## 📚 References - --- ## ✅ Acknowledgment By claiming this bounty, I acknowledge that: - [ ] I have read the [Contributing Guide](../../CONTRIBUTING.md) - [ ] I will follow the [Code of Conduct](../../CODE_OF_CONDUCT.md) - [ ] I understand the acceptance criteria - [ ] My contribution will be licensed under AGPL-3.0 License - [ ] Payment is subject to successful PR merge --- **For maintainers:** - [ ] Bounty claim approved - [ ] Issue assigned to claimant - [ ] Timeline agreed upon ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug Report about: Report a bug to help us improve NOFX title: '[BUG] ' labels: bug assignees: '' --- > **⚠️ Before submitting:** Please check the [Troubleshooting Guide](../../docs/guides/TROUBLESHOOTING.md) ([中文版](../../docs/guides/TROUBLESHOOTING.zh-CN.md)) to see if your issue can be resolved quickly. ## 🐛 Bug Description ## 🔍 Bug Category - [ ] Trading execution (orders not executing, wrong position size, etc.) - [ ] AI decision issues (unexpected decisions, only opening one direction, etc.) - [ ] Exchange connection (API errors, authentication failures, etc.) - [ ] UI/Frontend (display issues, buttons not working, data not updating, etc.) - [ ] Backend/API (server errors, crashes, performance issues, etc.) - [ ] Configuration (settings not saving, database errors, etc.) - [ ] Other: _________________ ## 📋 Steps to Reproduce 1. Go to '...' 2. Click on '...' / Run command '...' 3. Configure '...' 4. See error ## ✅ Expected Behavior ## ❌ Actual Behavior ## 📸 Screenshots & Logs ### Frontend Error (if applicable) **Browser Console Screenshot:** **Network Tab (failed requests):** ### Backend Logs (if applicable) **Docker users:** ```bash # View backend logs docker compose logs backend --tail=100 # OR continuously follow logs docker compose logs -f backend ``` **Manual/PM2 users:** ```bash # Terminal output where you ran: ./nofx # OR PM2 logs: pm2 logs nofx --lines 100 ``` **Backend Log Output:** ``` Paste backend logs here (last 50-100 lines around the error) ``` ### Trading/Decision Logs (if trading issue) **Decision Log Path:** `decision_logs/{trader_id}/{timestamp}.json` ```json { "paste relevant decision log here if applicable" } ``` ## 💻 Environment **System:** - **OS:** [e.g. macOS 13, Ubuntu 22.04, Windows 11] - **Deployment:** [Docker / Manual / PM2] **Backend:** - **Go Version:** [run: `go version`] - **NOFX Version:** [run: `git log -1 --oneline` or check release tag] **Frontend:** - **Browser:** [e.g. Chrome 120, Firefox 121, Safari 17] - **Node.js Version:** [run: `node -v`] **Trading Setup:** - **Exchange:** [Binance / Hyperliquid / Aster] - **Account Type:** [Main Account / Subaccount] - **Position Mode:** [Hedge Mode (Dual) / One-way Mode] ← **Important for trading bugs!** - **AI Model:** [DeepSeek / Qwen / Custom] - **Number of Traders:** [e.g. 1, 2, etc.] ## 🔧 Configuration (if relevant) **Leverage Settings:** ```json { "btc_eth_leverage": 5, "altcoin_leverage": 5 } ``` **Any custom settings:** ## 📊 Additional Context **Frequency:** - [ ] Happens every time - [ ] Happens randomly - [ ] Happened once **Timeline:** - Did this work before? [ ] Yes [ ] No - When did it break? [e.g. after upgrade to v3.0.0, after changing config, etc.] - Recent changes? [e.g. updated dependencies, changed exchange, etc.] **Impact:** - [ ] System cannot start - [ ] Trading stopped/broken - [ ] UI broken but trading works - [ ] Minor visual issue - [ ] Other: _________________ ## 💡 Possible Solution --- ## 📝 Quick Tips for Faster Resolution **For Trading Issues:** 1. ✅ Check Binance position mode: Go to Futures → ⚙️ Preferences → Position Mode → Must be **Hedge Mode** 2. ✅ Verify API permissions: Futures trading must be enabled 3. ✅ Check decision logs in `decision_logs/{trader_id}/` for AI reasoning **For Connection Issues:** 4. ✅ Test API connectivity: `curl http://localhost:8080/api/health` 5. ✅ Check API rate limits on exchange 6. ✅ Verify API keys are not expired **For UI Issues:** 7. ✅ Hard refresh: Ctrl+Shift+R (or Cmd+Shift+R on Mac) 8. ✅ Check browser console (F12) for errors 9. ✅ Verify backend is running: `docker compose ps` or `ps aux | grep nofx` ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature Request about: Suggest a new feature for NOFX title: '[FEATURE] ' labels: enhancement assignees: '' --- ## 📋 Feature Description ## 🎯 Problem to Solve ## 💡 Proposed Solution ## 🔧 Technical Details ## ✅ Acceptance Criteria - [ ] Item 1 - [ ] Item 2 ## 📚 Additional Context ================================================ FILE: .github/PR_TITLE_GUIDE.md ================================================ # PR Title Guide ## 📋 Overview We use the **Conventional Commits** format to maintain consistency in PR titles, but this is **recommended**, not mandatory. It will not prevent your PR from being merged. ## ✅ Recommended Format ``` type(scope): description ``` ### Examples ``` feat(trader): add new trading strategy fix(api): resolve authentication issue docs: update README chore(deps): update dependencies ci(workflow): improve GitHub Actions ``` --- ## 📖 Detailed Guide ### Type - Required Describes the type of change: | Type | Description | Example | |------|-------------|---------| | `feat` | New feature | `feat(trader): add stop-loss feature` | | `fix` | Bug fix | `fix(api): handle null response` | | `docs` | Documentation change | `docs: update installation guide` | | `style` | Code formatting (no functional change) | `style: format code with prettier` | | `refactor` | Code refactoring (neither feature nor fix) | `refactor(exchange): simplify connection logic` | | `perf` | Performance optimization | `perf(ai): optimize prompt processing` | | `test` | Add or modify tests | `test(trader): add unit tests` | | `chore` | Build process or auxiliary tool changes | `chore: update dependencies` | | `ci` | CI/CD related changes | `ci: add test coverage report` | | `security` | Security fixes | `security: update vulnerable dependencies` | | `build` | Build system or external dependency changes | `build: upgrade webpack to v5` | ### Scope - Optional Describes the area affected by the change: | Scope | Description | |-------|-------------| | `exchange` | Exchange-related | | `trader` | Trader/trading strategy | | `ai` | AI model related | | `api` | API interface | | `ui` | User interface | | `frontend` | Frontend code | | `backend` | Backend code | | `security` | Security related | | `deps` | Dependencies | | `workflow` | GitHub Actions workflows | | `github` | GitHub configuration | | `actions` | GitHub Actions | | `config` | Configuration files | | `docker` | Docker related | | `build` | Build related | | `release` | Release related | **Note:** If the change affects multiple scopes, you can omit the scope or choose the most relevant one. ### Description - Required - Use present tense ("add" not "added") - Start with lowercase - No period at the end - Concisely describe what changed --- ## 🎯 Complete Examples ### ✅ Good PR Titles ``` feat(trader): add risk management system fix(exchange): resolve connection timeout issue docs: add API documentation for trading endpoints style: apply consistent code formatting refactor(ai): simplify prompt processing logic perf(backend): optimize database queries test(api): add integration tests for auth chore(deps): update TypeScript to 5.0 ci(workflow): add automated security scanning security(api): fix SQL injection vulnerability build(docker): optimize Docker image size ``` ### ⚠️ Titles That Need Improvement | Poor Title | Issue | Improved | |-----------|-------|----------| | `update code` | Too vague | `refactor(trader): simplify order execution logic` | | `Fixed bug` | Capitalized, not specific | `fix(api): handle edge case in login` | | `Add new feature.` | Has period, not specific | `feat(ui): add dark mode toggle` | | `changes` | Doesn't follow format | `chore: update dependencies` | | `feat: Added new trading algo` | Wrong tense | `feat(trader): add new trading algorithm` | --- ## 🤖 Automated Check Behavior ### When PR Title Doesn't Follow Format 1. **Won't block merging** ✅ - Check is marked as "advisory" - PR can still be reviewed and merged 2. **Provides friendly reminder** 💬 - Bot will comment on the PR - Provides format guidance and examples - Suggests how to improve the title 3. **Can be updated anytime** 🔄 - Re-checks after updating PR title - No need to close and reopen PR ### Example Comment If your PR title is `update workflow`, you'll receive a comment like this: ```markdown ## ⚠️ PR Title Format Suggestion Your PR title doesn't follow the Conventional Commits format, but this won't block your PR from being merged. **Current title:** `update workflow` **Recommended format:** `type(scope): description` ### Valid types: feat, fix, docs, style, refactor, perf, test, chore, ci, security, build ### Common scopes (optional): exchange, trader, ai, api, ui, frontend, backend, security, deps, workflow, github, actions, config, docker, build, release ### Examples: - feat(trader): add new trading strategy - fix(api): resolve authentication issue - docs: update README - chore(deps): update dependencies - ci(workflow): improve GitHub Actions **Note:** This is a suggestion to improve consistency. Your PR can still be reviewed and merged. ``` --- ## 🔧 Configuration Details ### Supported Types Configured in `.github/workflows/pr-checks.yml`: ```yaml types: | feat fix docs style refactor perf test chore ci security build ``` ### Supported Scopes ```yaml scopes: | exchange trader ai api ui frontend backend security deps workflow github actions config docker build release ``` ### Adding New Scopes If you need to add a new scope: 1. Add it to the `scopes` section in `.github/workflows/pr-checks.yml` 2. Update the regex in `.github/workflows/pr-checks-run.yml` (optional) 3. Update this documentation --- ## 📚 Why Use Conventional Commits? ### Benefits 1. **Automated Changelog** 📝 - Automatically generate version changelogs - Clearly categorize different types of changes 2. **Semantic Versioning** 🔢 - `feat` → MINOR version (1.1.0) - `fix` → PATCH version (1.0.1) - `BREAKING CHANGE` → MAJOR version (2.0.0) 3. **Better Readability** 👀 - Understand PR purpose at a glance - Easier to browse Git history 4. **Team Collaboration** 🤝 - Unified commit style - Reduces communication overhead ### Example: Auto-generated Changelog ```markdown ## v1.2.0 (2025-11-02) ### Features - **trader**: add risk management system (#123) - **ui**: add dark mode toggle (#125) ### Bug Fixes - **api**: resolve authentication issue (#124) - **exchange**: fix connection timeout (#126) ### Documentation - update API documentation (#127) ``` --- ## 🎓 Learning Resources - **Conventional Commits:** https://www.conventionalcommits.org/ - **Angular Commit Guidelines:** https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit - **Semantic Versioning:** https://semver.org/ --- ## ❓ FAQ ### Q: Must I follow this format? **A:** No. This is recommended but not mandatory. It won't block your PR from being merged. However, following the format improves project maintainability. ### Q: What if I forget? **A:** The bot will remind you in the PR comments. You can update the title anytime. ### Q: Can I make multiple types of changes in one PR? **A:** Yes, but it's recommended to: - Choose the most significant type - Or consider splitting into multiple PRs (easier to review) ### Q: Can I omit the scope? **A:** Yes. `requireScope: false` means scope is optional. Example: `docs: update README` (no scope is fine) ### Q: How do I add a new type or scope? **A:** Submit a PR to modify `.github/workflows/pr-checks.yml` and document the purpose of the new item in this guide. ### Q: How do I indicate Breaking Changes? **A:** Add `BREAKING CHANGE:` in the description or add `!` after the type: ``` feat!: remove deprecated API feat(api)!: change authentication method BREAKING CHANGE: The old /auth endpoint is removed ``` --- ## 📊 Statistics Want to see the commit type distribution in your project? Run: ```bash git log --oneline --no-merges | \ grep -oE '^[a-f0-9]+ (feat|fix|docs|style|refactor|perf|test|chore|ci|security|build)' | \ cut -d' ' -f2 | sort | uniq -c | sort -rn ``` --- ## ✅ Quick Checklist Before submitting a PR, check if your title: - [ ] Contains a valid type (feat, fix, docs, etc.) - [ ] Starts with lowercase - [ ] Uses present tense ("add" not "added") - [ ] Is concise (preferably under 50 characters) - [ ] Accurately describes the change **Remember:** These are recommendations, not requirements! ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/README.md ================================================ # PR Templates ## 📋 Template Overview We offer 4 specialized templates for different types of PRs to help contributors quickly fill out PR information: ### 1. 🔧 Backend Template **File:** `backend.md` **Use for:** - Go code changes - API endpoint development - Trading logic implementation - Backend performance optimization - Database-related changes **Includes:** - Go test environment - Security considerations - Performance impact assessment - `go fmt` and `go build` checks ### 2. 🎨 Frontend Template **File:** `frontend.md` **Use for:** - UI/UX changes - React/Vue component development - Frontend styling updates - Browser compatibility fixes - Frontend performance optimization **Includes:** - Screenshots/demo requirements - Browser testing checklist - Internationalization checks - Responsive design verification - `npm run lint` and `npm run build` checks ### 3. 📝 Documentation Template **File:** `docs.md` **Use for:** - README updates - API documentation - Tutorials and guides - Code comment improvements - Translation work **Includes:** - Documentation type classification - Content quality checks - Bilingual requirements (EN/CN) - Link validity verification ### 4. 📦 General Template **File:** `general.md` **Use for:** - Mixed-type changes - Cross-domain PRs - Build configuration changes - Dependency updates - When unsure which template to use ## 🤖 Automatic Template Suggestion Our GitHub Action automatically analyzes your PR and suggests the most suitable template: ### How it works: 1. **File Analysis** - Detects all changed file types in the PR 2. **Smart Detection** - If >50% are `.go` files → Suggests **Backend template** - If >50% are `.js/.ts/.tsx/.vue` files → Suggests **Frontend template** - If >70% are `.md` files → Suggests **Documentation template** 3. **Auto-comment** - If it detects you're using the default template but should use a specialized one - It will automatically add a friendly comment suggestion 4. **Auto-labeling** - Automatically adds corresponding labels: `backend`, `frontend`, `documentation` ## 📖 How to Use ### Method 1: URL Parameter (Recommended) When creating a PR, add the template parameter to the URL: ``` https://github.com/YOUR_ORG/nofx/compare/dev...YOUR_BRANCH?template=backend.md ``` Replace `backend.md` with: - `backend.md` - Backend template - `frontend.md` - Frontend template - `docs.md` - Documentation template - `general.md` - General template ### Method 2: Manual Selection 1. When creating a PR, the default template will be shown 2. Follow the guidance links at the top to view the corresponding template 3. Copy the template content into the PR description ### Method 3: Follow Auto-suggestion 1. Create a PR with any template 2. GitHub Action will automatically analyze and comment with a suggestion 3. Update the PR description based on the suggestion ## 🎯 Best Practices 1. **Choose in Advance** - Determine the change type before creating the PR 2. **Complete Filling** - Don't skip required items 3. **Keep it Concise** - Keep descriptions clear but concise 4. **Add Screenshots** - For UI changes, always add screenshots 5. **Test Evidence** - Provide evidence that tests pass ## 🔧 Customization If you need to modify templates or auto-detection logic: 1. **Modify Templates** - Edit `.github/PULL_REQUEST_TEMPLATE/*.md` files 2. **Adjust Detection Threshold** - Edit `.github/workflows/pr-template-suggester.yml` - Modify file type percentage thresholds (current: 50% backend, 50% frontend, 70% docs) 3. **Add New Template** - Create a new `.md` file in the `PULL_REQUEST_TEMPLATE/` directory - Update the workflow to support new file type detection ## ❓ FAQ **Q: My PR has both frontend and backend code, which template should I use?** A: Use the **General template** (`general.md`), or choose the template for the primary change type. --- **Q: What if the automatically suggested template is not suitable?** A: You can ignore the suggestion and continue using the current template. Auto-suggestions are for reference only. --- **Q: Can I not use any template?** A: Not recommended. Templates help ensure PRs contain necessary information and speed up reviews. --- **Q: How to disable automatic template suggestions?** A: Delete or disable the `.github/workflows/pr-template-suggester.yml` file. --- 🌟 **Thank you for using our PR template system!** ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/backend.md ================================================ # Pull Request - Backend > **💡 Tip:** Recommended PR title format `type(scope): description` > Example: `feat(trader): add new strategy` | `fix(api): resolve auth issue` --- ## 📝 Description --- ## 🎯 Type of Change - [ ] 🐛 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change - [ ] ♻️ Refactoring - [ ] ⚡ Performance improvement - [ ] 🔒 Security fix - [ ] 🔧 Build/config change --- ## 🔗 Related Issues - Closes # - Related to # --- ## 📋 Changes Made - - --- ## 🧪 Testing ### Test Environment - **OS:** - **Go Version:** - **Exchange:** [if applicable] ### Manual Testing - [ ] Tested locally - [ ] Tested on testnet (for exchange integration) - [ ] Unit tests pass - [ ] Verified no existing functionality broke ### Test Results ``` Test output here ``` --- ## 🔒 Security Considerations - [ ] No API keys or secrets hardcoded - [ ] User inputs properly validated - [ ] No SQL injection vulnerabilities - [ ] Authentication/authorization properly handled - [ ] Sensitive data is encrypted - [ ] N/A (not security-related) --- ## ⚡ Performance Impact - [ ] No significant performance impact - [ ] Performance improved - [ ] Performance may be impacted (explain below) **If impacted, explain:** --- ## ✅ Checklist ### Code Quality - [ ] Code follows project style - [ ] Self-review completed - [ ] Comments added for complex logic - [ ] Code compiles successfully (`go build`) - [ ] Ran `go fmt` ### Documentation - [ ] Updated relevant documentation - [ ] Added inline comments where necessary - [ ] Updated API documentation (if applicable) ### Git - [ ] Commits follow conventional format - [ ] Rebased on latest `dev` branch - [ ] No merge conflicts --- ## 📚 Additional Notes --- **By submitting this PR, I confirm:** - [ ] I have read the [Contributing Guidelines](../../CONTRIBUTING.md) - [ ] I agree to the [Code of Conduct](../../CODE_OF_CONDUCT.md) - [ ] My contribution is licensed under AGPL-3.0 --- 🌟 **Thank you for your contribution!** ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/docs.md ================================================ # Pull Request - Documentation > **💡 Tip:** Recommended PR title format `docs(scope): description` > Example: `docs(api): update trading endpoints` | `docs(readme): add setup guide` --- ## 📝 Description --- ## 📚 Type of Documentation - [ ] 📖 README update - [ ] 📋 API documentation - [ ] 🎓 Tutorial/Guide - [ ] 📝 Code comments - [ ] 🔧 Configuration docs - [ ] 🐛 Fix typo/error - [ ] 🌍 Translation --- ## 🔗 Related Issues - Closes # - Related to # --- ## 📋 Changes Made - - --- ## 📸 Screenshots (if applicable) --- ## 🌐 Internationalization - [ ] English version complete - [ ] Chinese version complete - [ ] Both versions are consistent - [ ] N/A (only one language needed) --- ## ✅ Checklist ### Content Quality - [ ] Information is accurate and up-to-date - [ ] Language is clear and concise - [ ] No spelling or grammar errors - [ ] Links are valid and working - [ ] Code examples are tested and working - [ ] Formatting is consistent ### Documentation Standards - [ ] Follows project documentation style - [ ] Includes necessary examples - [ ] Technical terms are explained - [ ] Self-review completed ### Git - [ ] Commits follow conventional format - [ ] Rebased on latest `dev` branch - [ ] No merge conflicts --- ## 📚 Additional Notes --- **By submitting this PR, I confirm:** - [ ] I have read the [Contributing Guidelines](../../CONTRIBUTING.md) - [ ] I agree to the [Code of Conduct](../../CODE_OF_CONDUCT.md) - [ ] My contribution is licensed under AGPL-3.0 --- 🌟 **Thank you for your contribution!** ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/frontend.md ================================================ # Pull Request - Frontend > **💡 Tip:** Recommended PR title format `type(scope): description` > Example: `feat(ui): add dark mode toggle` | `fix(form): resolve validation bug` --- ## 📝 Description --- ## 🎯 Type of Change - [ ] 🐛 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change - [ ] 🎨 Code style update - [ ] ♻️ Refactoring - [ ] ⚡ Performance improvement --- ## 🔗 Related Issues - Closes # - Related to # --- ## 📋 Changes Made - - --- ## 📸 Screenshots / Demo **Before:** **After:** --- ## 🧪 Testing ### Test Environment - **OS:** - **Node Version:** - **Browser(s):** ### Manual Testing - [ ] Tested in development mode - [ ] Tested production build - [ ] Tested on multiple browsers - [ ] Tested responsive design - [ ] Verified no existing functionality broke --- ## 🌐 Internationalization - [ ] All user-facing text supports i18n - [ ] Both English and Chinese versions provided - [ ] N/A --- ## ✅ Checklist ### Code Quality - [ ] Code follows project style - [ ] Self-review completed - [ ] Comments added for complex logic - [ ] Code builds successfully (`npm run build`) - [ ] Ran `npm run lint` - [ ] No console errors or warnings ### Testing - [ ] Component tests added/updated - [ ] Tests pass locally ### Documentation - [ ] Updated relevant documentation - [ ] Updated type definitions (TypeScript) - [ ] Added JSDoc comments where necessary ### Git - [ ] Commits follow conventional format - [ ] Rebased on latest `dev` branch - [ ] No merge conflicts --- ## 📚 Additional Notes --- **By submitting this PR, I confirm:** - [ ] I have read the [Contributing Guidelines](../../CONTRIBUTING.md) - [ ] I agree to the [Code of Conduct](../../CODE_OF_CONDUCT.md) - [ ] My contribution is licensed under AGPL-3.0 --- 🌟 **Thank you for your contribution!** ================================================ FILE: .github/PULL_REQUEST_TEMPLATE/general.md ================================================ # Pull Request - General > **💡 Tip:** Recommended PR title format `type(scope): description` > Example: `feat(trader): add new strategy` | `fix(api): resolve auth issue` | `docs(readme): update` --- ## 📝 Description --- ## 🎯 Type of Change - [ ] 🐛 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change - [ ] 📝 Documentation update - [ ] 🎨 Code style update - [ ] ♻️ Refactoring - [ ] ⚡ Performance improvement - [ ] ✅ Test update - [ ] 🔧 Build/config change - [ ] 🔒 Security fix --- ## 🔗 Related Issues - Closes # - Related to # --- ## 📋 Changes Made - - --- ## 🧪 Testing - [ ] Tested locally - [ ] Tests pass - [ ] Verified no existing functionality broke **Test details:** --- ## ✅ Checklist ### Code Quality - [ ] Code follows project style - [ ] Self-review completed - [ ] Comments added for complex logic - [ ] No new warnings or errors ### Documentation - [ ] Updated relevant documentation - [ ] Added inline comments where necessary ### Git - [ ] Commits follow conventional format - [ ] Rebased on latest `dev` branch - [ ] No merge conflicts --- ## 🔒 Security (if applicable) - [ ] No API keys or secrets hardcoded - [ ] User inputs properly validated - [ ] N/A --- ## 📚 Additional Notes --- **By submitting this PR, I confirm:** - [ ] I have read the [Contributing Guidelines](../../CONTRIBUTING.md) - [ ] I agree to the [Code of Conduct](../../CODE_OF_CONDUCT.md) - [ ] My contribution is licensed under AGPL-3.0 --- 🌟 **Thank you for your contribution!** ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Summary - Problem: - What changed: - What did NOT change (scope boundary): ## Change Type - [ ] Bug fix - [ ] Feature - [ ] Refactoring - [ ] Docs - [ ] Security fix - [ ] Chore / infra ## Scope - [ ] Trading engine / strategies - [ ] MCP / AI clients - [ ] API / server - [ ] Telegram bot / agent - [ ] Web UI / frontend - [ ] Config / deployment - [ ] CI/CD / infra ## Linked Issues - Closes # - Related # ## Testing What you verified and how: - [ ] `go build ./...` passes - [ ] `go test ./...` passes - [ ] Manual testing done (describe below) ## Security Impact - Secrets/keys handling changed? (`Yes/No`) - New/changed API endpoints? (`Yes/No`) - User input validation affected? (`Yes/No`) ## Compatibility - Backward compatible? (`Yes/No`) - Config/env changes? (`Yes/No`) - Migration needed? (`Yes/No`) - If yes, upgrade steps: ================================================ FILE: .github/SECURITY.md ================================================ # Security Policy ## 🔒 Security at NOFX We take the security of NOFX seriously. This document outlines our security policy and procedures for reporting vulnerabilities. ## 📋 Supported Versions We release patches for security vulnerabilities. Which versions are eligible for receiving such patches depends on the CVSS v3.0 Rating: | Version | Supported | Status | | ------- | ------------------ | ------ | | 3.x.x | ✅ Yes | Active development | | 2.x.x | ⚠️ Limited support | Security fixes only | | < 2.0 | ❌ No | No longer supported | ## 🚨 Reporting a Vulnerability **Please do not report security vulnerabilities through public GitHub issues.** If you discover a security vulnerability, please follow these steps: ### 1. Private Disclosure Send an email to the security team at: - **Email**: tinklefund@gmail.com (or contact maintainers directly via Twitter DM) - **Twitter**: [@nofx_official](https://x.com/nofx_official) or [@Web3Tinkle](https://x.com/Web3Tinkle) ### 2. Information to Include Please include the following details in your report: - **Description**: A clear description of the vulnerability - **Impact**: The potential impact of the vulnerability - **Steps to Reproduce**: Detailed steps to reproduce the issue - **Proof of Concept**: If applicable, include PoC code or screenshots - **Suggested Fix**: If you have ideas on how to fix it - **Your Contact Information**: For follow-up questions ### 3. Response Timeline - **Initial Response**: Within 48 hours of receiving your report - **Status Update**: Weekly updates on the progress - **Fix Timeline**: Critical issues within 7 days, others within 30 days - **Public Disclosure**: After the fix is deployed (coordinated disclosure) ### 4. What to Expect After you submit a report: 1. ✅ We will acknowledge receipt of your report 2. 🔍 We will investigate and validate the issue 3. 📋 We will develop and test a fix 4. 🚀 We will deploy the fix to production 5. 📢 We will coordinate public disclosure with you 6. 🏆 We will credit you in the security advisory (if desired) ## 🛡️ Security Best Practices If you're using NOFX, please follow these security best practices: ### API Keys and Secrets - ❌ **Never commit** API keys, private keys, or secrets to version control - ✅ **Use environment variables** for all sensitive configuration - ✅ **Rotate keys regularly** (at least every 90 days) - ✅ **Use separate keys** for different environments (dev/staging/prod) - ✅ **Implement IP whitelisting** for exchange API keys - ✅ **Enable 2FA** on all exchange accounts ### Private Keys (Hyperliquid/Aster) - ❌ **Never share** your private keys with anyone - ✅ **Use dedicated wallets** for trading (not your main wallet) - ✅ **Use agent wallets** when available (Hyperliquid) - ✅ **Limit wallet funds** to amounts you can afford to lose - ✅ **Back up keys securely** using encrypted storage ### API Security - ✅ **Enable API key restrictions** (IP whitelist, permissions) - ✅ **Use read-only keys** for monitoring when possible - ✅ **Set withdrawal restrictions** on exchange accounts - ✅ **Monitor API usage** for unusual activity - ✅ **Revoke compromised keys** immediately ### System Security - ✅ **Keep dependencies updated** (run `npm audit` and `go mod tidy`) - ✅ **Use HTTPS** for all external communications - ✅ **Implement rate limiting** on API endpoints - ✅ **Enable authentication** on production deployments - ✅ **Review logs regularly** for suspicious activity - ✅ **Use Docker** for isolated environments ### Database Security - ✅ **Encrypt sensitive data** at rest (API keys, private keys) - ✅ **Restrict database access** (not exposed to internet) - ✅ **Back up regularly** with encrypted backups - ✅ **Use strong passwords** for database credentials ### Configuration Security - ❌ **Never use default passwords** or weak credentials - ✅ **Change default ports** if exposed to internet - ✅ **Disable unnecessary features** in production - ✅ **Use firewall rules** to restrict access - ✅ **Implement RBAC** for multi-user setups ## 🚫 Out of Scope The following are **not** considered security vulnerabilities: - ❌ Trading losses due to AI decisions - ❌ Exchange API rate limiting - ❌ Network latency issues - ❌ Market volatility impacts - ❌ Social engineering attacks - ❌ DDoS attacks on public infrastructure - ❌ Issues in third-party dependencies (report to upstream) - ❌ Already known and documented limitations ## 🏅 Recognition We appreciate the security research community's efforts. Contributors who responsibly disclose vulnerabilities will be: - ✅ Credited in security advisories (with permission) - ✅ Listed in our Hall of Fame (coming soon) - ✅ Eligible for bug bounties (when program launches) ## 📚 Security Resources ### Documentation - [Getting Started Guide](../docs/getting-started/README.md) - [Architecture Documentation](../docs/architecture/README.md) - [Docker Deployment Guide](../docs/getting-started/docker-deploy.en.md) - [Troubleshooting Guide](../docs/guides/TROUBLESHOOTING.md) ### Security Tools - **Code Scanning**: GitHub Advanced Security (enabled) - **Dependency Scanning**: Dependabot (enabled) - **Secret Scanning**: GitHub Secret Scanning (enabled) - **Container Scanning**: Docker Scout (recommended) ### External Resources - [OWASP Top 10](https://owasp.org/www-project-top-ten/) - [CWE Top 25](https://cwe.mitre.org/top25/archive/2023/2023_top25_list.html) - [NIST Cybersecurity Framework](https://www.nist.gov/cyberframework) ## 🔐 Encryption & Secure Storage NOFX uses the following security measures: - **AES-256 encryption** for sensitive data at rest (planned v3.1) - **TLS 1.3** for all network communications - **JWT tokens** for API authentication - **bcrypt** for password hashing (where applicable) - **Environment isolation** via Docker containers ## 📝 Security Audit History | Date | Version | Auditor | Report | |------|---------|---------|--------| | TBD | 3.0.0 | Internal | Initial security review | ## 🤝 Responsible Disclosure Policy We follow a **coordinated disclosure** approach: 1. 📧 Report received and acknowledged 2. 🔍 Investigation and validation (1-7 days) 3. 🛠️ Fix development and testing (7-30 days) 4. 🚀 Fix deployment to production 5. 📢 Public advisory published (after fix) 6. 🏆 Credit to researcher (if desired) **Please allow us time to fix critical issues before public disclosure.** ## 📞 Contact For security concerns, reach out via: - **Email**: Contact maintainers (see [GitHub profile](https://github.com/NoFxAiOS/nofx)) - **Twitter**: [@nofx_official](https://x.com/nofx_official) (DM open) - **Telegram**: [NOFX Developer Community](https://t.me/nofx_dev_community) - **GitHub**: Private security advisory (preferred for verified issues) ## ⚖️ Legal **Safe Harbor**: We consider security research conducted under this policy to be: - ✅ Authorized in accordance with applicable law - ✅ Lawful and in good faith - ✅ Exempt from DMCA and CFAA claims - ✅ Protected from legal action by the project **Conditions**: - Make a good faith effort to avoid privacy violations - Do not access or modify other users' data - Do not disrupt our services or infrastructure - Do not publicly disclose issues before we've had time to address them ## 🔄 Updates to This Policy This security policy may be updated from time to time. We will notify users of significant changes via: - GitHub release notes - Security advisories - Community channels (Telegram, Twitter) --- **Last Updated**: January 2025 **Version**: 1.0.0 Thank you for helping keep NOFX and its users safe! 🙏 --- ## 📖 Additional Resources - [Contributing Guidelines](../CONTRIBUTING.md) - [Code of Conduct](../CODE_OF_CONDUCT.md) - [License](../LICENSE) - [Changelog](../CHANGELOG.md) ================================================ FILE: .github/labeler.yml ================================================ # Auto-labeler configuration # Automatically adds labels based on changed files # Area: Frontend 'area: frontend': - changed-files: - any-glob-to-any-file: - 'web/**/*' - '*.tsx' - '*.ts' - '*.jsx' - '*.js' - '*.css' # Area: Backend 'area: backend': - changed-files: - any-glob-to-any-file: - '**/*.go' - 'go.mod' - 'go.sum' - 'cmd/**/*' - 'internal/**/*' - 'pkg/**/*' # Area: Exchange 'area: exchange': - changed-files: - any-glob-to-any-file: - 'internal/exchange/**/*' - 'pkg/exchange/**/*' - '**/binance*.go' - '**/hyperliquid*.go' - '**/aster*.go' - '**/okx*.go' - '**/bybit*.go' # Area: AI 'area: ai': - changed-files: - any-glob-to-any-file: - 'internal/ai/**/*' - 'pkg/ai/**/*' - '**/deepseek*.go' - '**/qwen*.go' - '**/openai*.go' - '**/claude*.go' # Area: API 'area: api': - changed-files: - any-glob-to-any-file: - 'internal/api/**/*' - 'pkg/api/**/*' - '**/handler*.go' - '**/router*.go' # Area: Security 'area: security': - changed-files: - any-glob-to-any-file: - '**/auth*.go' - '**/jwt*.go' - '**/encryption*.go' - '**/crypto*.go' - 'SECURITY.md' # Area: Database 'area: database': - changed-files: - any-glob-to-any-file: - 'internal/database/**/*' - 'internal/db/**/*' - '**/migration*.go' - '**/*.sql' - '**/schema*.go' # Area: UI/UX 'area: ui/ux': - changed-files: - any-glob-to-any-file: - 'web/src/components/**/*' - 'web/src/pages/**/*' - '**/*.css' - '**/style*.ts' # Area: Deployment 'area: deployment': - changed-files: - any-glob-to-any-file: - 'Dockerfile' - 'docker-compose*.yml' - '.github/workflows/**/*' - 'start.sh' - '**/*deploy*.md' # Type: Documentation 'type: documentation': - changed-files: - any-glob-to-any-file: - 'docs/**/*' - '*.md' - 'README*' - 'CHANGELOG*' - 'CONTRIBUTING.md' - 'CODE_OF_CONDUCT.md' # Type: Test 'type: test': - changed-files: - any-glob-to-any-file: - '**/*_test.go' - 'test/**/*' - '**/*.test.ts' - '**/*.test.tsx' - '**/*.spec.ts' # Dependencies 'dependencies': - changed-files: - any-glob-to-any-file: - 'go.mod' - 'go.sum' - 'package.json' - 'package-lock.json' - 'web/package.json' - 'web/package-lock.json' ================================================ FILE: .github/labels.yml ================================================ # GitHub Labels Configuration # Use https://github.com/crazy-max/ghaction-github-labeler to sync labels # Priority Labels - name: "priority: critical" color: "d73a4a" description: "Critical priority - requires immediate attention" - name: "priority: high" color: "ff6b6b" description: "High priority - should be addressed soon" - name: "priority: medium" color: "fbca04" description: "Medium priority - normal queue" - name: "priority: low" color: "0e8a16" description: "Low priority - nice to have" # Type Labels - name: "type: bug" color: "d73a4a" description: "Something isn't working" - name: "type: feature" color: "a2eeef" description: "New feature or request" - name: "type: enhancement" color: "84b6eb" description: "Improvement to existing feature" - name: "type: documentation" color: "0075ca" description: "Documentation improvements" - name: "type: security" color: "ee0701" description: "Security-related changes" - name: "type: performance" color: "f9d0c4" description: "Performance improvements" - name: "type: refactor" color: "fbca04" description: "Code refactoring" - name: "type: test" color: "c5def5" description: "Test-related changes" # Status Labels - name: "status: needs review" color: "fbca04" description: "PR is ready for review" - name: "status: needs changes" color: "d93f0b" description: "PR needs changes based on review" - name: "status: on hold" color: "fef2c0" description: "PR/issue is on hold" - name: "status: in progress" color: "0e8a16" description: "Currently being worked on" - name: "status: blocked" color: "d93f0b" description: "Blocked by another issue/PR" # Area Labels (aligned with roadmap) - name: "area: security" color: "ee0701" description: "Security enhancements (Phase 1.1)" - name: "area: ai" color: "7057ff" description: "AI capabilities and models (Phase 1.2)" - name: "area: exchange" color: "0075ca" description: "Exchange integrations (Phase 1.3)" - name: "area: architecture" color: "d4c5f9" description: "Project structure refactoring (Phase 1.4)" - name: "area: ui/ux" color: "c2e0c6" description: "User experience improvements (Phase 1.5)" - name: "area: frontend" color: "bfdadc" description: "Frontend (React/TypeScript)" - name: "area: backend" color: "c5def5" description: "Backend (Go)" - name: "area: api" color: "0e8a16" description: "API endpoints" - name: "area: database" color: "f9d0c4" description: "Database changes" - name: "area: deployment" color: "fbca04" description: "Deployment and CI/CD" # Special Labels - name: "good first issue" color: "7057ff" description: "Good for newcomers" - name: "help wanted" color: "008672" description: "Extra attention is needed" - name: "bounty" color: "1d76db" description: "Bounty available for this issue" - name: "bounty: claimed" color: "5319e7" description: "Bounty has been claimed" - name: "bounty: paid" color: "0e8a16" description: "Bounty has been paid" - name: "RFC" color: "d4c5f9" description: "Request for Comments - needs discussion" - name: "breaking change" color: "d73a4a" description: "Includes breaking changes" - name: "duplicate" color: "cfd3d7" description: "This issue or pull request already exists" - name: "invalid" color: "e4e669" description: "This doesn't seem right" - name: "wontfix" color: "ffffff" description: "This will not be worked on" - name: "dependencies" color: "0366d6" description: "Dependency updates" # Roadmap Phases - name: "roadmap: phase-1" color: "0e8a16" description: "Core Infrastructure Enhancement" - name: "roadmap: phase-2" color: "fbca04" description: "Testing & Stability" - name: "roadmap: phase-3" color: "0075ca" description: "Universal Market Expansion" - name: "roadmap: phase-4" color: "7057ff" description: "Advanced AI & Automation" - name: "roadmap: phase-5" color: "d73a4a" description: "Enterprise & Scaling" ================================================ FILE: .github/workflows/README.md ================================================ # GitHub Actions Workflows This directory contains the GitHub Actions workflows for the NOFX project. ## 📚 Documentation Index - **[README.md](./README.md)** - This file, overview of all workflows - **[PERMISSIONS.md](./PERMISSIONS.md)** - Detailed permission analysis and security model - **[TRIGGERS.md](./TRIGGERS.md)** - Comparison of event triggers (pull_request vs pull_request_target vs workflow_run) - **[FORK_PR_FLOW.md](./FORK_PR_FLOW.md)** - Complete analysis of what happens when a fork PR is submitted - **[FLOW_DIAGRAM.md](./FLOW_DIAGRAM.md)** - Visual flow diagrams and quick reference - **[SECRETS_SCANNING.md](./SECRETS_SCANNING.md)** - Secrets scanning solutions and TruffleHog setup ## 🚀 Quick Start **Want to understand how fork PRs work?** → Read [FLOW_DIAGRAM.md](./FLOW_DIAGRAM.md) **Need security details?** → Read [PERMISSIONS.md](./PERMISSIONS.md) **Confused about triggers?** → Read [TRIGGERS.md](./TRIGGERS.md) ## PR Check Workflows We use a **two-workflow pattern** to safely handle PR checks from both internal and fork PRs: ### 1. `pr-checks-run.yml` - Execute Checks **Trigger:** On pull request (opened, synchronize, reopened) **Permissions:** Read-only **Purpose:** Executes all PR checks with read-only permissions, making it safe for fork PRs. **What it does:** - ✅ Checks PR title format (Conventional Commits) - ✅ Calculates PR size - ✅ Runs backend checks (Go formatting, vet, tests) - ✅ Runs frontend checks (linting, type checking, build) - ✅ Saves all results as artifacts **Security:** Safe for fork PRs because it only has read permissions and cannot access secrets or modify the repository. ### 2. `pr-checks-comment.yml` - Post Results **Trigger:** When `pr-checks-run.yml` completes (workflow_run) **Permissions:** Write (pull-requests, issues) **Purpose:** Posts check results as PR comments, running in the main repository context. **What it does:** - ✅ Downloads artifacts from `pr-checks-run.yml` - ✅ Reads check results - ✅ Posts a comprehensive comment to the PR **Security:** Safe because: - Runs in the main repository context (not fork context) - Has write permissions but doesn't execute untrusted code - Only reads pre-generated results from artifacts ### 3. `pr-checks.yml` - Strict Checks **Trigger:** On pull request **Permissions:** Read + conditional write **Purpose:** Runs mandatory checks that must pass before PR can be merged. **What it does:** - ✅ Validates PR title (blocks merge if invalid) - ✅ Auto-labels PR based on size and files changed (non-fork only) - ✅ Runs backend tests (Go) - ✅ Runs frontend tests (React/TypeScript) - ✅ Security scanning (Trivy, Gitleaks) **Security:** - Fork PRs: Only runs read-only operations (tests, security scans) - Non-fork PRs: Can add labels and comments - Uses `continue-on-error` for operations that may fail on forks ## Why Two Workflows for PR Checks? ### The Problem When a PR comes from a forked repository: - GitHub restricts `GITHUB_TOKEN` permissions for security - Fork PRs cannot write comments, add labels, or access secrets - This prevents malicious contributors from: - Stealing repository secrets - Modifying workflow files to execute malicious code - Spamming issues/PRs with automated comments ### The Solution **Two-Workflow Pattern:** ``` Fork PR Submitted ↓ [pr-checks-run.yml] - Runs with read-only permissions - Executes all checks safely - Saves results to artifacts ↓ [pr-checks-comment.yml] - Triggered by workflow_run - Runs in main repo context (has write permissions) - Downloads artifacts - Posts comment with results ``` This approach: - ✅ Allows fork PRs to run checks - ✅ Safely posts results as comments - ✅ Prevents security vulnerabilities - ✅ Follows GitHub's best practices ### Can workflow_run Comment on Fork PRs? **Yes! ✅ The permissions are sufficient.** **Key Understanding:** - `workflow_run` executes in the **base repository** context - Fork PRs exist in the **base repository** (not in the fork) - The base repository's `GITHUB_TOKEN` has write permissions - Therefore, `workflow_run` can comment on fork PRs **Security:** - Fork PR code runs in isolated environment (read-only) - Comment workflow doesn't execute fork code - Only reads pre-generated artifact data **For detailed permission analysis, see:** [PERMISSIONS.md](./PERMISSIONS.md) ## Workflow Comparison | Workflow | Fork PRs | Write Access | Blocks Merge | Purpose | |----------|----------|--------------|--------------|---------| | `pr-checks-run.yml` | ✅ Yes | ❌ No | ❌ No | Advisory checks | | `pr-checks-comment.yml` | ✅ Yes | ✅ Yes* | ❌ No | Post results | | `pr-checks.yml` | ✅ Yes | ⚠️ Partial | ✅ Yes | Mandatory checks | \* Write access only in main repo context, not available to fork PR code ## File History - `pr-checks-advisory.yml.old` - Old advisory workflow that failed on fork PRs (deprecated) - Now replaced by the two-workflow pattern (`pr-checks-run.yml` + `pr-checks-comment.yml`) ## Testing the Workflows ### Test with a Fork PR 1. Fork the repository 2. Make changes in your fork 3. Create a PR to the main repository 4. Observe: - `pr-checks-run.yml` runs successfully with read-only access - `pr-checks-comment.yml` posts results as a comment - `pr-checks.yml` runs tests but skips labeling ### Test with a Branch PR 1. Create a branch in the main repository 2. Make changes 3. Create a PR 4. Observe: - All workflows run with full permissions - Labels are added automatically - Comments are posted ## References - [GitHub Actions: Keeping your GitHub Actions and workflows secure Part 1](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) - [Safely posting comments from untrusted workflows](https://securitylab.github.com/research/github-actions-building-blocks/) - [GitHub Actions: workflow_run trigger](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) ================================================ FILE: .github/workflows/docker-build.yml ================================================ name: Build and Push Docker Images on: push: branches: - main - dev - release/stable tags: - 'v*' pull_request: branches: - main - dev workflow_dispatch: env: REGISTRY_GHCR: ghcr.io jobs: prepare: name: Prepare repository metadata runs-on: ubuntu-22.04 outputs: image_base: ${{ steps.lowercase.outputs.image_base }} steps: - name: Convert repository name to lowercase id: lowercase run: | REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') echo "image_base=${REPO_LOWER}" >> $GITHUB_OUTPUT echo "Lowercase repository: ${REPO_LOWER}" build-and-push: name: Build ${{ matrix.name }} (${{ matrix.arch_tag }}) needs: prepare runs-on: ${{ matrix.runner }} permissions: contents: read packages: write strategy: fail-fast: false matrix: include: - name: backend dockerfile: ./docker/Dockerfile.backend image_suffix: backend platform: linux/amd64 arch_tag: amd64 runner: ubuntu-22.04 - name: backend dockerfile: ./docker/Dockerfile.backend image_suffix: backend platform: linux/arm64 arch_tag: arm64 runner: ubuntu-22.04-arm - name: frontend dockerfile: ./docker/Dockerfile.frontend image_suffix: frontend platform: linux/amd64 arch_tag: amd64 runner: ubuntu-22.04 - name: frontend dockerfile: ./docker/Dockerfile.frontend image_suffix: frontend platform: linux/arm64 arch_tag: arm64 runner: ubuntu-22.04-arm steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY_GHCR }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} continue-on-error: true - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: | ${{ env.REGISTRY_GHCR }}/${{ needs.prepare.outputs.image_base }}/nofx-${{ matrix.image_suffix }} ${{ secrets.DOCKERHUB_USERNAME && format('{0}/nofx-{1}', secrets.DOCKERHUB_USERNAME, matrix.image_suffix) || '' }} tags: | type=ref,event=branch,suffix=-${{ matrix.arch_tag }} type=semver,pattern={{version}},suffix=-${{ matrix.arch_tag }} type=semver,pattern={{major}}.{{minor}},suffix=-${{ matrix.arch_tag }} type=semver,pattern={{major}},suffix=-${{ matrix.arch_tag }} type=sha,prefix={{branch}}-,suffix=-${{ matrix.arch_tag }} - name: Build and push ${{ matrix.name }}-${{ matrix.arch_tag }} image uses: docker/build-push-action@v5 with: context: . file: ${{ matrix.dockerfile }} platforms: ${{ matrix.platform }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha,scope=${{ matrix.name }}-${{ matrix.arch_tag }} cache-to: type=gha,mode=max,scope=${{ matrix.name }}-${{ matrix.arch_tag }} build-args: | BUILD_DATE=${{ github.event.head_commit.timestamp }} VCS_REF=${{ github.sha }} VERSION=${{ github.ref_name }} - name: Image digest run: | echo "✅ Built: ${{ matrix.name }}-${{ matrix.arch_tag }}" echo "Platform: ${{ matrix.platform }}" echo "Tags: ${{ steps.meta.outputs.tags }}" create-manifest: name: Create multi-arch manifests if: github.event_name != 'pull_request' needs: [prepare, build-and-push] runs-on: ubuntu-22.04 permissions: contents: read packages: write strategy: matrix: image_suffix: [backend, frontend] steps: - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY_GHCR }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} continue-on-error: true - name: Create and push multi-arch manifest env: IMAGE_BASE: ${{ needs.prepare.outputs.image_base }} run: | # Convert branch name: release/stable -> release-stable (matching Docker metadata action) REF_NAME=$(echo "${{ github.ref_name }}" | sed 's/\//-/g') GHCR_IMAGE="${{ env.REGISTRY_GHCR }}/${IMAGE_BASE}/nofx-${{ matrix.image_suffix }}" echo "📦 Creating manifest for ${{ matrix.image_suffix }}" echo "Repository: ${IMAGE_BASE}" echo "Image: ${GHCR_IMAGE}" echo "Ref name: ${REF_NAME}" docker buildx imagetools create -t "${GHCR_IMAGE}:${REF_NAME}" \ "${GHCR_IMAGE}:${REF_NAME}-amd64" \ "${GHCR_IMAGE}:${REF_NAME}-arm64" # Only main branch gets the 'latest' tag (not dev) if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then docker buildx imagetools create -t "${GHCR_IMAGE}:latest" \ "${GHCR_IMAGE}:${REF_NAME}-amd64" \ "${GHCR_IMAGE}:${REF_NAME}-arm64" echo "✅ Created latest tag (main branch only)" fi # release/stable branch gets the 'stable' tag if [[ "${{ github.ref }}" == "refs/heads/release/stable" ]]; then docker buildx imagetools create -t "${GHCR_IMAGE}:stable" \ "${GHCR_IMAGE}:${REF_NAME}-amd64" \ "${GHCR_IMAGE}:${REF_NAME}-arm64" echo "✅ Created stable tag (release/stable branch)" fi if [[ -n "${{ secrets.DOCKERHUB_USERNAME }}" ]]; then DOCKERHUB_IMAGE="${{ secrets.DOCKERHUB_USERNAME }}/nofx-${{ matrix.image_suffix }}" docker buildx imagetools create -t "${DOCKERHUB_IMAGE}:${REF_NAME}" \ "${DOCKERHUB_IMAGE}:${REF_NAME}-amd64" \ "${DOCKERHUB_IMAGE}:${REF_NAME}-arm64" || true echo "✅ Created Docker Hub manifest" fi echo "🎉 Multi-arch manifest created successfully!" ================================================ FILE: .github/workflows/pr-checks-comment.yml ================================================ name: PR Checks - Comment # This workflow posts ADVISORY check results as comments # Runs in the main repo context with write permissions (SAFE) # Triggered after pr-checks-run.yml completes # # NOTE: PR title and size checks are handled by pr-checks.yml (no duplication) # This workflow only posts backend/frontend advisory check results on: workflow_run: workflows: ["PR Checks - Run"] types: [completed] # Write permissions - SAFE because runs in main repo context # This token has write access to the base repository # Fork PRs exist in the base repo, so we can comment on them permissions: pull-requests: write issues: write actions: read # Needed to download artifacts jobs: comment: name: Post Advisory Check Results runs-on: ubuntu-latest # Only run if the workflow was triggered by a pull_request event if: github.event.workflow_run.event == 'pull_request' steps: - name: Download artifacts id: download-artifacts continue-on-error: true uses: actions/download-artifact@v4 with: github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} path: artifacts - name: Debug workflow run info run: | echo "=== Workflow Run Debug Info ===" echo "Workflow Run ID: ${{ github.event.workflow_run.id }}" echo "Workflow Run Event: ${{ github.event.workflow_run.event }}" echo "Workflow Run Conclusion: ${{ github.event.workflow_run.conclusion }}" echo "Workflow Run Head SHA: ${{ github.event.workflow_run.head_sha }}" - name: List downloaded artifacts run: | echo "=== Checking downloaded artifacts ===" ls -la artifacts/ || echo "⚠️ No artifacts directory found" find artifacts/ -type f || echo "⚠️ No files found in artifacts" echo "" echo "Artifact download result: ${{ steps.download-artifacts.outcome }}" - name: Read backend results id: backend continue-on-error: true run: | if [ -f artifacts/backend-results/backend-results.json ]; then echo "=== Backend Results JSON ===" cat artifacts/backend-results/backend-results.json echo "pr_number=$(jq -r '.pr_number' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT echo "fmt_status=$(jq -r '.fmt_status' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT echo "vet_status=$(jq -r '.vet_status' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT echo "test_status=$(jq -r '.test_status' artifacts/backend-results/backend-results.json)" >> $GITHUB_OUTPUT # Read output files if [ -f artifacts/backend-results/fmt-files.txt ]; then echo "fmt_files<> $GITHUB_OUTPUT cat artifacts/backend-results/fmt-files.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi if [ -f artifacts/backend-results/vet-output-short.txt ]; then echo "vet_output<> $GITHUB_OUTPUT cat artifacts/backend-results/vet-output-short.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi if [ -f artifacts/backend-results/test-output-short.txt ]; then echo "test_output<> $GITHUB_OUTPUT cat artifacts/backend-results/test-output-short.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi else echo "pr_number=0" >> $GITHUB_OUTPUT echo "⚠️ Backend results artifact not found" fi - name: Read frontend results id: frontend continue-on-error: true run: | if [ -f artifacts/frontend-results/frontend-results.json ]; then echo "=== Frontend Results JSON ===" cat artifacts/frontend-results/frontend-results.json echo "build_status=$(jq -r '.build_status' artifacts/frontend-results/frontend-results.json)" >> $GITHUB_OUTPUT # Read output files if [ -f artifacts/frontend-results/build-output-short.txt ]; then echo "build_output<> $GITHUB_OUTPUT cat artifacts/frontend-results/build-output-short.txt >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi else echo "⚠️ Frontend results artifact not found" fi - name: Get PR information id: pr-info if: steps.backend.outputs.pr_number != '0' uses: actions/github-script@v7 with: script: | const prNumber = ${{ steps.backend.outputs.pr_number }}; // Get PR details const { data: pr } = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber }); // Check PR title format (Conventional Commits) const prTitle = pr.title; const conventionalCommitPattern = /^(feat|fix|docs|style|refactor|perf|test|chore|ci|security|build)(\(.+\))?: .+/; const titleValid = conventionalCommitPattern.test(prTitle); core.setOutput('pr_title', prTitle); core.setOutput('title_valid', titleValid); // Calculate PR size const additions = pr.additions; const deletions = pr.deletions; const total = additions + deletions; let size = ''; let sizeEmoji = ''; if (total < 300) { size = 'Small'; sizeEmoji = '🟢'; } else if (total < 1000) { size = 'Medium'; sizeEmoji = '🟡'; } else { size = 'Large'; sizeEmoji = '🔴'; } core.setOutput('pr_size', size); core.setOutput('size_emoji', sizeEmoji); core.setOutput('total_lines', total); core.setOutput('additions', additions); core.setOutput('deletions', deletions); - name: Post advisory results comment if: steps.backend.outputs.pr_number != '0' uses: actions/github-script@v7 with: script: | const prNumber = ${{ steps.backend.outputs.pr_number }}; let comment = '## 🤖 Advisory Check Results\n\n'; comment += 'These are **advisory** checks to help improve code quality. They won\'t block your PR from being merged.\n\n'; // PR Information section const prTitle = '${{ steps.pr-info.outputs.pr_title }}'; const titleValid = '${{ steps.pr-info.outputs.title_valid }}' === 'true'; const prSize = '${{ steps.pr-info.outputs.pr_size }}'; const sizeEmoji = '${{ steps.pr-info.outputs.size_emoji }}'; const totalLines = '${{ steps.pr-info.outputs.total_lines }}'; const additions = '${{ steps.pr-info.outputs.additions }}'; const deletions = '${{ steps.pr-info.outputs.deletions }}'; comment += '### 📋 PR Information\n\n'; // Title check if (titleValid) { comment += '**Title Format:** ✅ Good - Follows Conventional Commits\n'; } else { comment += '**Title Format:** ⚠️ Suggestion - Consider using `type(scope): description`\n'; comment += '
Recommended format\n\n'; comment += '**Valid types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `security`, `build`\n\n'; comment += '**Examples:**\n'; comment += '- `feat(trader): add new trading strategy`\n'; comment += '- `fix(api): resolve authentication issue`\n'; comment += '- `docs: update README`\n'; comment += '
\n\n'; } // Size check comment += `**PR Size:** ${sizeEmoji} ${prSize} (${totalLines} lines: +${additions} -${deletions})\n`; if (prSize === 'Large') { comment += '\n💡 **Suggestion:** This is a large PR. Consider breaking it into smaller, focused PRs for easier review.\n'; } comment += '\n'; // Backend checks const fmtStatus = '${{ steps.backend.outputs.fmt_status }}'; const vetStatus = '${{ steps.backend.outputs.vet_status }}'; const testStatus = '${{ steps.backend.outputs.test_status }}'; if (fmtStatus || vetStatus || testStatus) { comment += '\n### 🔧 Backend Checks\n\n'; if (fmtStatus) { comment += '**Go Formatting:** ' + fmtStatus + '\n'; const fmtFiles = `${{ steps.backend.outputs.fmt_files }}`; if (fmtFiles && fmtFiles.trim()) { comment += '
Files needing formatting\n\n```\n' + fmtFiles + '\n```\n
\n\n'; } } if (vetStatus) { comment += '**Go Vet:** ' + vetStatus + '\n'; const vetOutput = `${{ steps.backend.outputs.vet_output }}`; if (vetOutput && vetOutput.trim()) { comment += '
Issues found\n\n```\n' + vetOutput.substring(0, 1000) + '\n```\n
\n\n'; } } if (testStatus) { comment += '**Tests:** ' + testStatus + '\n'; const testOutput = `${{ steps.backend.outputs.test_output }}`; if (testOutput && testOutput.trim()) { comment += '
Test output\n\n```\n' + testOutput.substring(0, 1000) + '\n```\n
\n\n'; } } comment += '\n**Fix locally:**\n'; comment += '```bash\n'; comment += 'go fmt ./... # Format code\n'; comment += 'go vet ./... # Check for issues\n'; comment += 'go test ./... # Run tests\n'; comment += '```\n'; } // Frontend checks const buildStatus = '${{ steps.frontend.outputs.build_status }}'; if (buildStatus) { comment += '\n### ⚛️ Frontend Checks\n\n'; comment += '**Build & Type Check:** ' + buildStatus + '\n'; const buildOutput = `${{ steps.frontend.outputs.build_output }}`; if (buildOutput && buildOutput.trim()) { comment += '
Build output\n\n```\n' + buildOutput.substring(0, 1000) + '\n```\n
\n\n'; } comment += '\n**Fix locally:**\n'; comment += '```bash\n'; comment += 'cd web\n'; comment += 'npm run build # Test build (includes type checking)\n'; comment += '```\n'; } comment += '\n---\n\n'; comment += '### 📖 Resources\n\n'; comment += '- [Contributing Guidelines](https://github.com/NoFxAiOS/nofx/blob/dev/CONTRIBUTING.md)\n'; comment += '- [Migration Guide](https://github.com/NoFxAiOS/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md)\n\n'; comment += '**Questions?** Feel free to ask in the comments! 🙏\n\n'; comment += '---\n\n'; comment += '*These checks are advisory and won\'t block your PR from being merged. This comment is automatically generated from [pr-checks-run.yml](https://github.com/NoFxAiOS/nofx/blob/dev/.github/workflows/pr-checks-run.yml).*'; // Post comment await github.rest.issues.createComment({ issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, body: comment }); - name: Post fallback comment if no results if: steps.backend.outputs.pr_number == '0' uses: actions/github-script@v7 with: script: | // Try to get PR number from the workflow_run event const pulls = await github.rest.pulls.list({ owner: context.repo.owner, repo: context.repo.repo, state: 'open', head: `${context.repo.owner}:${{ github.event.workflow_run.head_branch }}` }); if (pulls.data.length === 0) { console.log('⚠️ Could not find PR for this workflow run'); return; } const pr = pulls.data[0]; const prNumber = pr.number; // Get PR information for fallback comment const prTitle = pr.title; const conventionalCommitPattern = /^(feat|fix|docs|style|refactor|perf|test|chore|ci|security|build)(\(.+\))?: .+/; const titleValid = conventionalCommitPattern.test(prTitle); const additions = pr.additions || 0; const deletions = pr.deletions || 0; const total = additions + deletions; let size = ''; let sizeEmoji = ''; if (total < 300) { size = 'Small'; sizeEmoji = '🟢'; } else if (total < 1000) { size = 'Medium'; sizeEmoji = '🟡'; } else { size = 'Large'; sizeEmoji = '🔴'; } let comment = '## ⚠️ Advisory Checks - Results Unavailable\n\n'; comment += 'The advisory checks workflow completed, but results could not be retrieved.\n\n'; // Add PR Information comment += '### 📋 PR Information\n\n'; if (titleValid) { comment += '**Title Format:** ✅ Good - Follows Conventional Commits\n'; } else { comment += '**Title Format:** ⚠️ Suggestion - Consider using `type(scope): description`\n'; } comment += `**PR Size:** ${sizeEmoji} ${size} (${total} lines: +${additions} -${deletions})\n\n`; if (size === 'Large') { comment += '💡 **Suggestion:** This is a large PR. Consider breaking it into smaller, focused PRs for easier review.\n\n'; } comment += '---\n\n'; comment += '### ⚠️ Backend/Frontend Check Results\n\n'; comment += 'Results could not be retrieved.\n\n'; comment += '**Possible reasons:**\n'; comment += '- Artifacts were not uploaded successfully\n'; comment += '- Artifacts expired (retention: 1 day)\n'; comment += '- Permission issues\n\n'; comment += '**What to do:**\n'; comment += `1. Check the [PR Checks - Run workflow](${context.payload.workflow_run?.html_url || 'logs'}) logs\n`; comment += '2. Ensure your code passes local checks:\n'; comment += '```bash\n'; comment += '# Backend\n'; comment += 'go fmt ./...\n'; comment += 'go vet ./...\n'; comment += 'go build\n'; comment += 'go test ./...\n\n'; comment += '# Frontend (if applicable)\n'; comment += 'cd web\n'; comment += 'npm run build\n'; comment += '```\n\n'; comment += '---\n\n'; comment += '*This is an automated fallback message. The advisory checks ran but results are not available.*'; await github.rest.issues.createComment({ issue_number: prNumber, owner: context.repo.owner, repo: context.repo.repo, body: comment }); ================================================ FILE: .github/workflows/pr-checks-run.yml ================================================ name: PR Checks - Run # This workflow runs advisory PR checks with read-only permissions # Safe for fork PRs - results are saved as artifacts # Companion workflow (pr-checks-comment.yml) will post comments # # NOTE: This workflow provides ADVISORY checks (non-blocking) # Main blocking checks are in pr-checks.yml # PR title and size checks are handled by pr-checks.yml (no duplication) on: pull_request: types: [opened, synchronize, reopened] branches: [main, dev] # Read-only permissions - safe for fork PRs permissions: contents: read jobs: # Backend advisory checks # Different from pr-checks.yml: these use continue-on-error and generate reports backend-checks: name: Backend Checks runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.21' - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y libta-lib-dev || true go mod download || true - name: Check Go formatting id: go-fmt continue-on-error: true run: | UNFORMATTED=$(gofmt -l . 2>/dev/null || echo "") if [ -n "$UNFORMATTED" ]; then echo "status=⚠️ Needs formatting" >> $GITHUB_OUTPUT echo "$UNFORMATTED" | head -10 > fmt-files.txt else echo "status=✅ Good" >> $GITHUB_OUTPUT echo "" > fmt-files.txt fi - name: Run go vet id: go-vet continue-on-error: true run: | if go vet ./... 2>&1 | tee vet-output.txt; then echo "status=✅ Good" >> $GITHUB_OUTPUT else echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT cat vet-output.txt | head -20 > vet-output-short.txt fi - name: Run tests id: go-test continue-on-error: true run: | if go test ./... -v 2>&1 | tee test-output.txt; then echo "status=✅ Passed" >> $GITHUB_OUTPUT else echo "status=⚠️ Failed" >> $GITHUB_OUTPUT cat test-output.txt | tail -30 > test-output-short.txt fi - name: Save backend results if: always() run: | cat > backend-results.json <> $GITHUB_OUTPUT else echo "exists=false" >> $GITHUB_OUTPUT fi - name: Install dependencies if: steps.check-web.outputs.exists == 'true' working-directory: ./web continue-on-error: true run: npm ci - name: Build and Type Check if: steps.check-web.outputs.exists == 'true' id: build working-directory: ./web continue-on-error: true run: | # build script includes: tsc && vite build if npm run build 2>&1 | tee build-output.txt; then echo "status=✅ Success" >> $GITHUB_OUTPUT else echo "status=⚠️ Failed" >> $GITHUB_OUTPUT cat build-output.txt | tail -30 > build-output-short.txt fi - name: Save frontend results if: always() && steps.check-web.outputs.exists == 'true' working-directory: ./web run: | cat > frontend-results.json <= 1000) { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number, body: comment }); } } catch (error) { console.log('Failed to add label/comment (expected for fork PRs):', error.message); } } else { console.log('Fork PR detected - skipping label/comment (will be handled by pr-checks-comment.yml)'); } # Backend checks (simplified - no TA-Lib required) backend-checks: name: Backend Code Quality (Go) runs-on: ubuntu-latest permissions: contents: read # Only need read access for testing steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.21' - name: Cache Go modules uses: actions/cache@v4 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - name: Download dependencies run: go mod download - name: Run go fmt continue-on-error: true # Don't block PR if formatting issues found run: | if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then echo "⚠️ Code formatting issues found. Please run 'go fmt ./...' locally." echo "" echo "Files needing formatting:" gofmt -s -l . echo "" echo "This is a warning and won't block your PR from being merged." exit 1 else echo "✅ All Go files are properly formatted" fi - name: Run go vet run: go vet ./... - name: Build run: go build -v -o nofx # Frontend tests frontend-tests: name: Frontend Tests (React/TypeScript) runs-on: ubuntu-latest permissions: contents: read # Only need read access for testing steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '18' - name: Cache Node modules uses: actions/cache@v4 with: path: web/node_modules key: ${{ runner.os }}-node-${{ hashFiles('web/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - name: Install dependencies working-directory: ./web run: npm ci - name: Build and Type Check working-directory: ./web run: npm run build # Note: build script runs "tsc && vite build" which includes type checking # Auto-label based on files changed auto-label: name: Auto Label PR runs-on: ubuntu-latest # Only run for non-fork PRs (fork PRs don't have write permission) if: github.event.pull_request.head.repo.full_name == github.repository permissions: contents: read pull-requests: write issues: write # Required: PRs are issues, labeler needs to modify issue labels steps: - uses: actions/labeler@v5 with: configuration-path: .github/labeler.yml repo-token: ${{ secrets.GITHUB_TOKEN }} # Check for security issues security-check: name: Security Scan runs-on: ubuntu-latest permissions: contents: read security-events: write # Required: Upload SARIF results to GitHub Security steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy results uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: 'trivy-results.sarif' # Check for secrets in code secrets-check: name: Check for Secrets runs-on: ubuntu-latest permissions: contents: read # Only need read access for scanning steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run TruffleHog OSS uses: trufflesecurity/trufflehog@main with: path: ./ base: ${{ github.event.pull_request.base.sha }} head: ${{ github.event.pull_request.head.sha }} extra_args: --debug --only-verified # All checks passed all-checks: name: All Checks Passed runs-on: ubuntu-latest needs: [validate-pr, backend-checks, frontend-tests, security-check, secrets-check] if: always() permissions: contents: read # Only need read access for status checking steps: - name: Check all jobs run: | # Note: validate-pr uses continue-on-error, so it won't block even if title format is invalid # We only care about actual test failures echo "validate-pr: ${{ needs.validate-pr.result }}" echo "backend-checks: ${{ needs.backend-checks.result }}" echo "frontend-tests: ${{ needs.frontend-tests.result }}" echo "security-check: ${{ needs.security-check.result }}" echo "secrets-check: ${{ needs.secrets-check.result }}" # Check if any critical checks failed (excluding validate-pr which is advisory) if [[ "${{ needs.backend-checks.result }}" == "failure" ]] || \ [[ "${{ needs.frontend-tests.result }}" == "failure" ]] || \ [[ "${{ needs.security-check.result }}" == "failure" ]] || \ [[ "${{ needs.secrets-check.result }}" == "failure" ]]; then echo "❌ Critical checks failed" exit 1 else echo "✅ All critical checks passed!" if [[ "${{ needs.validate-pr.result }}" != "success" ]]; then echo "ℹ️ Note: PR title format check is advisory only and doesn't block merging" fi fi ================================================ FILE: .github/workflows/pr-docker-check.yml ================================================ name: PR Docker Build Check # Lightweight build check on PR only, no image push # Strategy: Quick verify amd64 + spot check arm64 (backend only) on: pull_request: branches: - main - dev paths: - 'docker/**' - 'Dockerfile*' - 'go.mod' - 'go.sum' - '**.go' - 'web/**' - '.github/workflows/docker-build.yml' - '.github/workflows/pr-docker-check.yml' jobs: # Quick check: amd64 builds for all images docker-build-amd64: name: Build Check (amd64) runs-on: ubuntu-22.04 permissions: contents: read strategy: fail-fast: false matrix: include: - name: backend dockerfile: ./docker/Dockerfile.backend test_run: true # Needs test run - name: frontend dockerfile: ./docker/Dockerfile.frontend test_run: true steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build ${{ matrix.name }} image (amd64) id: build uses: docker/build-push-action@v5 with: context: . file: ${{ matrix.dockerfile }} platforms: linux/amd64 push: false load: true # Load into local Docker for test run tags: nofx-${{ matrix.name }}:pr-test cache-from: type=gha,scope=${{ matrix.name }}-amd64 cache-to: type=gha,mode=max,scope=${{ matrix.name }}-amd64 build-args: | BUILD_DATE=${{ github.event.pull_request.updated_at }} VCS_REF=${{ github.event.pull_request.head.sha }} VERSION=pr-${{ github.event.pull_request.number }} - name: Test run container (smoke test) if: matrix.test_run timeout-minutes: 2 run: | echo "🧪 Testing container startup..." # Start container docker run -d --name test-${{ matrix.name }} \ --health-cmd="exit 0" \ nofx-${{ matrix.name }}:pr-test # Wait for container to start (up to 30 seconds) for i in {1..30}; do if docker ps | grep -q test-${{ matrix.name }}; then echo "✅ Container started successfully" docker logs test-${{ matrix.name }} docker stop test-${{ matrix.name }} || true exit 0 fi sleep 1 done echo "❌ Container failed to start" docker logs test-${{ matrix.name }} || true exit 1 - name: Check image size run: | SIZE=$(docker image inspect nofx-${{ matrix.name }}:pr-test --format='{{.Size}}') SIZE_MB=$((SIZE / 1024 / 1024)) echo "📦 Image size: ${SIZE_MB} MB" # Warning thresholds if [ "${{ matrix.name }}" = "backend" ] && [ $SIZE_MB -gt 500 ]; then echo "⚠️ Warning: Backend image is larger than 500MB" elif [ "${{ matrix.name }}" = "frontend" ] && [ $SIZE_MB -gt 200 ]; then echo "⚠️ Warning: Frontend image is larger than 200MB" else echo "✅ Image size is reasonable" fi # ARM64 native build check: Uses GitHub native ARM64 runner (fast!) docker-build-arm64-native: name: Build Check (arm64 native - backend) runs-on: ubuntu-22.04-arm # Native ARM64 runner permissions: contents: read steps: - name: Checkout code uses: actions/checkout@v4 # Native ARM64 does not need QEMU, builds directly - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build backend image (arm64 native) uses: docker/build-push-action@v5 timeout-minutes: 15 # Native builds are faster! with: context: . file: ./docker/Dockerfile.backend platforms: linux/arm64 push: false load: true # Load locally for testing tags: nofx-backend:pr-test-arm64 cache-from: type=gha,scope=backend-arm64 cache-to: type=gha,mode=max,scope=backend-arm64 build-args: | BUILD_DATE=${{ github.event.pull_request.updated_at }} VCS_REF=${{ github.event.pull_request.head.sha }} VERSION=pr-${{ github.event.pull_request.number }} - name: Test run ARM64 container timeout-minutes: 2 run: | echo "🧪 Testing ARM64 container startup..." # Start container docker run -d --name test-backend-arm64 \ --health-cmd="exit 0" \ nofx-backend:pr-test-arm64 # Wait for startup for i in {1..30}; do if docker ps | grep -q test-backend-arm64; then echo "✅ ARM64 container started successfully" docker logs test-backend-arm64 docker stop test-backend-arm64 || true exit 0 fi sleep 1 done echo "❌ ARM64 container failed to start" docker logs test-backend-arm64 || true exit 1 - name: ARM64 build summary run: | echo "✅ Backend ARM64 native build successful!" echo "Using GitHub native ARM64 runner - no QEMU needed!" echo "Build time is ~3x faster than emulation" # Aggregate check results check-summary: name: Docker Build Summary needs: [docker-build-amd64, docker-build-arm64-native] runs-on: ubuntu-22.04 if: always() permissions: pull-requests: write # For posting comments steps: - name: Check build results id: check run: | echo "## 🐳 Docker Build Check Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Check amd64 build if [[ "${{ needs.docker-build-amd64.result }}" == "success" ]]; then echo "✅ **AMD64 builds**: All passed" >> $GITHUB_STEP_SUMMARY AMD64_OK=true else echo "❌ **AMD64 builds**: Failed" >> $GITHUB_STEP_SUMMARY AMD64_OK=false fi # Check arm64 build if [[ "${{ needs.docker-build-arm64-native.result }}" == "success" ]]; then echo "✅ **ARM64 build** (native): Backend passed (frontend will be verified after merge)" >> $GITHUB_STEP_SUMMARY ARM64_OK=true else echo "❌ **ARM64 build** (native): Backend failed" >> $GITHUB_STEP_SUMMARY ARM64_OK=false fi echo "" >> $GITHUB_STEP_SUMMARY if [ "$AMD64_OK" = true ] && [ "$ARM64_OK" = true ]; then echo "### 🎉 All checks passed!" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "After merge:" >> $GITHUB_STEP_SUMMARY echo "- Full multi-arch builds (amd64 + arm64) will run in parallel" >> $GITHUB_STEP_SUMMARY echo "- Estimated time: 15-20 minutes" >> $GITHUB_STEP_SUMMARY exit 0 else echo "### ❌ Build checks failed" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Please check the build logs above and fix the errors." >> $GITHUB_STEP_SUMMARY exit 1 fi - name: Comment on PR if: always() && github.event.pull_request.head.repo.full_name == github.repository uses: actions/github-script@v7 with: script: | const amd64Status = '${{ needs.docker-build-amd64.result }}'; const arm64Status = '${{ needs.docker-build-arm64-native.result }}'; const successIcon = '✅'; const failIcon = '❌'; const comment = [ '## 🐳 Docker Build Check Results', '', `**AMD64 builds**: ${amd64Status === 'success' ? successIcon : failIcon} ${amd64Status}`, `**ARM64 build** (native runner): ${arm64Status === 'success' ? successIcon : failIcon} ${arm64Status}`, '', amd64Status === 'success' && arm64Status === 'success' ? '### 🎉 All Docker builds passed!\n\n✨ Using GitHub native ARM64 runners - 3x faster than emulation!\n\nAfter merge, full multi-arch builds will run in ~10-12 minutes.' : '### ⚠️ Some builds failed\n\nPlease check the Actions tab for details.', '', 'Checked: Backend (amd64 + arm64 native), Frontend (amd64) | Powered by GitHub ARM64 Runners' ].join('\n'); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, body: comment }); ================================================ FILE: .github/workflows/pr-docker-compose-healthcheck.yml ================================================ name: PR Docker Compose Healthcheck # Verify docker-compose.yml healthcheck config works correctly in Alpine containers on: pull_request: branches: - main - dev paths: - 'docker-compose.yml' - 'docker/Dockerfile.backend' - 'docker/Dockerfile.frontend' - '.github/workflows/pr-docker-compose-healthcheck.yml' jobs: healthcheck-test: name: Test Docker Compose Healthcheck runs-on: ubuntu-22.04 timeout-minutes: 10 permissions: contents: read steps: - name: Checkout code uses: actions/checkout@v4 - name: Create minimal .env for testing run: | cat > .env < config.json < 0.5) labels.push('backend'); else if ((jsFiles + tsFiles) / totalFiles > 0.5) labels.push('frontend'); else if (mdFiles / totalFiles > 0.7) labels.push('documentation'); else labels.push('fullstack'); // --- Size label (like OpenClaw) --- const totalChanged = additions + deletions; const sizeLabels = ['size: XS', 'size: S', 'size: M', 'size: L', 'size: XL']; let sizeLabel = 'size: XL'; if (totalChanged < 50) sizeLabel = 'size: XS'; else if (totalChanged < 200) sizeLabel = 'size: S'; else if (totalChanged < 500) sizeLabel = 'size: M'; else if (totalChanged < 1000) sizeLabel = 'size: L'; labels.push(sizeLabel); // Ensure size labels exist for (const sl of sizeLabels) { try { await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: sl }); } catch (e) { if (e.status === 404) { await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: sl, color: 'b76e79' }); } } } // Remove stale size labels const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, }); for (const cl of currentLabels) { if (sizeLabels.includes(cl.name) && cl.name !== sizeLabel) { await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, name: cl.name, }).catch(() => {}); } } // Apply labels await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, labels: labels, }); console.log(`Applied labels: ${labels.join(', ')} (${totalChanged} lines changed)`); ================================================ FILE: .github/workflows/scripts/calculate_coverage.py ================================================ #!/usr/bin/env python3 """ Calculate Go test coverage and generate reports. This script parses the coverage.out file generated by `go test -coverprofile`, extracts coverage statistics, and generates formatted reports. """ import sys import re import os from typing import Dict, List, Tuple def parse_coverage_file(coverage_file: str) -> Tuple[float, Dict[str, float]]: """ Parse coverage output file and extract coverage data. Args: coverage_file: Path to coverage.out file Returns: Tuple of (total_coverage, package_coverage_dict) """ if not os.path.exists(coverage_file): print(f"Error: Coverage file {coverage_file} not found", file=sys.stderr) sys.exit(1) # Run go tool cover to get coverage data import subprocess try: result = subprocess.run( ['go', 'tool', 'cover', '-func', coverage_file], capture_output=True, text=True, check=True ) except subprocess.CalledProcessError as e: print(f"Error running go tool cover: {e}", file=sys.stderr) sys.exit(1) lines = result.stdout.strip().split('\n') package_coverage = {} total_coverage = 0.0 for line in lines: # Skip empty lines if not line.strip(): continue # Check for total coverage line if line.startswith('total:'): # Extract percentage from "total: (statements) XX.X%" match = re.search(r'(\d+\.\d+)%', line) if match: total_coverage = float(match.group(1)) continue # Parse package/file coverage # Format: "package/file.go:function statements coverage%" parts = line.split() if len(parts) >= 3: file_path = parts[0] coverage_str = parts[-1] # Extract package name from file path package = file_path.split(':')[0] package_name = '/'.join(package.split('/')[:-1]) if '/' in package else package # Extract coverage percentage match = re.search(r'(\d+\.\d+)%', coverage_str) if match: coverage_pct = float(match.group(1)) # Aggregate by package if package_name not in package_coverage: package_coverage[package_name] = [] package_coverage[package_name].append(coverage_pct) # Calculate average coverage per package package_avg = { pkg: sum(coverages) / len(coverages) for pkg, coverages in package_coverage.items() } return total_coverage, package_avg def get_coverage_status(coverage: float) -> Tuple[str, str, str]: """ Get coverage status based on percentage. Args: coverage: Coverage percentage Returns: Tuple of (emoji, status_text, badge_color) """ if coverage >= 80: return '🟢', 'excellent', 'brightgreen' elif coverage >= 60: return '🟡', 'good', 'yellow' elif coverage >= 40: return '🟠', 'fair', 'orange' else: return '🔴', 'needs improvement', 'red' def generate_coverage_report(coverage_file: str, output_file: str) -> None: """ Generate a detailed coverage report in markdown format. Args: coverage_file: Path to coverage.out file output_file: Path to output markdown file """ import subprocess try: result = subprocess.run( ['go', 'tool', 'cover', '-func', coverage_file], capture_output=True, text=True, check=True ) except subprocess.CalledProcessError as e: print(f"Error generating coverage report: {e}", file=sys.stderr) sys.exit(1) with open(output_file, 'w') as f: f.write("## Coverage by Package\n\n") f.write("```\n") f.write(result.stdout) f.write("```\n") def set_github_output(name: str, value: str) -> None: """ Set GitHub Actions output variable. Args: name: Output variable name value: Output variable value """ github_output = os.environ.get('GITHUB_OUTPUT') if github_output: with open(github_output, 'a') as f: f.write(f"{name}={value}\n") else: print(f"::set-output name={name}::{value}") def main(): """Main entry point.""" if len(sys.argv) < 2: print("Usage: calculate_coverage.py [output_file]", file=sys.stderr) sys.exit(1) coverage_file = sys.argv[1] output_file = sys.argv[2] if len(sys.argv) > 2 else 'coverage_report.md' # Parse coverage data total_coverage, package_coverage = parse_coverage_file(coverage_file) # Get coverage status emoji, status, badge_color = get_coverage_status(total_coverage) # Generate detailed report generate_coverage_report(coverage_file, output_file) # Output results print(f"Total Coverage: {total_coverage}%") print(f"Status: {status}") print(f"Badge Color: {badge_color}") # Set GitHub Actions outputs set_github_output('coverage', f'{total_coverage}%') set_github_output('coverage_num', str(total_coverage)) set_github_output('status', status) set_github_output('emoji', emoji) set_github_output('badge_color', badge_color) # Print package breakdown if package_coverage: print("\nCoverage by Package:") for package, coverage in sorted(package_coverage.items()): print(f" {package}: {coverage:.1f}%") if __name__ == '__main__': main() ================================================ FILE: .github/workflows/scripts/comment_pr.py ================================================ #!/usr/bin/env python3 """ Post or update coverage report comment on GitHub Pull Request. This script generates a formatted coverage report comment and posts it to a PR, or updates an existing coverage comment if one already exists. """ import os import sys import json import requests from typing import Optional def read_file(file_path: str) -> str: """Read file content.""" try: with open(file_path, 'r') as f: return f.read() except FileNotFoundError: print(f"Warning: File {file_path} not found", file=sys.stderr) return "" def generate_comment_body(coverage: str, emoji: str, status: str, badge_color: str, coverage_report_path: str) -> str: """ Generate the PR comment body. Args: coverage: Coverage percentage (e.g., "75.5%") emoji: Status emoji status: Status text badge_color: Badge color coverage_report_path: Path to detailed coverage report Returns: Formatted comment body in markdown """ coverage_report = read_file(coverage_report_path) # URL encode the coverage percentage for the badge coverage_encoded = coverage.replace('%', '%25') comment = f"""## {emoji} Go Test Coverage Report **Total Coverage:** `{coverage}` ({status}) ![Coverage](https://img.shields.io/badge/coverage-{coverage_encoded}-{badge_color})
📊 Detailed Coverage Report (click to expand) {coverage_report}
### Coverage Guidelines - 🟢 >= 80%: Excellent - 🟡 >= 60%: Good - 🟠 >= 40%: Fair - 🔴 < 40%: Needs improvement --- *This is an automated coverage report. The coverage requirement is advisory and does not block PR merging.* """ return comment def find_existing_comment(token: str, repo: str, pr_number: int) -> Optional[int]: """ Find existing coverage comment in the PR. Args: token: GitHub token repo: Repository in format "owner/repo" pr_number: Pull request number Returns: Comment ID if found, None otherwise """ url = f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments" headers = { 'Authorization': f'token {token}', 'Accept': 'application/vnd.github.v3+json' } try: response = requests.get(url, headers=headers) response.raise_for_status() comments = response.json() # Look for existing coverage comment for comment in comments: if (comment.get('user', {}).get('type') == 'Bot' and 'Go Test Coverage Report' in comment.get('body', '')): return comment['id'] except requests.exceptions.RequestException as e: print(f"Error fetching comments: {e}", file=sys.stderr) return None def post_comment(token: str, repo: str, pr_number: int, body: str) -> bool: """ Post a new comment to the PR. Args: token: GitHub token repo: Repository in format "owner/repo" pr_number: Pull request number body: Comment body Returns: True if successful, False otherwise """ url = f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments" headers = { 'Authorization': f'token {token}', 'Accept': 'application/vnd.github.v3+json' } data = {'body': body} try: response = requests.post(url, headers=headers, json=data) response.raise_for_status() print("✅ Coverage comment posted successfully") return True except requests.exceptions.RequestException as e: print(f"Error posting comment: {e}", file=sys.stderr) if hasattr(e, 'response') and e.response is not None: print(f"Response: {e.response.text}", file=sys.stderr) return False def update_comment(token: str, repo: str, comment_id: int, body: str) -> bool: """ Update an existing comment. Args: token: GitHub token repo: Repository in format "owner/repo" comment_id: Comment ID to update body: New comment body Returns: True if successful, False otherwise """ url = f"https://api.github.com/repos/{repo}/issues/comments/{comment_id}" headers = { 'Authorization': f'token {token}', 'Accept': 'application/vnd.github.v3+json' } data = {'body': body} try: response = requests.patch(url, headers=headers, json=data) response.raise_for_status() print("✅ Coverage comment updated successfully") return True except requests.exceptions.RequestException as e: print(f"Error updating comment: {e}", file=sys.stderr) if hasattr(e, 'response') and e.response is not None: print(f"Response: {e.response.text}", file=sys.stderr) return False def is_fork_pr(event_path: str) -> bool: """ Check if the PR is from a fork. Args: event_path: Path to GitHub event JSON file Returns: True if fork PR, False otherwise """ try: with open(event_path, 'r') as f: event = json.load(f) pr = event.get('pull_request', {}) head_repo = pr.get('head', {}).get('repo', {}).get('full_name') base_repo = pr.get('base', {}).get('repo', {}).get('full_name') return head_repo != base_repo except (FileNotFoundError, json.JSONDecodeError, KeyError) as e: print(f"Warning: Could not determine if fork PR: {e}", file=sys.stderr) return False def main(): """Main entry point.""" # Get environment variables token = os.environ.get('GITHUB_TOKEN') repo = os.environ.get('GITHUB_REPOSITORY') event_path = os.environ.get('GITHUB_EVENT_PATH', '') # Get arguments if len(sys.argv) < 6: print("Usage: comment_pr.py [coverage_report_path]", file=sys.stderr) sys.exit(1) pr_number = int(sys.argv[1]) coverage = sys.argv[2] emoji = sys.argv[3] status = sys.argv[4] badge_color = sys.argv[5] coverage_report_path = sys.argv[6] if len(sys.argv) > 6 else 'coverage_report.md' # Validate environment if not token: print("Error: GITHUB_TOKEN environment variable not set", file=sys.stderr) sys.exit(1) if not repo: print("Error: GITHUB_REPOSITORY environment variable not set", file=sys.stderr) sys.exit(1) # Check if fork PR if event_path and is_fork_pr(event_path): print("ℹ️ Fork PR detected - skipping comment (no write permissions)") sys.exit(0) # Generate comment body comment_body = generate_comment_body(coverage, emoji, status, badge_color, coverage_report_path) # Check for existing comment existing_comment_id = find_existing_comment(token, repo, pr_number) # Post or update comment if existing_comment_id: print(f"Found existing comment (ID: {existing_comment_id}), updating...") success = update_comment(token, repo, existing_comment_id, comment_body) else: print("No existing comment found, creating new one...") success = post_comment(token, repo, pr_number, comment_body) sys.exit(0 if success else 1) if __name__ == '__main__': main() ================================================ FILE: .github/workflows/scripts/requirements.txt ================================================ # Python dependencies for GitHub Actions scripts requests>=2.31.0 ================================================ FILE: .github/workflows/test.yml ================================================ name: Test on: push: branches: [main, dev] pull_request: branches: [main, dev] jobs: backend-tests: name: Backend Tests runs-on: ubuntu-latest continue-on-error: true # Don't block PRs steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.23' - name: Download dependencies run: go mod download - name: Run tests run: go test -v ./... - name: Generate coverage run: go test -coverprofile=coverage.out ./... continue-on-error: true frontend-tests: name: Frontend Tests runs-on: ubuntu-latest continue-on-error: true # Don't block PRs steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: web/package-lock.json - name: Install dependencies run: cd web && npm ci - name: Run tests run: cd web && npm run test ================================================ FILE: .gitignore ================================================ # IDE 配置文件 .idea/ *.iml *.xml # AI 工具 .claude/ CLAUDE.md # 编译产物 nofx-auto *.exe nofx nofx_test # Go 相关 *.test *.out .gocache/ # 操作系统 .DS_Store Thumbs.db # 临时文件 *.log *.tmp *.bak *.backup # 环境变量 .env config.json configbak.json # 数据目录(数据库、日志等) data/ *.db # 决策日志 decision_logs/ nofx_test # Node.js web/node_modules/ node_modules/ web/dist/ web/.vite/ # ESLint 临时报告文件(调试时生成,不纳入版本控制) eslint-*.json # VS code .vscode # 密钥和敏感文件 # 注意:crypto目录包含加密服务代码,应该被提交 # 只忽略密钥文件本身 secrets/ *.key *.pem *.p12 *.pfx rsa_key* # 加密相关 DATA_ENCRYPTION_KEY=* *.enc # Python __pycache__/ *.py[cod] *$py.class *.so .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # Python 虚拟环境 .venv/ venv/ ENV/ env/ .env/ # uv .uv/ uv.lock # Pytest .pytest_cache/ .coverage htmlcov/ *.cover .hypothesis/ # Jupyter Notebook .ipynb_checkpoints *.ipynb # pyenv .python-version # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ PR_DESCRIPTION.md ================================================ FILE: .husky/_/husky.sh ================================================ #!/usr/bin/env sh if [ -z "$husky_skip_init" ]; then debug () { if [ "$HUSKY_DEBUG" = "1" ]; then echo "husky (debug) - $1" fi } readonly hook_name="$(basename -- "$0")" debug "starting $hook_name..." if [ "$HUSKY" = "0" ]; then debug "HUSKY env variable is set to 0, skipping hook" exit 0 fi if [ -f ~/.huskyrc ]; then debug "sourcing ~/.huskyrc" . ~/.huskyrc fi readonly husky_skip_init=1 export husky_skip_init sh -e "$0" "$@" exitCode="$?" if [ $exitCode != 0 ]; then echo "husky - $hook_name hook exited with code $exitCode (error)" fi if [ $exitCode = 127 ]; then echo "husky - command not found in PATH=$PATH" fi exit $exitCode fi ================================================ FILE: .husky/pre-commit ================================================ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" cd web && npx lint-staged ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to the NOFX project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). **Languages:** [English](CHANGELOG.md) | [中文](CHANGELOG.zh-CN.md) --- ## [Unreleased] ### Added - Documentation system with multi-language support (EN/CN/RU/UK) - Complete getting-started guides (Docker, Custom API) - Architecture documentation with system design details - User guides with FAQ and troubleshooting - Community documentation with bounty programs ### Changed - Reorganized documentation structure into logical categories - Updated all README files with proper navigation links --- ## [3.0.0] - 2025-10-30 ### Added - Major Architecture Transformation 🚀 **Complete System Redesign - Web-Based Configuration Platform** This is a **major breaking update** that completely transforms NOFX from a static config-based system to a modern web-based trading platform. #### Database-Driven Architecture - SQLite integration replacing static JSON config - Persistent storage with automatic timestamps - Foreign key relationships and triggers for data consistency - Separate tables for AI models, exchanges, traders, and system config #### Web-Based Configuration Interface - Complete web-based configuration management (no more JSON editing) - AI Model setup through web interface (DeepSeek/Qwen API keys) - Exchange management (Binance/Hyperliquid credentials) - Dynamic trader creation (combine any AI model with any exchange) - Real-time control (start/stop traders without system restart) #### Flexible Architecture - Separation of concerns (AI models and exchanges independent) - Mix & match capability (unlimited combinations) - Scalable design (support for unlimited traders) - Clean slate approach (no default traders) #### Enhanced API Layer - RESTful design with complete CRUD operations - New endpoints: - `GET/PUT /api/models` - AI model configuration - `GET/PUT /api/exchanges` - Exchange configuration - `POST/DELETE /api/traders` - Trader management - `POST /api/traders/:id/start|stop` - Trader control - Updated documentation for all API endpoints #### Modernized Codebase - Type safety with proper separation of configuration types - Database abstraction with prepared statements - Comprehensive error handling and validation - Better code organization (database, API, business logic) ### Changed - **BREAKING**: Old `config.json` files no longer used - Configuration must be done through web interface - Much easier setup and better UX - No more server restarts for configuration changes ### Why This Matters - 🎯 **User Experience**: Much easier to configure and manage - 🔧 **Flexibility**: Create any combination of AI models and exchanges - 📊 **Scalability**: Support for complex multi-trader setups - 🔒 **Reliability**: Database ensures data persistence and consistency - 🚀 **Future-Proof**: Foundation for advanced features --- ## [2.0.2] - 2025-10-29 ### Fixed - Critical Bug Fixes: Trade History & Performance Analysis #### PnL Calculation - Major Error Fixed - **Fixed**: PnL now calculated as actual USDT amount instead of percentage only - Previously ignored position size and leverage (e.g., 100 USDT @ 5% = 1000 USDT @ 5%) - Now: `PnL (USDT) = Position Value × Price Change % × Leverage` - Impact: Win rate, profit factor, and Sharpe ratio now accurate #### Position Tracking - Missing Critical Data - **Fixed**: Open position records now store quantity and leverage - Previously only stored price and time - Essential for accurate PnL calculations #### Position Key Logic - Long/Short Conflict - **Fixed**: Changed from `symbol` to `symbol_side` format - Now properly distinguishes between long and short positions - Example: `BTCUSDT_long` vs `BTCUSDT_short` #### Sharpe Ratio Calculation - Code Optimization - **Changed**: Replaced custom Newton's method with `math.Sqrt` - More reliable, maintainable, and efficient ### Why This Matters - Historical trade statistics now show real USDT profit/loss - Performance comparison between different leverage trades is accurate - AI self-learning mechanism receives correct feedback - Multi-position tracking (long + short simultaneously) works correctly --- ## [2.0.2] - 2025-10-29 ### Fixed - Aster Exchange Precision Error - Fixed Aster exchange precision error (code -1111) - Improved price and quantity formatting to match exchange requirements - Added detailed precision processing logs for debugging - Enhanced all order functions with proper precision handling #### Technical Details - Added `formatFloatWithPrecision` function - Price and quantity formatted according to exchange specifications - Trailing zeros removed to optimize API requests --- ## [2.0.1] - 2025-10-29 ### Fixed - ComparisonChart Data Processing - Fixed ComparisonChart data processing logic - Switched from cycle_number to timestamp grouping - Resolved chart freezing issue when backend restarts - Improved chart data display (shows all historical data chronologically) - Enhanced debugging logs --- ## [2.0.0] - 2025-10-28 ### Added - Major Updates - AI self-learning mechanism (historical feedback, performance analysis) - Multi-trader competition mode (Qwen vs DeepSeek) - Binance-style UI (complete interface imitation) - Performance comparison charts (real-time ROI comparison) - Risk control optimization (per-coin position limit adjustment) ### Fixed - Fixed hardcoded initial balance issue - Fixed multi-trader data sync issue - Optimized chart data alignment (using cycle_number) --- ## [1.0.0] - 2025-10-27 ### Added - Initial Release - Basic AI trading functionality - Decision logging system - Simple Web interface - Support for Binance Futures - DeepSeek and Qwen AI model integration --- ## How to Use This Changelog ### For Users - Check the [Unreleased] section for upcoming features - Review version sections to understand what changed - Follow migration guides for breaking changes ### For Contributors When making changes, add them to the [Unreleased] section under appropriate categories: - **Added** - New features - **Changed** - Changes to existing functionality - **Deprecated** - Features that will be removed - **Removed** - Features that were removed - **Fixed** - Bug fixes - **Security** - Security fixes When releasing a new version, move [Unreleased] items to a new version section with date. --- ## Links - [Documentation](docs/README.md) - [Contributing Guidelines](CONTRIBUTING.md) - [Security Policy](SECURITY.md) - [GitHub Repository](https://github.com/NoFxAiOS/nofx) --- **Last Updated:** 2025-11-01 ================================================ FILE: CHANGELOG.zh-CN.md ================================================ # 更新日志 NOFX 项目的所有重要更改都将记录在此文件中。 本文件格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), 本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。 **语言:** [English](CHANGELOG.md) | [中文](CHANGELOG.zh-CN.md) --- ## [未发布] ### 新增 - 多语言文档系统(英文/中文/俄语/乌克兰语) - 完整的快速开始指南(Docker、自定义 API) - 架构文档,包含系统设计细节 - 用户指南,包含 FAQ 和故障排除 - 社区文档,包含悬赏计划 ### 变更 - 重组文档结构为逻辑分类 - 更新所有 README 文件,添加适当的导航链接 --- ## [3.0.0] - 2025-10-30 ### 新增 - 重大架构变革 🚀 **系统完全重新设计 - 基于 Web 的配置平台** 这是一个**重大破坏性更新**,将 NOFX 从基于静态配置的系统完全转变为现代化的 Web 交易平台。 #### 数据库驱动架构 - SQLite 集成,取代静态 JSON 配置 - 持久化存储,自动时间戳 - 外键关系和触发器确保数据一致性 - 为 AI 模型、交易所、交易员和系统配置分离表结构 #### 基于 Web 的配置界面 - 完整的 Web 配置管理(无需编辑 JSON) - 通过 Web 界面设置 AI 模型(DeepSeek/Qwen API 密钥) - 交易所管理(Binance/Hyperliquid 凭证) - 动态创建交易员(结合任意 AI 模型和交易所) - 实时控制(无需重启即可启动/停止交易员) #### 灵活架构 - 关注点分离(AI 模型和交易所独立) - 混合搭配能力(无限组合) - 可扩展设计(支持无限交易员) - 清洁起点(无默认交易员) #### 增强的 API 层 - RESTful 设计,完整的 CRUD 操作 - 新端点: - `GET/PUT /api/models` - AI 模型配置 - `GET/PUT /api/exchanges` - 交易所配置 - `POST/DELETE /api/traders` - 交易员管理 - `POST /api/traders/:id/start|stop` - 交易员控制 - 更新所有 API 端点文档 #### 现代化代码库 - 类型安全,适当分离配置类型 - 数据库抽象,使用预处理语句 - 全面的错误处理和验证 - 更好的代码组织(数据库、API、业务逻辑) ### 变更 - **破坏性变更**:不再使用旧的 `config.json` 文件 - 必须通过 Web 界面进行配置 - 设置更简单,用户体验更好 - 配置更改无需重启服务器 ### 为什么重要 - 🎯 **用户体验**:配置和管理更容易 - 🔧 **灵活性**:创建 AI 模型和交易所的任意组合 - 📊 **可扩展性**:支持复杂的多交易员设置 - 🔒 **可靠性**:数据库确保数据持久性和一致性 - 🚀 **面向未来**:为高级功能奠定基础 --- ## [2.0.2] - 2025-10-29 ### 修复 - 关键错误修复:交易历史和性能分析 #### 盈亏计算 - 重大错误修复 - **修复**:盈亏现在计算为实际 USDT 金额,而不是仅百分比 - 之前忽略了仓位大小和杠杆(例如,100 USDT @ 5% = 1000 USDT @ 5%) - 现在:`盈亏 (USDT) = 仓位价值 × 价格变化 % × 杠杆` - 影响:胜率、盈利因子和夏普比率现在准确 #### 仓位跟踪 - 缺失关键数据 - **修复**:持仓记录现在存储数量和杠杆 - 之前只存储价格和时间 - 这对准确的盈亏计算至关重要 #### 仓位键逻辑 - 多空冲突 - **修复**:从 `symbol` 改为 `symbol_side` 格式 - 现在正确区分多头和空头仓位 - 示例:`BTCUSDT_long` vs `BTCUSDT_short` #### 夏普比率计算 - 代码优化 - **变更**:用 `math.Sqrt` 替换自定义牛顿法 - 更可靠、可维护和高效 ### 为什么重要 - 历史交易统计现在显示真实的 USDT 盈亏 - 不同杠杆交易之间的性能比较准确 - AI 自学习机制接收正确的反馈 - 多仓位跟踪(同时多空)正常工作 --- ## [2.0.2] - 2025-10-29 ### 修复 - Aster 交易所精度错误 - 修复 Aster 交易所精度错误(代码 -1111) - 改进价格和数量格式化以匹配交易所要求 - 添加详细的精度处理日志用于调试 - 增强所有订单函数的精度处理 #### 技术细节 - 添加 `formatFloatWithPrecision` 函数 - 根据交易所规范格式化价格和数量 - 删除尾随零以优化 API 请求 --- ## [2.0.1] - 2025-10-29 ### 修复 - ComparisonChart 数据处理 - 修复 ComparisonChart 数据处理逻辑 - 从 cycle_number 切换到时间戳分组 - 解决后端重启时图表冻结问题 - 改进图表数据显示(按时间顺序显示所有历史数据) - 增强调试日志 --- ## [2.0.0] - 2025-10-28 ### 新增 - 重大更新 - AI 自学习机制(历史反馈、性能分析) - 多交易员竞赛模式(Qwen vs DeepSeek) - 币安风格 UI(完整界面仿制) - 性能比较图表(实时 ROI 比较) - 风险控制优化(每币种仓位限制调整) ### 修复 - 修复硬编码初始余额问题 - 修复多交易员数据同步问题 - 优化图表数据对齐(使用 cycle_number) --- ## [1.0.0] - 2025-10-27 ### 新增 - 初始版本 - 基础 AI 交易功能 - 决策日志系统 - 简单的 Web 界面 - 支持币安合约 - DeepSeek 和 Qwen AI 模型集成 --- ## 如何使用本更新日志 ### 用户 - 查看 [未发布] 部分了解即将推出的功能 - 查看版本部分了解变更内容 - 遵循破坏性变更的迁移指南 ### 贡献者 进行更改时,将它们添加到 [未发布] 部分的相应类别下: - **新增** - 新功能 - **变更** - 现有功能的变更 - **弃用** - 即将删除的功能 - **移除** - 已删除的功能 - **修复** - 错误修复 - **安全** - 安全修复 发布新版本时,将 [未发布] 项目移动到带日期的新版本部分。 --- ## 链接 - [文档](docs/README.md) - [贡献指南](CONTRIBUTING.md) - [安全策略](SECURITY.md) - [GitHub 仓库](https://github.com/NoFxAiOS/nofx) --- **最后更新:** 2025-11-01 ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct / 贡献者公约行为准则 **Languages:** [English](#english) | [中文](#中文) --- # English ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at: You can also report via: - **Twitter:** DM to [@nofx_official](https://x.com/nofx_official) All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq [translations]: https://www.contributor-covenant.org/translations --- # 中文 ## 我们的承诺 作为成员、贡献者和领导者,我们承诺使社区中的每个人都不受骚扰,无论其年龄、体型、明显或不明显的残疾、种族、性别特征、性别认同和表达、经验水平、教育程度、社会经济地位、国籍、个人外貌、种族、种姓、肤色、宗教或性认同和取向如何。 我们承诺以有助于开放、友好、多元、包容和健康社区的方式行事和互动。 ## 我们的标准 有助于为我们的社区创造积极环境的行为示例包括: * 对他人表现出同理心和善意 * 尊重不同的意见、观点和经验 * 给予并优雅地接受建设性反馈 * 接受责任并向受我们错误影响的人道歉,并从经验中学习 * 关注不仅对我们个人最好,而且对整个社区最好的事情 不可接受的行为示例包括: * 使用性化的语言或图像,以及任何形式的性关注或性挑逗 * 挑衅、侮辱性或贬损性评论,以及人身或政治攻击 * 公开或私下骚扰 * 未经他人明确许可,发布他人的私人信息,如物理地址或电子邮件地址 * 在专业环境中可能被合理认为不适当的其他行为 ## 执行责任 社区领导者负责阐明和执行我们可接受行为的标准,并将对他们认为不适当、威胁性、冒犯性或有害的任何行为采取适当和公平的纠正措施。 社区领导者有权利和责任删除、编辑或拒绝不符合本行为准则的评论、提交、代码、wiki 编辑、问题和其他贡献,并在适当时传达审核决定的原因。 ## 范围 本行为准则适用于所有社区空间,也适用于个人在公共空间正式代表社区的情况。代表我们社区的示例包括使用官方电子邮件地址、通过官方社交媒体账户发布信息,或在线上或线下活动中担任指定代表。 ## 执行 可以向负责执行的社区领导者报告滥用、骚扰或其他不可接受行为的实例: 您也可以通过以下方式报告: - **Twitter:** 私信 [@nofx_official](https://x.com/nofx_official) 所有投诉都将得到迅速和公正的审查和调查。 所有社区领导者都有义务尊重任何事件报告者的隐私和安全。 ## 执行指南 社区领导者将遵循这些社区影响指南来确定他们认为违反本行为准则的任何行动的后果: ### 1. 纠正 **社区影响**:使用不适当的语言或其他被认为在社区中不专业或不受欢迎的行为。 **后果**:社区领导者的私下书面警告,说明违规的性质和解释为什么行为不适当。可能要求公开道歉。 ### 2. 警告 **社区影响**:通过单一事件或一系列行动违规。 **后果**:警告并说明持续行为的后果。在指定时间内不与相关人员互动,包括不主动与执行行为准则的人互动。这包括避免在社区空间以及外部渠道(如社交媒体)的互动。违反这些条款可能导致临时或永久禁令。 ### 3. 临时禁令 **社区影响**:严重违反社区标准,包括持续的不当行为。 **后果**:在指定时间内临时禁止与社区进行任何形式的互动或公开交流。在此期间,不允许与相关人员进行公开或私下互动,包括不主动与执行行为准则的人互动。违反这些条款可能导致永久禁令。 ### 4. 永久禁令 **社区影响**:表现出违反社区标准的模式,包括持续的不当行为、对个人的骚扰,或对个人类别的攻击或贬低。 **后果**:永久禁止在社区内进行任何形式的公开互动。 ## 归属 本行为准则改编自 [贡献者公约][homepage] 2.1 版,可在 [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1] 获取。 社区影响指南受到 [Mozilla 行为准则执行阶梯][Mozilla CoC] 的启发。 有关本行为准则的常见问题解答,请参阅 [https://www.contributor-covenant.org/faq][FAQ]。翻译版本可在 [https://www.contributor-covenant.org/translations][translations] 获取。 [homepage]: https://www.contributor-covenant.org [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq [translations]: https://www.contributor-covenant.org/translations ================================================ FILE: CONTRIBUTING.md ================================================ # 🤝 Contributing to NOFX **Language:** [English](CONTRIBUTING.md) | [中文](docs/i18n/zh-CN/CONTRIBUTING.md) Thank you for your interest in contributing to NOFX! This document provides guidelines and workflows for contributing to the project. --- ## 📑 Table of Contents - [Code of Conduct](#code-of-conduct) - [How Can I Contribute?](#how-can-i-contribute) - [Development Workflow](#development-workflow) - [PR Submission Guidelines](#pr-submission-guidelines) - [Coding Standards](#coding-standards) - [Commit Message Guidelines](#commit-message-guidelines) - [Review Process](#review-process) - [Bounty Program](#bounty-program) --- ## 📜 Code of Conduct This project adheres to the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. --- ## 🎯 How Can I Contribute? ### 1. Report Bugs 🐛 - Use the [Bug Report Template](.github/ISSUE_TEMPLATE/bug_report.md) - Check if the bug has already been reported - Include detailed reproduction steps - Provide environment information (OS, Go version, etc.) ### 2. Suggest Features ✨ - Use the [Feature Request Template](.github/ISSUE_TEMPLATE/feature_request.md) - Explain the use case and benefits - Check if it aligns with the [project roadmap](docs/roadmap/README.md) ### 3. Submit Pull Requests 🔧 Before submitting a PR, please check the following: #### ✅ **Accepted Contributions** **High Priority** (aligned with roadmap): - 🔒 Security enhancements (encryption, authentication, RBAC) - 🧠 AI model integrations (GPT-4, Claude, Gemini Pro) - 🔗 Exchange integrations (OKX, Bybit, Lighter, EdgeX) - 📊 Trading data APIs (AI500, OI analysis, NetFlow) - 🎨 UI/UX improvements (mobile responsiveness, charts) - ⚡ Performance optimizations - 🐛 Bug fixes - 📝 Documentation improvements **Medium Priority:** - ✅ Test coverage improvements - 🌐 Internationalization (new language support) - 🔧 Build/deployment tooling - 📈 Monitoring and logging enhancements #### ❌ **Not Accepted** (without prior discussion) - Major architectural changes without RFC (Request for Comments) - Features not aligned with project roadmap - Breaking changes without migration path - Code that introduces new dependencies without justification - Experimental features without opt-in flag **⚠️ Important:** For major features, please open an issue for discussion **before** starting work. --- ## 🛠️ Development Workflow ### 1. Fork and Clone ```bash # Fork the repository on GitHub # Then clone your fork git clone https://github.com/YOUR_USERNAME/nofx.git cd nofx # Add upstream remote git remote add upstream https://github.com/NoFxAiOS/nofx.git ``` ### 2. Create a Feature Branch ```bash # Update your local dev branch git checkout dev git pull upstream dev # Create a new branch git checkout -b feature/your-feature-name # or git checkout -b fix/your-bug-fix ``` **Branch Naming Convention:** - `feature/` - New features - `fix/` - Bug fixes - `docs/` - Documentation updates - `refactor/` - Code refactoring - `perf/` - Performance improvements - `test/` - Test updates - `chore/` - Build/config changes ### 3. Set Up Development Environment ```bash # Install Go dependencies go mod download # Install frontend dependencies cd web npm install cd .. # Install TA-Lib (required) # macOS: brew install ta-lib # Ubuntu/Debian: sudo apt-get install libta-lib0-dev ``` ### 4. Make Your Changes - Follow the [coding standards](#coding-standards) - Write tests for new features - Update documentation as needed - Keep commits focused and atomic ### 5. Test Your Changes ```bash # Run backend tests go test ./... # Build backend go build -o nofx # Run frontend in dev mode cd web npm run dev # Build frontend npm run build ``` ### 6. Commit Your Changes Follow the [commit message guidelines](#commit-message-guidelines): ```bash git add . git commit -m "feat: add support for OKX exchange integration" ``` ### 7. Push and Create PR ```bash # Push to your fork git push origin feature/your-feature-name # Go to GitHub and create a Pull Request # Use the PR template and fill in all sections ``` --- ## 📝 PR Submission Guidelines ### Before Submitting - [ ] Code compiles successfully (`go build` and `npm run build`) - [ ] All tests pass (`go test ./...`) - [ ] No linting errors (`go fmt`, `go vet`) - [ ] Documentation is updated - [ ] Commits follow conventional commits format - [ ] Branch is rebased on latest `dev` ### PR Title Format Use [Conventional Commits](https://www.conventionalcommits.org/) format: ``` (): Examples: feat(exchange): add OKX exchange integration fix(trader): resolve position tracking bug docs(readme): update installation instructions perf(ai): optimize prompt generation refactor(core): extract common exchange interface ``` **Types:** - `feat` - New feature - `fix` - Bug fix - `docs` - Documentation - `style` - Code style (formatting, no logic change) - `refactor` - Code refactoring - `perf` - Performance improvement - `test` - Test updates - `chore` - Build/config changes - `ci` - CI/CD changes - `security` - Security improvements ### PR Description Use the [PR template](.github/PULL_REQUEST_TEMPLATE.md) and ensure: 1. **Clear description** of what and why 2. **Type of change** is marked 3. **Related issues** are linked 4. **Testing steps** are documented 5. **Screenshots** for UI changes 6. **All checkboxes** are completed ### PR Size Keep PRs focused and reasonably sized: - ✅ **Small PR** (< 300 lines): Ideal, fast review - ⚠️ **Medium PR** (300-1000 lines): Acceptable, may take longer - ❌ **Large PR** (> 1000 lines): Please break into smaller PRs --- ## 💻 Coding Standards ### Go Code ```go // ✅ Good: Clear naming, proper error handling func ConnectToExchange(apiKey, secret string) (*Exchange, error) { if apiKey == "" || secret == "" { return nil, fmt.Errorf("API credentials are required") } client, err := createClient(apiKey, secret) if err != nil { return nil, fmt.Errorf("failed to create client: %w", err) } return &Exchange{client: client}, nil } // ❌ Bad: Poor naming, no error handling func ce(a, s string) *Exchange { c := createClient(a, s) return &Exchange{client: c} } ``` **Best Practices:** - Use meaningful variable names - Handle all errors explicitly - Add comments for complex logic - Follow Go idioms and conventions - Run `go fmt` before committing - Use `go vet` and `golangci-lint` ### TypeScript/React Code ```typescript // ✅ Good: Type-safe, clear naming interface TraderConfig { id: string; exchange: 'binance' | 'hyperliquid' | 'aster'; aiModel: string; enabled: boolean; } const TraderCard: React.FC<{ trader: TraderConfig }> = ({ trader }) => { const [isRunning, setIsRunning] = useState(false); const handleStart = async () => { try { await startTrader(trader.id); setIsRunning(true); } catch (error) { console.error('Failed to start trader:', error); } }; return
...
; }; // ❌ Bad: No types, unclear naming const TC = (props) => { const [r, setR] = useState(false); const h = () => { startTrader(props.t.id); setR(true); }; return
...
; }; ``` **Best Practices:** - Use TypeScript strict mode - Define interfaces for all data structures - Avoid `any` type - Use functional components with hooks - Follow React best practices - Run `npm run lint` before committing ### File Structure ``` NOFX/ ├── cmd/ # Main applications ├── internal/ # Private code │ ├── exchange/ # Exchange adapters │ ├── trader/ # Trading logic │ ├── ai/ # AI integrations │ └── api/ # API handlers ├── pkg/ # Public libraries ├── web/ # Frontend │ ├── src/ │ │ ├── components/ │ │ ├── pages/ │ │ ├── hooks/ │ │ └── utils/ │ └── public/ └── docs/ # Documentation ``` --- ## 📋 Commit Message Guidelines ### Format ``` ():