English | Tiếng Việt | Rules (Quy chuẩn) | Setup VPS
Copyright (C) 2026 Tran Thanh Binh, Nguyen Huynh Kim Ngan, Nguyen Trinh Anh Khoi, Trinh Minh Uyen.
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
🚨 IMPORTANT WARNING FOR BEGINNERS:
This project requires running SQL Server locally and PostgreSQL on a VPS. When changing the database structure (adding tables, modifying columns, etc.), you MUST create a migration using the method below!
# Run this command whenever you modify Entity/DbContext: .\add-migration.ps1 "MigrationName"If you forget to create a PostgreSQL migration:
- ✅ New code is deployed to VPS
- ❌ Database is NOT updated
- 💥 The application will CRASH when running!
➡️ For details, see Section 3. Create and Manage Database Migrations
🚨 IMPORTANT REGARDING DEPLOYMENT:
When deploying to a host, remember to configure
COOKIE_DOMAINin GitHub Secrets. If left blank when using a domain name, the session will not persist when the page reloads!Additionally, to run project tests quickly in Windows operation, you should also add this project folder to the exclusion list in Windows Defender (If you feel it's dangerous, you can omit this.). Follow these steps to exclude a specific folder from Windows Defender scans:
- Open Windows Security: Press the
Windowskey, type Windows Security, and press Enter.- Navigate to Protection: Click on Virus & threat protection in the left menu.
- Manage Settings: Under the Virus & threat protection settings section, click Manage settings.
- Exclusions: Scroll down to the bottom and click Add or remove exclusions.
- Add Folder: Click the + Add an exclusion button and select Folder from the dropdown menu.
- Select Path: Browse to the folder you want to exclude (folder contain project), select it, and click Select Folder.
- Confirm: If a User Account Control (UAC) prompt appears, click Yes.
- 1. System Requirements
- 2. Project Setup
- 3. Create and Manage Database Migrations
- 4. Running the application
- 5. Social Login Configuration Guide
- 6. Test Environment Configuration (Required)
- 7. GitHub Secrets Configuration (For Production Deploy)
- 8. Online Payment Configuration (English)
- 9. GHN (Giao Hàng Nhanh) Configuration (English)
- 10. AI Sidecar Configuration (Gemini & LangSmith)
- 11. Troubleshooting
It is highly recommended to use Windows to have the best programming experience.
Before getting started, make sure your computer has the following software installed:
- .NET 10 SDK - Download here
- SQL Server - Download here and SQL Server Management Studio (SSMS) - Download here
- Git - Download here
- Visual Studio 2026 - Download here
- Docker - Download here
Clone the project
git clone git@github.com:AnhEmMotor/AnhEmMotor-Backend.git
cd AnhEmMotor-BackendOpen the terminal at the project's root directory and run the following command:
dotnet restoreThe project uses the appsettings.json file for configuration. The template file is appsettings.Template.json.
-
Go to the
WebAPIdirectory:cd WebAPI
-
Create the
appsettings.jsonfile from the template. The code below runs in PowerShell. You can manually copy (Ctrl + C) and paste (Ctrl + V):Copy-Item appsettings.Template.json appsettings.json -
Create the
appsettings.Development.jsonfile (if necessary):Copy-Item appsettings.Template.Development.json appsettings.Development.json
Open the WebAPI/appsettings.json file and fill in the following information:
The project supports both SQL Server, MySQL and PostgreSQL. Choose the appropriate provider for your environment:
-
SQL Server (For Development on Windows):
{ "Provider": "SqlServer", "ConnectionStrings": { "StringConnection": "Server=localhost;Database=AnhEmMotorDB;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true" } } -
MySQL (For Production or Testing):
{ "Provider": "MySql", "ConnectionStrings": { "StringConnection": "Server=localhost;Database=anhemmotor;User=root;Password=your_password;" } } -
PostgreSQL (For Production or Testing):
{ "Provider": "PostgreSQL", "ConnectionStrings": { "StringConnection": "Server=localhost;Database=anhemmotor;User=root;Password=your_password;" } }
⚠️ IMPORTANT NOTE:
- Local Development: Use SQL Server
- Production/VPS: Use PostgreSQL
- Testing: Automatically uses PostgreSQL via Docker (no configuration needed, but Docker must be installed)
"ConnectionStrings": {
"StringConnection": "Server=localhost;Database=AnhEmMotorDB;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true"
}If you do not have a Database yet, please create one, then find its connection string. To find the Database connection string in Visual Studio:
- Go to Tools -> Connect to Database...
- In the new dialog box, fill in the following information:
- Server name: If your machine has only one SQL Server instance, type "."; if you have multiple servers, find the login name of that server.
- Authentication: Choose "Windows Authentication" (if logging in with a Windows user) or "SQL Server Authentication" (using a username and password).
- If the server requires Trust Certificate, check the "Trust Server Certificate" box.
- After filling in the details, the "Select or enter a database name:" dropdown will be enabled, select the Database you want to connect to (This is the Database you just created above).
- Then click Advanced. A string will appear in a new window, which is the Database connection string you need. Copy and paste it.
Configure JWT for user authentication:
"Jwt": {
"Key": "YourSuperSecretKeyThatIsAtLeast32CharactersLong!@#$%^&*()",
"Issuer": "https://localhost:7001",
"Audience": "https://localhost:3000",
"AccessTokenExpiryInMinutes": 5,
"RefreshTokenExpiryInDays": 7
}Note:
Key: Must be at least 32 characters longIssuer: API URL (usuallyhttps://localhost:7001)Audience: Client (frontend) URL. For local development, even with two projects and two different API endpoints, this doesn't matter much.
List of allowed hosts to access the API:
"AllowedHosts": "localhost;127.0.0.1;*.yourdomain.com"Or allow all:
"AllowedHosts": "*"Configure CORS to allow other domains to call the API:
"Cors": {
"AllowedOrigins": "https://frontend.com;http://localhost:3000"
}Or allow all (only for development):
"Cors": {
"AllowedOrigins": "*"
}Configure default roles and users:
"ProtectedAuthorizationEntities": {
"SuperRoles": ["Admin", "SuperAdmin"],
"ProtectedUsers": [
"admin@anhem.com:Admin@123456",
"superadmin@anhem.com:SuperAdmin@123456"
],
"DefaultRolesForNewUsers": ["User", "Customer"]
}Explanation:
- SuperRoles: Roles with full permissions that cannot be deleted
- Can have multiple roles:
["Admin", "SuperAdmin", "Manager"] - Each super role will automatically have all permissions
- Can have multiple roles:
- ProtectedUsers: Users that cannot be deleted, automatically created when the app starts
- Format:
"email:password"or just"email"(default password:DefaultProtectedUser@123456) - Example for multiple users:
[ "admin@anhem.com:Admin@123456", "manager@anhem.com", "support@anhem.com:Support@2024" ]
- Format:
- DefaultRolesForNewUsers: Roles automatically assigned to newly registered users
- Can have multiple default roles:
["User", "Customer", "Member"]
- Can have multiple default roles:
Configure Google and Facebook Client IDs and Secrets for Social Login:
"Authentication": {
"Google": {
"ClientId": "your-google-client-id",
"ClientSecret": "your-google-client-secret"
},
"Facebook": {
"AppId": "your-facebook-app-id",
"AppSecret": "your-facebook-app-secret"
}
}Configure initial data seeding:
"SeedingOptions": {
"RunDataSeedingOnStartup": true
}-
Configure undeletable product categories
"ProtectedProductCategory": [ "Xe máy", "Phụ kiện", "Phụ tùng" ],
-
Configure OpenTelemetry URL address to send project monitoring data during runtime
"OpenTelemetry": { "OtlpEndpoint": "http://localhost:4317" },
-
Open the terminal at the project's root directory
-
Run the command to create the database:
cd WebAPI dotnet ef database update
-
When running the project locally for the first time, necessary data for the project to start is not available, so data must be created. In the
appsettings.jsonfile, enable seeding:"SeedingOptions": { "RunDataSeedingOnStartup": true }
Run the application for the first time, the database and sample data will be created automatically.
Important: After running for the first time, disable
RunDataSeedingOnStartup:"RunDataSeedingOnStartup": false
🚨 IMPORTANT FOR BEGINNERS:
When you change the database structure (add tables, edit columns, etc.), you MUST create a migration! Otherwise, the project will encounter errors when deployed to the VPS!
Use a script wrapper to automatically create migrations for BOTH providers:
# From the project root directory
.\add-migration.ps1 "MigrationName"
⚠️ RULE: ONE BRANCH = ONE MIGRATIONTo keep the migration history clean and avoid deployment conflicts, each branch/Pull Request is only allowed to have EXACTLY ONE migration.
- If you need to make more changes to the database, remove the previous migration and create a new one, or combine your changes.
- The
add-migration.ps1script and GitHub Actions will block you if you try to include more than one migration.
Example:
.\add-migration.ps1 "AddProductColorColumn"The script will automatically:
- Create SQL Server migration (for local development)
- Create MySQL migration (for production deployment)
- Report obvious errors if there are issues
After creating the migration, update your local database:
dotnet ef database update --context ApplicationDBContext --project Infrastructure --startup-project WebAPIdotnet ef migrations add MigrationName --project Infrastructure --startup-project WebAPIdotnet ef migrations add MigrationName --context MySqlDbContext --output-dir MySqlMigrations --project Infrastructure --startup-project WebAPIdotnet ef migrations add MigrationName --context PostgreSqlDbContext --output-dir PostgreSqlMigrations --project Infrastructure --startup-project WebAPI
⚠️ DANGER:If you only create the SQL Server migration and forget to create the MySQL migration, when deploying to VPS:
- ✅ New code is deployed
- ❌ Database is NOT updated
- 💥 Application will CRASH (mismatch between code and DB schema)
Recommendation: Always use
add-migration.ps1to prevent forgetting!
# SQL Server migrations
dotnet ef migrations list --context ApplicationDBContext --project Infrastructure --startup-project WebAPI
# MySQL migrations
dotnet ef migrations list --context MySqlDbContext --project Infrastructure --startup-project WebAPI
# PostgreSQL migrations
dotnet ef migrations list --context PostgreSqlDbContext --project Infrastructure --startup-project WebAPI# SQL Server
dotnet ef migrations remove --context ApplicationDBContext--project Infrastructure --startup-project WebAPI
# MySQL
dotnet ef migrations remove --context MySqlDbContext --project Infrastructure --startup-project WebAPI
# PostgreSQL
dotnet ef migrations remove --context PostgreSqlDbContext --project Infrastructure --startup-project WebAPI- Open the
AnhEmMotor-Backend.slnfile with Visual Studio 2022 - Set the
WebAPIproject as the Startup Project (Right-click > Set as Startup Project). - Press
F5or click the Run button. Note that "https" should be selected next to the green arrow.
After running the application, access the Swagger UI to view the API documentation:
https://localhost:7001/swagger
-
Open a terminal at the
WebAPIdirectory:cd WebAPI
-
Run the application:
dotnet watch --project "WebAPI/WebAPI.csproj" --launch-profile "https"
-
The application will run at:
- HTTPS:
https://localhost:7001 - HTTP:
http://localhost:5000
- HTTPS:
If you don't have Social Login credentials yet, follow these steps to create your own Client ID and Client Secret:
- Go to Google Cloud Console.
- Create a Project: Click the project dropdown top-left -> "New Project" -> Enter name -> "Create".
- Configure OAuth Consent Screen:
- Search for "APIs & Services" > "OAuth consent screen".
- User Type: Select External -> "Create".
- App information: Fill in App name, User support email, and Developer contact information. Click "Save and Continue".
- Scopes: Click "Add or Remove Scopes" -> Search and select
.../auth/userinfo.emailand.../auth/userinfo.profile-> "Update" -> "Save and Continue". - Test users: Add your email to test before publishing.
- Create Credentials:
- Go to "Credentials" > "Create Credentials" > "OAuth client ID".
- Application type: Select Web application.
- Name: Enter your app name (e.g., "AnhEmMotor Web").
- Authorized JavaScript origins:
https://localhost:5173(Management UI)http://localhost:3000(Store UI)
- Authorized redirect URIs:
https://localhost:7001/signin-google(Backend API)
- Get Credentials: A dialog will appear with your Client ID and Client Secret. Copy them to your
appsettings.json.
- Go to Meta for Developers.
- Create an App:
- Click "My Apps" -> "Create App".
- Select "Authenticate and request data from users with Facebook Login" -> "Next".
- Fill in App Name and Contact Email -> "Create app".
- Configure Facebook Login:
- In the App Dashboard, find "Facebook Login" product -> click "Set up".
- Select "Web". You can skip the Quickstart steps.
- Get Credentials:
- Go to "App settings" > "Basic".
- Copy your App ID and App Secret.
- Fill in Privacy Policy URL (e.g.,
https://yourdomain.com/privacy).
- Configure Redirect URIs:
- Go to "Facebook Login" > "Settings".
- Under "Client OAuth settings", add your redirect URIs to "Valid OAuth Redirect URIs":
https://localhost:7001/signin-facebook
- Ensure "Embedded Browser OAuth Login" is turned on.
The project uses Testcontainers to automatically create an isolated MySQL environment when running tests.
Only requirement: Your computer must have Docker Desktop (or Docker Engine) installed and running.
How to run Tests:
- Start Docker.
- Run the command:
dotnet test - The system will automatically:
- Download the
postgres:17Docker Image. - Initialize the Container.
- Run Migrations.
- Execute Tests.
- Automatically clean up afterwards.
- Download the
The following secrets need to be set up in the GitHub repository:
Go to: Settings → Secrets and variables → Actions → New repository secret
| Secret Name | Description | Example |
|---|---|---|
ALLOWED_HOSTS |
Allowed domains | api.yourdomain.com;yourdomain.com or * |
CORS_ALLOWED_ORIGINS |
CORS Allowed Origins | https://anhemmotor.online;https://admin.anhemmotor.online;http://localhost:5002 |
DB_CONNECTION_STRING |
PostgreSQL connection string | Host=XXXXX;Port=5432;Database=AnhEmMotorDB;Username=postgres;Password=XXXXX;Include Error Detail=true; |
JWT_SECRET_KEY |
JWT secret key (>= 32 chars) | Your-Super-Secret-JWT-Key-32-Chars |
JWT_ISSUER |
API URL | https://api.yourdomain.com |
JWT_AUDIENCE |
Client URL | https://yourdomain.com |
PRODUCTION_SERVER_IP |
VPS IP or domain | * |
PRODUCTION_SERVER_USERNAME |
SSH username | root or youruser |
SERVER_REMOTE_ACCESS_PRIVATE_KEY |
Private SSH key | Content of ~/.ssh/id_rsa |
ENABLE_DATABASE_SEEDING |
Run data seeding on deploy (true/false) | false (production) or true (first-time setup) |
COOKIE_DOMAIN |
Cookie Domain (for refresh tokens) | .yourdomain.com or empty for IP address |
SUPER_ROLES_LIST |
Admin/SuperAdmin roles (JSON Array) | ["Admin", "SuperAdmin"] |
PROTECTED_USERS_LIST |
Un-deletable users (JSON Array) | ["admin@anhem.com:Admin@123456"] |
DEFAULT_ROLES_FOR_NEW_USER_LIST |
Default roles for new users (JSON Array) | ["User"] |
OTLP_ENDPOINT |
OpenTelemetry OTLP Endpoint | http://your-otel-collector:4317 |
GOOGLE_CLIENT_ID |
Google OAuth Client ID | your-google-client-id.apps.googleusercontent.com |
GOOGLE_CLIENT_SECRET |
Google OAuth Client Secret | GOCSPX-your-google-secret |
FACEBOOK_APP_ID |
Facebook App ID | your-facebook-app-id |
FACEBOOK_APP_SECRET |
Facebook App Secret | your-facebook-app-secret |
VNPAY__TMN_CODE |
VNPay TmnCode | your-vnpay-tmn-code |
VNPAY__HASH_SECRET |
VNPay HashSecret | your-vnpay-hash-secret |
VNPAY__BASE_URL |
VNPay BaseUrl | https://sandbox.vnpayment.vn/paymentv2/vpcpay.html |
VNPAY__CALLBACK_URL |
VNPay CallbackUrl | https://api.yourdomain.com/api/payment/vnpay-callback |
PAYOS__CLIENT_ID |
PayOS Client ID | your-payos-client-id |
PAYOS__API_KEY |
PayOS API Key | your-payos-api-key |
PAYOS__CHECKSUM_KEY |
PayOS Checksum Key | your-payos-checksum-key |
PAYOS__BASE_URL |
PayOS Base URL | https://api-merchant.payos.vn |
PAYOS__RETURN_URL |
PayOS Return URL | https://anhemmotor.online/payment-processing |
PAYOS__CANCEL_URL |
PayOS Cancel URL | https://anhemmotor.online/payment-processing |
UPLOAD_PATH |
Persistent image storage path | /var/www/anhemmotor/uploads |
GHN_TOKEN |
GHN API Token | a1b2c3d4e5f6g7h8... |
GHN_SHOP_ID |
GHN Shop ID | 012345 |
GHN_BASE_URL |
GHN API Base URL | https://dev-online-gateway.ghn.vn |
GEMINI_API_KEY |
Google Gemini API Key | AIzaSyB... |
GEMINI_MODEL |
Google Gemini Model Name | gemini-3.5-flash |
LANGSMITH_TRACING |
Enable LangSmith tracing (true/false) | true |
LANGSMITH_API_KEY |
LangSmith API Key | lsv2_pt_... |
Important: GitHub Secrets support JSON array format!
Single value:
["Admin"]Multiple values:
["Admin", "SuperAdmin", "Manager"]Single user:
["admin@anhem.com:Admin@123456"]Multiple users:
[
"admin@anhem.com:Admin@123456",
"manager@anhem.com",
"support@anhem.com:Support@2024"
]Single role:
["User"]Multiple roles:
["User", "Customer"]Note: Do not include spaces after commas in the JSON array! For example, the following two examples are incorrect:
["admin@anhem.com:Admin@123456" , "manager@anhem.com"]
["admin@anhem.com:Admin@123456", "manager@anhem.com"]To enable payment features, you need to obtain credentials from VNPay and PayOS.
- Register Test Account: Visit VNPay Sandbox or contact VNPay to get a test account.
- Obtain Credentials: After registration, you will receive an email containing:
- vnp_TmnCode: Terminal ID.
- vnp_HashSecret: Secret key used for signing hashes.
- Callback Configuration: Ensure the callback URL matches your environment:
https://api.yourdomain.com/api/payment/vnpay-callback(Production)https://localhost:7001/api/payment/vnpay-callback(Local)
- Create Account: Sign up at PayOS.vn.
- Create Payment Channel: Go to "Payment Channels" -> "Create Payment Channel" -> Choose the appropriate type.
- Get API Key: After creating a channel or by clicking on an existing one, you will find:
- Client ID
- API Key
- Checksum Key
To enable the automatic feature of pushing orders to GHN, you need to configure the settings in GitHub Secrets and in appsettings.*.json. The following guide will help you get these 3 pieces of information in the Staging/Development environment (Not production, to avoid losing money):
- Log in: Access the GHN Customer Website.
- Get Shop ID: Click on "Chủ cửa hàng" (Shop owner) in the sidebar. In the "Thông tin cá nhân" (Personal information) tab, there is an ID field. This ID is the value for the
GHN_SHOP_IDsecret (and in theappsettings.*.jsonfile, it is GHNSettings -> ShopId). - Get API Token: Also in the "Chủ cửa hàng" section, select the "Bảo mật" (Security) tab. On the "Token API & IP Tin cậy" line, click "Quản lý" (Manage). Another tab will open. In the "Token API" section, click the eye icon, verify your phone number, and a string will appear. This is the value for the
GHN_TOKENsecret (and in theappsettings.*.jsonfile, it is GHNSettings -> Token). - GHN URL: Use
https://dev-online-gateway.ghn.vnif you are in the Development environment. This is yourGHN_BASE_URL(and in theappsettings.*.jsonfile, it is GHNSettings -> BaseUrl). - Change shop location: Go to "Quản lý cửa hàng" (Store management) in the Sidebar, you need to change/add the default store location right there.
- Register Webhook: If you want to use Webhooks to receive notifications when an order is completed, you need to send an email to api@ghn.vn with the following information: Company Name, Client ID, Requested Environment, Webhook URL (which is the Endpoint URL running this project). Then wait for their response.
To enable the AI capabilities (e.g. smart search), you need a Gemini API Key and optionally LangSmith for tracing.
- Go to Google AI Studio.
- Sign in with your Google account.
- Click "Create API key" in a new or existing project.
- Copy the generated API key and put it into
AISetup -> GeminiApiKeyin yourappsettings.json.
- Go to LangSmith.
- Sign in or sign up.
- In the sidebar, go to Settings (gear icon) -> API Keys.
- Click "+ API Key", give it a name, and copy the key.
- In your
appsettings.json, setAISetup -> LangSmithTracingtotrueand paste the key intoLangSmithApiKey.
Solution: Make sure you have started Docker Desktop before running tests.
Solution:
- Check if SQL Server has been started. (Check if the "MSSQLSERVER" service has started)
- Check the connection string in
appsettings.json - Try a different connection string:
- For SQL Express:
Server=.\\SQLEXPRESS;... - For LocalDB:
Server=(localdb)\\MSSQLLocalDB;...
- For SQL Express:
Solution:
Add TrustServerCertificate=True to the connection string:
"StringConnection": "Server=localhost;Database=AnhEmMotorDB;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true"Solution:
Ensure Jwt.Key in appsettings.json is longer than 32 characters.
Solution:
- Run
dotnet restore - Rebuild solution
- Check if the connection string is correct
Solution:
Try run 2 command in Command Prompt Administrator:
sc stop winnat
sc start winnat
If it hasn't been successful yet, Restart your computer.
If it does not work, change the port in the WebAPI/Properties/launchSettings.json file (But since this file might be pushed to GitHub, remember to revert it to the old port):
"applicationUrl": "https://localhost:7002;http://localhost:5001"Copyright (C) 2026 Tran Thanh Binh, Nguyen Huynh Kim Ngan, Nguyen Trinh Anh Khoi, Trinh Minh Uyen.
Dự án này được cấp phép theo Giấy phép Apache 2.0. Xem tệp LICENSE để biết chi tiết.
🚨 CẢNH BÁO QUAN TRỌNG CHO NGƯỜI MỚI:
Dự án này sẽ cần chạy SQL Server trên máy local và PostgreSQL trên VPS. Khi thay đổi cấu trúc database (thêm bảng, sửa cột, etc.), BẮT BUỘC phải tạo migration theo cách thức dưới đây!
# Chạy lệnh này mỗi khi thay đổi Entity/DbContext: .\add-migration.ps1 "TenMigration"Nếu quên tạo PostgreSQL migration:
- ✅ Code mới được deploy lên VPS
- ❌ Database KHÔNG được update
- 💥 Application sẽ CRASH khi chạy!
➡️ Chi tiết xem Section 3. Tạo và Quản Lý Database Migrations
🚨 QUAN TRỌNG VỀ DEPLOY: Khi deploy lên host, hãy nhớ cấu hình
COOKIE_DOMAINtrong GitHub Secrets. Nếu để trống khi sử dụng tên miền, session sẽ không thể duy trì khi reload trang!Ngoài ra, để dự án Test chạy nhanh hơn trên máy Windows, hãy làm theo các bước sau để thêm folder dự án này vào danh sách không quét của Windows Defender (nếu bạn lo ngại về mã độc, bạn có thể không làm):
- Mở Windows Security: Nhấn phím
Windows, gõ Windows Security và nhấn Enter.- Đi đến mục Bảo vệ: Nhấn vào Virus & threat protection ở danh mục bên trái.
- Quản lý cài đặt: Tại phần Virus & threat protection settings, nhấn vào dòng Manage settings.
- Loại trừ (Exclusions): Cuộn xuống dưới cùng và nhấn vào Add or remove exclusions.
- Thêm thư mục: Nhấn nút + Add an exclusion và chọn Folder từ trình đơn thả xuống.
- Chọn đường dẫn: Tìm đến thư mục chứa dự án này, chọn nó và nhấn Select Folder.
- Xác nhận: Nếu có bảng thông báo User Account Control (UAC) hiện lên, hãy chọn Yes.
- 1. Yêu cầu hệ thống
- 2. Thiết lập dự án
- 3. Tạo và Quản Lý Database Migrations
- 4. Chạy ứng dụng
- 5. Cấu hình Môi trường Test (Yêu cầu)
- 6. Hướng dẫn Cấu hình Đăng nhập Mạng xã hội
- 7. GitHub Secrets Configuration (Cho Production Deploy)
- 8. Hướng dẫn Cấu hình Thanh toán Online
- 9. Hướng dẫn Cấu hình Giao Hàng Nhanh (GHN)
- 10. Hướng dẫn Cấu hình AI Sidecar (Gemini & LangSmith)
- 11. Troubleshooting
Máy tính lập trình nên dùng hệ điều hành Windows để có trải nghiệm lập trình tốt nhất.
Trước khi bắt đầu, đảm bảo máy tính của bạn đã cài đặt các phần mềm sau:
- .NET 10 SDK - Tải tại đây
- SQL Server - Tải tại đây và SQL Server Management Studio (SSMS) - Tải tại đây
- Git - Tải tại đây
- Visual Studio 2026 - Tải tại đây
- Docker - Tải tại đây
Clone dự án
git clone git@github.com:AnhEmMotor/AnhEmMotor-Backend.git
cd AnhEmMotor-Backend
Mở terminal tại thư mục gốc của dự án và chạy lệnh:
dotnet restoreDự án sử dụng file appsettings.json để cấu hình. File mẫu là appsettings.Template.json.
-
Di chuyển vào thư mục
WebAPI:cd WebAPI
-
Tạo file
appsettings.jsontừ file mẫu. Code bên dưới chạy trong Powershell. Bạn có thể tự copy Ctrl + C và Ctrl + V bằng tay:Copy-Item appsettings.Template.json appsettings.json -
Tạo file
appsettings.Development.json(nếu cần):Copy-Item appsettings.Template.Development.json appsettings.Development.json
Mở file WebAPI/appsettings.json và điền các thông tin sau:
Dự án hỗ trợ cả SQL Server, MySQL và PostgreSQL. Chọn provider phù hợp với môi trường:
-
SQL Server (Dành cho Development trên Windows):
{ "Provider": "SqlServer", "ConnectionStrings": { "StringConnection": "Server=localhost;Database=AnhEmMotorDB;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true" } } -
MySQL (Dành cho Production hoặc Testing):
{ "Provider": "MySql", "ConnectionStrings": { "StringConnection": "Server=localhost;Database=anhemmotor;User=root;Password=your_password;" } } -
PostgreSQL (Dành cho Production hoặc Testing):
{ "Provider": "PostgreSql", "ConnectionStrings": { "StringConnection": "Server=localhost;Database=anhemmotor;User=root;Password=your_password;" } }
⚠️ LƯU Ý QUAN TRỌNG:
- Local Development: Dùng SQL Server
- Production/VPS: sử dụng PostgreSql
- Testing: Tự động dùng PostgreSql qua Docker (không cần cấu hình, nhưng cần phải cài đặt Docker)
"ConnectionStrings": {
"StringConnection": "Server=localhost;Database=AnhEmMotorDB;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true"
}Nếu bạn chưa có Database, vui lòng tạo 1 Database, sau đó tìm chuỗi kết nối của Database đó. Để tìm chuỗi Database, làm như sau trong Visual Studio:
- Vào Tools -> Connect Databases...
- Trong hộp thoại mới hiện ra, điền các thông tin sau:
- Server name: Nếu máy chỉ có 1 server SQL Server, nên gõ dấu "."; nếu như có nhiều máy chủ, nên tìm tên đăng nhập của máy chủ đó.
- Authenication: Chọn kiểu login là "Windows Authenication" (nếu login bằng user trong Windows) hoặc "SQL Server Authenication" (dùng username - password đăng nhập)
- Nếu server cần Trust Certificate, hãy tích vào ô "Trust Server Certificate"
- Sau khi điền xong, ô "Select or enter a database name:" sáng lên, hãy chọn Database cần kết nối (Ở đây chính là Database mới tạo ở phía trên).
- Sau đó nhấn Advanced. Một chuỗi sẽ hiện ra trong cửa sổ mới, đó chính là chuỗi kết nối Database bạn cần dùng. Copy và dán vào chổ đó.
Cấu hình JWT để xác thực người dùng:
"Jwt": {
"Key": "YourSuperSecretKeyThatIsAtLeast32CharactersLong!@#$%^&*()",
"Issuer": "https://localhost:7001",
"Audience": "https://localhost:3000",
"AccessTokenExpiryInMinutes": 5,
"RefreshTokenExpiryInDays": 7
}Lưu ý:
Key: Phải dài hơn 32 ký tựIssuer: URL của API (thường làhttps://localhost:7001)Audience: URL của client (frontend). Với dự án chạy trên máy cá nhân, dù có tận 2 dự án với 2 đầu API khác nhau, nhưng điều này cũng không quan trọng.
Danh sách các hosts được phép truy cập:
"AllowedHosts": "localhost;127.0.0.1;*.yourdomain.com"Hoặc cho phép tất cả:
"AllowedHosts": "*"Cấu hình CORS để cho phép các domain khác gọi API:
"Cors": {
"AllowedOrigins": "https://frontend.com;http://localhost:3000"
}Hoặc cho phép tất cả (chỉ dùng cho dev):
"Cors": {
"AllowedOrigins": "*"
}Cấu hình roles và users mặc định:
"ProtectedAuthorizationEntities": {
"SuperRoles": ["Admin", "SuperAdmin"],
"ProtectedUsers": [
"admin@anhem.com:Admin@123456",
"superadmin@anhem.com:SuperAdmin@123456"
],
"DefaultRolesForNewUsers": ["User", "Customer"]
}Giải thích:
- SuperRoles: Roles có full quyền, không thể xóa
- Có thể có nhiều roles:
["Admin", "SuperAdmin", "Manager"] - Mỗi super role sẽ tự động có tất cả permissions
- Có thể có nhiều roles:
- ProtectedUsers: Users không thể xóa, được tạo tự động khi app khởi động
- Format:
"email:password"hoặc chỉ"email"(password mặc định:DefaultProtectedUser@123456) - Ví dụ nhiều users:
[ "admin@anhem.com:Admin@123456", "manager@anhem.com", "support@anhem.com:Support@2024" ]
- Format:
- DefaultRolesForNewUsers: Các Role mặc định được gán cho người dùng mới đăng ký
- Có thể gán nhiều role:
["User", "Customer", "Member"]
- Có thể gán nhiều role:
Cấu hình Client ID và Secret cho Google và Facebook:
"Authentication": {
"Google": {
"ClientId": "your-google-client-id",
"ClientSecret": "your-google-client-secret"
},
"Facebook": {
"AppId": "your-facebook-app-id",
"AppSecret": "your-facebook-app-secret"
}
}Cấu hình seeding dữ liệu ban đầu:
"SeedingOptions": {
"RunDataSeedingOnStartup": true
}-
Cấu hình các danh mục sản phẩm không xoá
"ProtectedProductCategory": [ "Xe máy", "Phụ kiện", "Phụ tùng" ],
-
Cấu hình địa chỉ OpenTelemetry URL để gửi dữ liệu giám sát dự án khi chạy
"OpenTelemetry": { "OtlpEndpoint": "http://localhost:4317" },
-
Mở terminal tại thư mục gốc của dự án
-
Chạy lệnh tạo database:
cd WebAPI dotnet ef database update
-
Khi chạy dự án lần đầu tiên trong máy, các dữ liệu cần có để dự án bắt đầu chạy vẫn chưa có, cần phải tạo dữ liệu. Trong file
appsettings.json, bật seeding:"SeedingOptions": { "RunDataSeedingOnStartup": true }
Chạy ứng dụng lần đầu tiên, database và dữ liệu mẫu sẽ được tạo tự động
Quan trọng: Sau khi chạy lần đầu, tắt
RunDataSeedingOnStartup:"RunDataSeedingOnStartup": false
🚨 QUAN TRỌNG CHO NGƯỜI MỚI:
Khi bạn thay đổi cấu trúc database (thêm bảng, sửa cột, etc.), BẮT BUỘC phải tạo migration! Nếu không, dự án sẽ bị lỗi khi deploy lên VPS!
Sử dụng script wrapper để tự động tạo migrations cho CẢ 2 providers:
# Từ thư mục gốc của dự án
.\add-migration.ps1 "TenMigration"
⚠️ QUY ĐỊNH: 1 NHÁNH = 1 MIGRATIONĐể giữ lịch sử migration sạch sẽ và tránh xung đột khi deploy, mỗi nhánh (branch) hoặc Pull Request chỉ được phép có DUY NHẤT 1 migration.
- Nếu bạn cần thay đổi thêm database, hãy xóa migration cũ và tạo lại cái mới, hoặc gộp các thay đổi lại.
- Script
add-migration.ps1và GitHub Actions sẽ chặn nếu bạn cố tình tạo nhiều hơn 1 migration trong cùng 1 PR.
Ví dụ:
.\add-migration.ps1 "AddProductColorColumn"Script sẽ tự động:
- Tạo SQL Server migration (cho local development)
- Tạo PostgreSql migration (cho production deployment)
- Báo lỗi rõ ràng nếu có vấn đề
Sau khi tạo migration, update database local:
dotnet ef database update --context ApplicationDBContext --project Infrastructure --startup-project WebAPIdotnet ef migrations add TenMigration --context ApplicationDBContext --project Infrastructure --startup-project WebAPIdotnet ef migrations add TenMigration --context MySqlDbContext --output-dir MySqlMigrations --project Infrastructure --startup-project WebAPIdotnet ef migrations add TenMigration --context PostgreSqlDbContext --output-dir PostgreSqlMigrations --project Infrastructure --startup-project WebAPI
⚠️ NGUY HIỂM:Nếu chỉ tạo SQL Server migration mà quên tạo PostgreSql migration, khi deploy lên VPS:
- ✅ Code mới được deploy
- ❌ Database KHÔNG được update
- 💥 Application sẽ CRASH (mismatch giữa code và DB schema)
Khuyến nghị: Luôn dùng
add-migration.ps1để tránh quên!
# SQL Server migrations
dotnet ef migrations list --context ApplicationDBContext --project Infrastructure --startup-project WebAPI
# MySQL migrations
dotnet ef migrations list --context MySqlDbContext --project Infrastructure --startup-project WebAPI
# PostgreSql migrations
dotnet ef migrations list --context PostgreSqlDbContext --project Infrastructure --startup-project WebAPI# SQL Server
dotnet ef migrations remove --context ApplicationDBContext --project Infrastructure --startup-project WebAPI
# MySQL
dotnet ef migrations remove --context MySqlDbContext --project Infrastructure --startup-project WebAPI
# PostgreSql
dotnet ef migrations remove --context PostgreSqlDbContext --project Infrastructure --startup-project WebAPI- Mở file
AnhEmMotor-Backend.slnbằng Visual Studio 2022 - Chọn project
WebAPIlàm Startup Project (chuột phải > Set as Startup Project). - Nhấn
F5hoặc click nút Run. Chú ý ở chổ mũi tên xanh phải đang chọn "https"
Sau khi chạy ứng dụng, truy cập Swagger UI để xem tài liệu API:
https://localhost:7001/swagger
-
Mở terminal tại thư mục
WebAPI:cd WebAPI
-
Chạy ứng dụng:
dotnet watch --project "WebAPI/WebAPI.csproj" --launch-profile "https"
-
Ứng dụng sẽ chạy tại:
- HTTPS:
https://localhost:7001 - HTTP:
http://localhost:5000
- HTTPS:
Sau khi chạy ứng dụng, truy cập Swagger UI để xem tài liệu API:
https://localhost:7001/swagger
Dự án sử dụng Testcontainers để tự động tạo môi trường PostgreSQL cô lập khi chạy Test.
Yêu cầu duy nhất: Máy tính phải cài đặt và đang chạy Docker Desktop (hoặc Docker Engine).
Cách chạy Test:
- Bật Docker.
- Chạy lệnh:
dotnet test - Hệ thống sẽ tự động:
- Tải Docker Image
postgres:17.9. - Khởi tạo Container.
- Chạy Migrations.
- Thực thi Test.
- Tự động dọn dẹp sau khi xong.
- Tải Docker Image
Nếu bạn chưa có thông tin xác thực Social Login, hãy làm theo các bước sau để tự tạo Client ID và Client Secret:
- Truy cập Google Cloud Console.
- Tạo Project: Click vào Project dropdown ở góc trên bên trái -> "New Project" -> Nhập tên dự án -> "Create".
- Cấu hình Màn hình ID OAuth:
- Tìm kiếm "APIs & Services" > "OAuth consent screen".
- User Type: Chọn External -> "Create".
- Thông tin ứng dụng: Điền tên App, User support email, và Developer contact information. Nhấn "Save and Continue".
- Phạm vi (Scopes): Nhấn "Add or Remove Scopes" -> Tìm và chọn
.../auth/userinfo.emailvà.../auth/userinfo.profile-> "Update" -> "Save and Continue". - Test users: Thêm email của bạn để test trước khi publish.
- Tạo Credentials:
- Vào mục "Credentials" > "Create Credentials" > "OAuth client ID".
- Application type: Chọn Web application.
- Name: Nhập tên ứng dụng của bạn (ví dụ: "AnhEmMotor Web").
- Authorized JavaScript origins:
https://localhost:5173(Giao diện Quản lý)http://localhost:3000(Giao diện Cửa hàng)
- Authorized redirect URIs:
https://localhost:7001/signin-google(Đầu API Backend)
- Lấy thông tin: Một hộp thoại sẽ hiện ra chứa Client ID và Client Secret. Hãy copy chúng vào file
appsettings.jsoncủa bạn.
- Truy cập Meta for Developers.
- Tạo Ứng dụng:
- Click "My Apps" -> "Create App".
- Chọn "Authenticate and request data from users with Facebook Login" -> "Next".
- Điền App Name và Contact Email -> "Create app".
- Cấu hình Facebook Login:
- Trong App Dashboard, tìm sản phẩm "Facebook Login" -> nhấn "Set up".
- Chọn "Web". Bạn có thể bỏ qua các bước Quickstart.
- Lấy thông tin:
- Vào mục "App settings" > "Basic".
- Sao chép App ID và App Secret.
- Điền Privacy Policy URL (ví dụ:
https://yourdomain.com/privacy).
- Cấu hình Redirect URIs:
- Vào mục "Facebook Login" > "Settings".
- Tại phần "Client OAuth settings", thêm redirect URIs vào mục "Valid OAuth Redirect URIs":
https://localhost:7001/signin-facebook
- Đảm bảo "Embedded Browser OAuth Login" đang được bật (ON).
Cần setup các secrets sau trong GitHub repository:
Vào: Settings → Secrets and variables → Actions → New repository secret
| Secret Name | Mô Tả | Ví Dụ |
|---|---|---|
ALLOWED_HOSTS |
Domains được phép | api.yourdomain.com;yourdomain.com hoặc * |
CORS_ALLOWED_ORIGINS |
CORS Allowed Origins | https://anhemmotor.online;https://admin.anhemmotor.online;http://localhost:5002 |
DB_CONNECTION_STRING |
PostgreSQL connection string | Host=XXXXX;Port=5432;Database=AnhEmMotorDB;Username=postgres;Password=XXXXX;Include Error Detail=true; |
JWT_SECRET_KEY |
JWT secret key (>= 32 chars) | Your-Super-Secret-JWT-Key-32-Chars |
JWT_ISSUER |
API URL | https://api.yourdomain.com |
JWT_AUDIENCE |
Client URL | https://yourdomain.com |
PRODUCTION_SERVER_IP |
VPS IP hoặc domain | * |
PRODUCTION_SERVER_USERNAME |
SSH username | root hoặc youruser |
SERVER_REMOTE_ACCESS_PRIVATE_KEY |
Private SSH key | Nội dung file ~/.ssh/id_rsa |
ENABLE_DATABASE_SEEDING |
Chạy data seeding khi deploy (true/false) | false (production) hoặc true (lần đầu setup) |
COOKIE_DOMAIN |
Cookie Domain (for refresh tokens) | .yourdomain.com hoặc để trống nếu đang chạy trên Localhost (Your IP) |
SUPER_ROLES_LIST |
Danh sách Roles Admin (JSON Array) | ["Admin", "SuperAdmin"] |
PROTECTED_USERS_LIST |
Người dùng không thể xóa (JSON Array) | ["admin@anhem.com:Admin@123456"] |
DEFAULT_ROLES_FOR_NEW_USER_LIST |
Roles mặc định cho user mới (JSON Array) | ["User"] |
OTLP_ENDPOINT |
Địa chỉ OpenTelemetry OTLP | http://your-otel-collector:4317 |
GOOGLE_CLIENT_ID |
Google OAuth Client ID | your-google-client-id.apps.googleusercontent.com |
GOOGLE_CLIENT_SECRET |
Google OAuth Client Secret | GOCSPX-your-google-secret |
FACEBOOK_APP_ID |
Facebook App ID | your-facebook-app-id |
FACEBOOK_APP_SECRET |
Facebook App Secret | your-facebook-app-secret |
VNPAY__TMN_CODE |
VNPay Terminal Code (TmnCode) | XXT7WT32 |
VNPAY__HASH_SECRET |
VNPay Hash Secret | 1ff1b8243e86dd74cd6f4c284b06bb2ad5... |
VNPAY__BASE_URL |
VNPay Base URL (Sandbox/Production) | https://sandbox.vnpayment.vn/paymentv2/vpcpay.html |
VNPAY__CALLBACK_URL |
VNPay Return/Callback URL | https://api.yourdomain.com/api/payment/vnpay-callback |
PAYOS__CLIENT_ID |
PayOS Client ID | your-payos-client-id |
PAYOS__API_KEY |
PayOS API Key | your-payos-api-key |
PAYOS__CHECKSUM_KEY |
PayOS Checksum Key | your-payos-checksum-key |
PAYOS__BASE_URL |
PayOS Base URL | https://api-merchant.payos.vn |
PAYOS__RETURN_URL |
PayOS Return URL | https://yourdomain.online/payment-processing |
PAYOS__CANCEL_URL |
PayOS Cancel URL | https://yourdomain.online/payment-processing |
UPLOAD_PATH |
Đường dẫn lưu trữ ảnh vĩnh viễn | /var/www/anhemmotor/uploads |
GHN_TOKEN |
Mã API Token từ GHN | a1b2c3d4e5f6g7h8... |
GHN_SHOP_ID |
Mã cửa hàng (Shop ID) trên GHN | 012345 |
GHN_BASE_URL |
Địa chỉ API của GHN | https://dev-online-gateway.ghn.vn |
GEMINI_API_KEY |
Google Gemini API Key | AIzaSyB... |
GEMINI_MODEL |
Tên mô hình Gemini | gemini-3.5-flash |
LANGSMITH_TRACING |
Bật LangSmith tracing (true/false) | true |
LANGSMITH_API_KEY |
LangSmith API Key | lsv2_pt_... |
Quan trọng: GitHub Secrets hỗ trợ JSON array format!
Single value:
["Admin"]Multiple values:
["Admin", "SuperAdmin", "Manager"]Single user:
["admin@anhem.com:Admin@123456"]Multiple users:
[
"admin@anhem.com:Admin@123456",
"manager@anhem.com",
"support@anhem.com:Support@2024"
]Single role:
["User"]Multiple roles:
["User", "Customer"]Lưu ý: Không có space (khoảng cách) sau dấu phẩy trong JSON array! Ví dụ viết như 2 ví dụ sau là sai:
["admin@anhem.com:Admin@123456" , "manager@anhem.com"]
["admin@anhem.com:Admin@123456", "manager@anhem.com"]Để tính năng thanh toán hoạt động, bạn cần lấy các mã bí mật từ cổng VNPay và PayOS.
- Đăng ký tài khoản Test: Truy cập VNPay Sandbox hoặc liên hệ VNPay để lấy tài khoản test.
- Lấy thông tin: Sau khi đăng ký, bạn sẽ nhận được email chứa:
- vnp_TmnCode: Mã định danh cửa hàng (Terminal ID).
- vnp_HashSecret: Chuỗi bí mật dùng để tạo chữ ký (Secret Key).
- Cấu hình Callback: Đảm bảo URL gọi lại khớp với cấu hình của bạn:
https://api.yourdomain.com/api/payment/vnpay-callback(Production)https://localhost:7001/api/payment/vnpay-callback(Local)
- Tạo tài khoản: Đăng ký tại PayOS.vn.
- Tạo kênh thanh toán: Vào mục "Kênh thanh toán" -> "Tạo kênh thanh toán" -> Chọn loại hình phù hợp.
- Lấy API Key: Ở lần đầu tiên sau khi tạo kênh thanh toán hoặc khi bấm vào kênh thanh toán trong phần "Kênh thanh toán", bạn sẽ thấy:
- Client ID
- API Key
- Checksum Key
Để kích hoạt tính năng tự động đẩy đơn hàng sang GHN, bạn cần thiết lập cấu hình trên GitHub Secrets và trong appsetting.*.json. Hướng dẫn sau sẽ giúp bạn lấy được 3 thông tin này dưới tầng Staging/Development (Không phải production, tránh bị mất tiền):
- Đăng nhập: Truy cập vào Website Khách hàng GHN.
- Lấy Shop ID (Mã Cửa Hàng): Bạn sẽ nhấn vào chữ "Chủ cửa hàng" ở tại sidebar, Ở trong tab "Thông tin cá nhân", có 1 ô ID. ID này chính là giá trị cho bí mật
GHN_SHOP_ID(và trong file appsettings.*.json là GHNSettings -> ShopId). - Lấy API Token: Cũng ở trong mục "Chủ cửa hàng", chọn tab "Bảo mật", trên dòng "Token API & IP Tin cậy", nhấn "Quản lý", 1 tab khác hiện ra, trong phần "Token API", bạn nhấn vào hình con mắt, xác thực số điện thoại và 1 chuỗi sẽ hiện ra. Đây chính là giá trị cho bí mật
GHN_TOKEN(và trong file appsettings.*.json là GHNSettings -> Token). - URL GHN: Sử dụng https://dev-online-gateway.ghn.vn nếu bạn ở môi trường Development. Đây là GHN_BASE_URL của bạn (và trong file appsettings.*.json là GHNSettings -> BaseUrl).
- Thay đổi vị trí của hàng: Vào phần "Quản lý cửa hàng" ở phần Sidebar, bạn cần thay đổi/thêm địa điểm của cửa hàng mặc định ngay trong đó.
- Đăng kí Webhook: Nếu như bạn muốn sử dụng Webhook để nhận tin khi có đơn hàng đã hoàn tất, bạn sẽ cần gửi mail đến địa chỉ api@ghn.vn với các thông tin làTên công ty, Mã khách hàng (ClientID), Môi trường yêu cầu, URL Webhook (chính là URL Endpoint chạy dự án này). Rồi chờ họ phản hồi.
Để sử dụng được các tính năng AI (ví dụ: tìm kiếm thông minh), bạn cần lấy Gemini API Key và tùy chọn lấy thêm LangSmith API Key để theo dõi (tracing).
- Truy cập Google AI Studio.
- Đăng nhập bằng tài khoản Google của bạn.
- Nhấn "Create API key" trong dự án hiện có hoặc tạo mới.
- Copy API key vừa tạo và dán vào
AISetup -> GeminiApiKeytrong fileappsettings.json.
- Truy cập LangSmith.
- Đăng nhập hoặc tạo tài khoản.
- Ở menu bên trái, chọn Settings (biểu tượng bánh răng) -> API Keys.
- Nhấn "+ API Key", đặt tên và copy key.
- Vào file
appsettings.json, đặtAISetup -> LangSmithTracingthànhtruevà dán key vàoLangSmithApiKey.
Giải pháp: Hãy chắc chắn bạn đã bật Docker Desktop trước khi chạy Test.
Giải pháp:
- Kiểm tra SQL Server đã được khởi động chưa. (Kiểm tra service "MSSQLSERVER" đã khởi động chưa)
- Kiểm tra connection string trong
appsettings.json - Thử connection string khác:
- Với SQL Express:
Server=.\\SQLEXPRESS;... - Với LocalDB:
Server=(localdb)\\MSSQLLocalDB;...
- Với SQL Express:
Giải pháp:
Thêm TrustServerCertificate=True vào connection string:
"StringConnection": "Server=localhost;Database=AnhEmMotorDB;Trusted_Connection=True;TrustServerCertificate=True;MultipleActiveResultSets=true"Giải pháp:
Đảm bảo Jwt.Key trong appsettings.json dài hơn 32 ký tự.
Giải pháp:
- Chạy
dotnet restore - Rebuild solution
- Kiểm tra connection string đúng chưa
Giải pháp:
Chạy 2 lệnh sau trong Command Prompt với quyền quản trị viên:
sc stop winnat
sc start winnat
Nếu vẫn không thành công, hãy khởi động lại máy tính.
Nếu không được, thay đổi port trong file WebAPI/Properties/launchSettings.json (Nhưng vì file này có thể push lên github nên nhớ trở về cổng cũ):
"applicationUrl": "https://localhost:7002;http://localhost:5001"