Chạy Test End-to-End
cd ~/r2-fe
npx nx run remitano-plus:ensure-symlink
npx nx run remitano-plus:sync-deps
cd ~/r2-fe/packages/remitano-plus
yarn adb
yarn e2e:build:android:release
yarn e2e:test:android ../features/**/*.feature
yarn e2e:test:android ../features/login/login.feature
Chạy Rails Mock Server
USE_PROVIDER_MOCK_RESPONSE=true RAILS_ENV=test bin/rails s -p 3017
Ghi chú branch & lệnh broadcast
- Branch:
update-socket-order-book
FundTransferChannel.broadcast_to('fund_transfers_3',
fund_transfer: {
id: 1,
created_time: 1212232332,
status: 'pending',
coin: 'USDT',
amount: 2.0,
from: 'REMITANO',
to: 'SPOT'
}
)
UserChannel.broadcast_to('users_3', user: {
id: 3,
remi_account_linked: true,
kyc_level: '2.0',
updated_time: 21212
})
Cấu trúc data nhận về
{
"fund_transfer": {
"amount": "1.0",
"coin": "USDT",
"created_time": 1693906176932,
"from": "TRADING",
"id": 148,
"status": "confirmed",
"to": "REMITANO"
}
}
// LOG: receive data {"amount": "1.0", "coin": "USDT", ...}
Update Symbol
SymbolInfo.destroy_all
SymbolInfoUpdater.perform("okx")
SymbolInfo.all.each(&:enable!)
Test & Seed Database
- Chạy test:
bundle exec rspec - Chạy seed:
rails r dev-seeds/test-admin-user-roles.rb
Các lệnh hỗ trợ dev
- Xoá banner nếu version 0.55 không còn nhiều
- Enable index scan:
ActiveRecord::Base.connection.execute('SET enable_seqscan = OFF')
Build & Run Android App
cd packages/remitano-plus && ENVFILE=.env.dev npx react-native run-android --variant=coinsavi_devdebug --appId 'com.coinsavi.dev' && cd -
Sidekiq & các job liên quan
bundle exec sidekiq -q investment -q sub_account -q fund -q provider_sync
bundle exec sidekiq -q investment -q sub_account -q fund -q provider_sync -q investment_priority
- Push open investment:
Investment.last.push_changes
Tăng số lượng investment account
10.times { InvestmentAccount.create!(provider_name: "okx") }
InvestmentAccount.update_all(status: :available)
Database migration môi trường test
RAILS_ENV=test rails db:migrate
Subaccount và symbol info
- Tạo subaccount Gateio:
user.send(:create_sub_account!, "gateio") - Tạo symbol info:
SymbolInfoCrawler.new.perform - Kucoin subaccount:
- Lưu lại UID: 204728943
KucoinWrapper::BrokerAccount.singleton.create_sub_account(tag: "hoapn-sub1") KucoinWrapper::BrokerAccount.singleton.query_sub_account
- Lưu lại UID: 204728943
(Bỏ trống, dùng cho update sau)
Sửa lỗi PostgreSQL (Mac)
brew services stop postgresql@14
rm -f /opt/homebrew/opt/postgresql@14/homebrew.mxcl.postgresql@14.plist
brew services start postgresql@14
Funding Balances & Transfer nội bộ
usa.send(:api_provider_wrapper).get_funding_balances
usa.send(:api_provider_wrapper).transfer_within_account(
asset: "USDT",
amount: 9.4082,
from: "main",
to: "trade",
client_tran_id: Time.current.to_i
)
Wordpress Plugin & Theme Symlink
# List plugin folder size
ll -sh wp-content/plugins
ln -s /Applications/MAMP/htdocs/trade-savi-wp/plugins/custom-data-types /Applications/MAMP/htdocs/wordpress/wp-content/plugins/custom-data-types
ln -s /Applications/MAMP/htdocs/trade-savi-wp/plugins/google-site-kit /Applications/MAMP/htdocs/wordpress/wp-content/plugins/google-site-kit
ln -s /Applications/MAMP/htdocs/trade-savi-wp/plugins/kucoin-wp /Applications/MAMP/htdocs/wordpress/wp-content/plugins/kucoin-wp
ln -s /Applications/MAMP/htdocs/trade-savi-wp/themes/saviwp /Applications/MAMP/htdocs/wordpress/wp-content/themes/saviwp
Thông tin khác
- Keystore production:
coinsavi
CI/CD Logging trên CircleCI
echo "APP_AWS_BUCKET length: ${#APP_AWS_BUCKET}"
echo "APP_AWS_BUCKET first 3 chars: ${APP_AWS_BUCKET:0:3}"
echo "APP_AWS_BUCKET last 3 chars: ${APP_AWS_BUCKET: -3}"
Build iOS với xcodebuild
xcodebuild -workspace RemitanoPlus.xcworkspace -scheme RemitanoPlus-Dev -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.5' build
Hướng dẫn Build iOS và Podfile ví dụ
Build iOS với xcodebuild
xcodebuild -workspace RemitanoPlus.xcworkspace \
-scheme RemitanoPlus-Dev \
-configuration Debug \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,id=EF9C5275-4B18-4258-9A39-D272BE5352CF'
Ví dụ Podfile cho React Native (iOS)
# Resolve react_native_pods.rb với node để hỗ trợ hoisting
require Pod::Executable.execute_command('node', ['-p',
'require.resolve(
"react-native/scripts/react_native_pods.rb",
{paths: [process.argv[1]]},
)', __dir__]).strip
platform :ios, '15.0'
prepare_react_native_project!
# Nếu dùng `react-native-flipper` build iOS sẽ fail khi đặt NO_FLIPPER=1.
# Bạn có thể exclude bằng react-native.config.js:
# module.exports = {
# dependencies: {
# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
# },
# }
ENV['RCT_NEW_ARCH_ENABLED'] = '0'
ENV['RN_FABRIC_ENABLED'] = '0'
linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage.to_sym
end
def node_require(script)
# Resolve script với node để hỗ trợ hoisting
require Pod::Executable.execute_command('node', ['-p',
"require.resolve(
'#{script}',
{paths: [process.argv[1]]},
)", __dir__]).strip
end
node_require('react-native-permissions/scripts/setup.rb')
setup_permissions([
'AppTrackingTransparency',
'Camera',
'Microphone',
'Notifications',
'PhotoLibrary',
'PhotoLibraryAddOnly',
])
def default_pods
config = use_native_modules!
# Flags sẽ thay đổi phụ thuộc vào biến môi trường.
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true,
:fabric_enabled => ENV['RN_FABRIC_ENABLED'] == '1',
# Bật Flipper.
#
# Lưu ý: nếu dùng use_frameworks!, Flipper sẽ không hoạt động.
# :app_path là path tới root app của bạn.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
pod 'Firebase', :modular_headers => true
pod 'FirebaseCore', :modular_headers => true
pod 'FirebaseRemoteConfig', :modular_headers => true
pod 'GTMSessionFetcher', :modular_headers => true
pod 'FirebaseCoreExtension', :modular_headers => true
pod 'FirebaseAuthInterop', :modular_headers => true
pod 'FirebaseAppCheckInterop', :modular_headers => true
pod 'GoogleUtilities', :modular_headers => true
pod 'FirebaseInstallations', :modular_headers => true
pod 'AppAuth', :modular_headers => true
pod 'FirebaseABTesting', :modular_headers => true
pod 'GoogleDataTransport', :modular_headers => true
pod 'nanopb', :modular_headers => true
# pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '8.17.1'
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'FaceDetectorMLKit',
'BarcodeDetectorMLKit'
]
end
target 'RemitanoPlus' do
default_pods
end
target 'RemitanoPlus-Dev' do
default_pods
end
target 'RemitanoPlus-Stage' do
default_pods
end
target 'RemitanoPlus-E2e' do
default_pods
end
post_install do |installer|
config = use_native_modules!
# Fix Sentry C++ compile lỗi với Xcode 16+: bỏ 'const' trong std::vector<const T>
sentry_thread_cache_file = File.join(installer.sandbox.root, 'Sentry/Sources/Sentry/include/SentryThreadMetadataCache.hpp')
if File.exist?(sentry_thread_cache_file)
text = File.read(sentry_thread_cache_file)
new_text = text.gsub('std::vector<const ThreadHandleMetadataPair>', 'std::vector<ThreadHandleMetadataPair>')
File.write(sentry_thread_cache_file, new_text)
puts "✅ Patched SentryThreadMetadataCache.hpp for Xcode 16"
end
# Bổ sung include thiếu cho ucontext64_t với Xcode 16+
sentry_mach_context_file = File.join(installer.sandbox.root, 'Sentry/Sources/SentryCrash/Recording/Tools/SentryCrashMachineContext.c')
if File.exist?(sentry_mach_context_file)
text = File.read(sentry_mach_context_file)
unless text.include?('#include <sys/_types/_ucontext64.h>')
new_text = text.gsub('#include <mach/mach.h>', "#include <mach/mach.h>\n#include <sys/_types/_ucontext64.h>")
File.write(sentry_mach_context_file, new_text)
puts "✅ Patched SentryCrashMachineContext.c for Xcode 16"
end
end
react_native_post_install(
installer,
config[:reactNativePath],
:mac_catalyst_enabled => false
)
installer.pods_project.targets.each do |target|
target.build_configurations.each do |configuration|
target.build_settings(configuration.name)['ONLY_ACTIVE_ARCH'] = 'NO'
end
end
end