Skip to content

Commit f496f9f

Browse files
alexp8Sneer-ra2TF338claudedependabot[bot]
authored
canceled matches update (#493)
* add more logs and update secondsInQueue (#456) Co-authored-by: Sneer-ra2 <116219243+Sneer-ra2@users.noreply.github.com> * set AutoSaveInterval to 0 * update secondsInQueue to use updated_at * fix secondsInQueue bug * update player name fix * account-settings updates * Fix: Cooldown should start on connect (#452) (#461) * Fix: Cooldown should start on connect (#452) * Fix: Cooldown should start on connect * Fix: Cooldown should start on connect * housekeeping --------- Co-authored-by: TF338 <211804947+TF338@users.noreply.github.com> * fix cooldown * Do not prevent YvY any longer. (#468) * create migration (#470) * refactor(player-detail): optimize queries and refactor controller following SOLID principles (#472) Achieved 95.5% query reduction (1,563 → 70 queries) and improved code quality by refactoring the getLadderPlayer method from a 172-line "God Method" into a clean, maintainable architecture. Performance Improvements: - Eliminated N+1 query issues in service methods using SQL aggregation - Added eager loading to prevent duplicate queries in views - Optimized game data transformation with pre-computed URLs - Reduced service method queries from ~708 to ~5 - Reduced view queries from ~216 to 0 Query Optimizations: - getPlayerMatchups: 200+ queries → 1 with eager loading - getFactionResults: 27 queries → 1 with SQL aggregation (SUM/CASE) - getMapWinLossByPlayer: 121+ queries → 1 with aggregation + join - getPlayerGamesPlayedByMonth: 60 queries → 1 with DATE grouping - getTeamMatchups: 300+ queries → 1 with eager loading Code Quality Improvements (Fixed 10 Issues): - Applied Single Responsibility Principle - extracted Action class - Eliminated variable shadowing ($user vs $authenticatedUser vs $playerUser) - Removed redundant database queries (duplicate User::where calls) - Replaced json_encode/decode anti-pattern with clean object cast - Introduced constants for magic numbers (GAMES_PER_PAGE, etc.) - Added full type hints to all method signatures - Extracted data transformation logic to GameTransformer service - Fixed inconsistent null checks (strict comparison) - Removed duplicate view data (playerGamesLast24Hours) - Fixed undefined variable bug in SiteHelper::getMapPreviewUrl Architecture Changes: - Created GetPlayerDetailAction (Action pattern) - 230 lines - Created GameTransformer service - 95 lines - Created PlayerDetailData DTO (example) - 45 lines - Reduced controller method from 172 to 22 lines (87% reduction) New Files: - app/Actions/Player/GetPlayerDetailAction.php - app/DataTransferObjects/PlayerDetailData.php - app/Http/Services/GameTransformer.php Modified Files: - app/Http/Controllers/LadderController.php (refactored getLadderPlayer) - app/Http/Services/StatsService.php (SQL aggregation for stats) - app/Http/Services/ChartService.php (optimized date grouping) - app/Helpers/SiteHelper.php (fixed undefined variable) - resources/views/ladders/player/_games-table.blade.php (use eager-loaded data) - resources/views/ladders/components/_games-player-row.blade.php (pre-computed URLs) Developer Experience: - Added .vscode/ to .gitignore for IDE configuration - Added .specs/ to .gitignore for local technical documentation Benefits: ✅ 95.5% query reduction (1,563 → 70 queries) ✅ 87% controller code reduction (172 → 22 lines) ✅ SOLID principles applied ✅ Improved testability ✅ Enhanced maintainability ✅ No breaking changes (100% backward compatible) ✅ No performance regression 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> * Performance Optimization: Game & Player Detail Pages (#473) * refactor(player-detail): optimize queries and refactor controller following SOLID principles Achieved 95.5% query reduction (1,563 → 70 queries) and improved code quality by refactoring the getLadderPlayer method from a 172-line "God Method" into a clean, maintainable architecture. Performance Improvements: - Eliminated N+1 query issues in service methods using SQL aggregation - Added eager loading to prevent duplicate queries in views - Optimized game data transformation with pre-computed URLs - Reduced service method queries from ~708 to ~5 - Reduced view queries from ~216 to 0 Query Optimizations: - getPlayerMatchups: 200+ queries → 1 with eager loading - getFactionResults: 27 queries → 1 with SQL aggregation (SUM/CASE) - getMapWinLossByPlayer: 121+ queries → 1 with aggregation + join - getPlayerGamesPlayedByMonth: 60 queries → 1 with DATE grouping - getTeamMatchups: 300+ queries → 1 with eager loading Code Quality Improvements (Fixed 10 Issues): - Applied Single Responsibility Principle - extracted Action class - Eliminated variable shadowing ($user vs $authenticatedUser vs $playerUser) - Removed redundant database queries (duplicate User::where calls) - Replaced json_encode/decode anti-pattern with clean object cast - Introduced constants for magic numbers (GAMES_PER_PAGE, etc.) - Added full type hints to all method signatures - Extracted data transformation logic to GameTransformer service - Fixed inconsistent null checks (strict comparison) - Removed duplicate view data (playerGamesLast24Hours) - Fixed undefined variable bug in SiteHelper::getMapPreviewUrl Architecture Changes: - Created GetPlayerDetailAction (Action pattern) - 230 lines - Created GameTransformer service - 95 lines - Created PlayerDetailData DTO (example) - 45 lines - Reduced controller method from 172 to 22 lines (87% reduction) New Files: - app/Actions/Player/GetPlayerDetailAction.php - app/DataTransferObjects/PlayerDetailData.php - app/Http/Services/GameTransformer.php Modified Files: - app/Http/Controllers/LadderController.php (refactored getLadderPlayer) - app/Http/Services/StatsService.php (SQL aggregation for stats) - app/Http/Services/ChartService.php (optimized date grouping) - app/Helpers/SiteHelper.php (fixed undefined variable) - resources/views/ladders/player/_games-table.blade.php (use eager-loaded data) - resources/views/ladders/components/_games-player-row.blade.php (pre-computed URLs) Developer Experience: - Added .vscode/ to .gitignore for IDE configuration - Added .specs/ to .gitignore for local technical documentation Benefits: ✅ 95.5% query reduction (1,563 → 70 queries) ✅ 87% controller code reduction (172 → 22 lines) ✅ SOLID principles applied ✅ Improved testability ✅ Enhanced maintainability ✅ No breaking changes (100% backward compatible) ✅ No performance regression 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor * feat(game-detail): add comprehensive eager loading to eliminate N+1 queries Enhanced GameReportService with complete relationship eager loading: **Added eager loads:** - player.user.userSettings (for user preferences) - player.clanPlayer.clan (for clan games) - player.playerCaches (constrained by history ID) - map.mapHeaders (for map preview data) - stats (Stats2 relationship) - clan (for clan identification) - gameReport (for clan logic in views) - qmMatch.map (for map preview) **Query optimization:** - Consolidated player eager loads into single closure - Added constrained eager loading for playerCaches - Separate eager loads for mod vs non-mod users - All relationships used in views are now eager loaded **Known limitation:** Views currently call relationship methods (->player()->first()) instead of properties (->player), which bypasses eager loading. This is documented in game-detail-view-optimization-followup.md for future optimization. Current state: 260 → 248 queries (~5% reduction) Potential with view fixes: 260 → 5-10 queries (95-98% reduction) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(game-detail): remove non-existent playerCaches relationship from eager loading Removed attempted eager loading of 'playerCaches' relationship which does not exist on the Player model. The Player model has a playerCache($historyId) method that makes queries, but no playerCaches() relationship is defined. Attempting to eager load a non-existent relationship causes a runtime error. **Issue:** Call to undefined relationship [playerCaches] on model [App\Models\Player] **Fix:** Removed playerCaches from eager loading in GameReportService. The views still call the playerCache() method which makes queries - this is documented in game-detail-view-optimization-followup.md for future fix. **To properly optimize playerCache queries:** 1. Add playerCaches() relationship to Player model 2. Update views to use relationship collection 3. OR add memoization to the existing method 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * perf(game-detail): pre-compute player data and fix relationship access in views Moved query-heavy computations from views to controller to eliminate N+1 queries. **Action Layer Changes:** - Added attachPlayerCacheData() method to pre-compute player cache info - Attached playerCache, playerRank, playerPoints, playerTier to each PlayerGameReport - Added 'map' and 'gameAbbreviation' to view data (already eager-loaded) **View Layer Changes:** - Fixed relationship access: ->player()->first() → ->player (use property) - Fixed relationship access: ->clan()->first() → ->clan (use property) - Fixed relationship access: ->ladder()->first() → ->ladder (use property) - Removed direct Map query: Map::where('hash', '=', $game->hash) (use passed $map) - Use pre-computed $pgr->playerRank instead of $playerCache->rank() - Use pre-computed $pgr->playerPoints instead of $playerCache->points - Use pre-computed $pgr->playerTier instead of getCachedPlayerTierByLadderHistory() **Files Updated:** - app/Actions/Game/GetGameDetailAction.php - resources/views/ladders/game-detail.blade.php - resources/views/ladders/clan-game-detail.blade.php - resources/views/ladders/game/_player-card.blade.php - resources/views/ladders/game/_map-preview-with-players.blade.php **Query Reduction:** Before: 249 queries Expected after: ~10-20 queries (90-95% reduction) All queries that were in views are now executed once in the action layer and the results are passed to the view as pre-computed data. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * perf(game-detail): eliminate N+1 queries for countableGameObject and admin tools Fixed massive N+1 query issue in game cameo stats and admin game tools. **Critical Fix - countableGameObject N+1:** The view was iterating over gameObjectCounts (30-50 per player) and for EACH one, lazy-loading the countableGameObject relationship. For a 4-player game, this caused 120-200 queries! **Changes Made:** 1. GameReportService - Added eager loading: - stats.gameObjectCounts.countableGameObject (CRITICAL) - player.gameClips (for game clip display) 2. GetGameDetailAction - Pre-compute game clips: - Added playerGameClip to attachPlayerCacheData() - Uses eager-loaded gameClips collection instead of query 3. _game-cameo-stats.blade.php: - Fixed: $pgr->player()->first() → $pgr->player - Fixed: $player->gameClip($pgr->game_id) → $pgr->playerGameClip - Removed: $player->playerCache() query (use pre-computed data) - Now uses eager-loaded countableGameObject relationship 4. _admin-game-tools.blade.php (mod-only): - Fixed: $thisGameReport->playerGameReports()->get() → $thisGameReport->playerGameReports - Fixed: $pgr->player()->first() → $pgr->player - Uses already eager-loaded data instead of new queries **Query Impact:** Before: 222 queries Expected: ~10-20 queries (90-95% reduction) The countableGameObject fix alone eliminates 100-200 queries depending on the number of players and game objects in the match. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(game-detail): add missing gameClips relationship to Player model Added gameClips() hasMany relationship to Player model to support eager loading. **Issue:** Call to undefined relationship [gameClips] on model [App\Models\Player] **Root Cause:** The Player model had a gameClip($gameId) method but no gameClips() relationship. GameReportService was attempting to eager load 'player.gameClips' which failed. **Fix:** Added relationship to Player model: ```php public function gameClips() { return $this->hasMany(GameClip::class); } ``` The GameClip model already had belongsTo(Player::class), so this completes the bidirectional relationship. **Impact:** - Enables eager loading of game clips - Eliminates N+1 queries when accessing player game clips - Existing gameClip($gameId) method still works for backward compatibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * perf(game-detail): eliminate queries in map preview and player card views Fixed redundant Stats2 queries and pre-computed faction/point report data. **Issues Fixed:** 1. **Redundant Stats2 Query (2 occurrences):** - _map-preview-with-players.blade.php line 111 - _player-card.blade.php line 10 Problem: ```php ❌ $playerStats2 = Stats2::where("id", $pgr->stats->id)->first(); ``` This was querying for a Stats2 model that was already loaded as $pgr->stats! Solution: Pre-compute faction in action: $pgr->playerFaction = $pgr->stats->faction(...) Views now use: $pgr->playerFaction (no query) 2. **Point Report Method Calls:** - _map-preview-with-players.blade.php line 41 Problem: ```php ❌ $pointReport = $pgr->gameReport->getPointReportByClan($pgr->clan_id); ``` This method call could trigger additional queries. Solution: Pre-compute in action: $pgr->pointReport = $gameReport->getPointReportByClan(...) Views now use: $pgr->pointReport ?? $pgr 3. **Map Waypoints Eager Loading:** Added 'map.mapHeaders.waypoints' to eager loading for player spawn positions. **Changes Made:** - GameReportService: Added waypoints eager loading - GetGameDetailAction: - Added attachPointReports() method - Pre-compute playerFaction in attachPlayerCacheData() - Views: Use pre-computed data instead of making queries **Query Impact:** Before: ~2-4 queries per player for faction + point reports After: 0 queries (all pre-computed) For 4-player game: Eliminates 8-16 additional queries 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * remove stale file --------- Co-authored-by: Claude <noreply@anthropic.com> * bug fix * update gitignore * add script to download backup * check if player is streaming (#477) * fix: exclude observers from Quick Match ready-check player count (#476) Critical bug fix where observers were incorrectly counted toward required player count in Quick Match ready validation, causing two failure modes: 1. 1v1 matches: AFK observers could prevent matches from starting 2. 2v2+ matches: Incomplete teams (e.g., 3 players + 1 observer) would incorrectly satisfy the 4-player requirement, starting unfair matches Changes: - Split player count validation into two queries in MatchUpController - Query 1: Validate only actual players (exclude is_observer) for ready-check - Query 2: Include all players (with observers) for spawn configuration - Add comprehensive logging for actual vs total player counts - Improve error messages with structured context The match creation logic already correctly excludes observers; this fix brings the ready-check logic into alignment with that behavior. Fixes unfair team compositions while preserving observer functionality. Ready observers are still included in spawn.ini when they poll in time. * Track Canceled & Failed Quick Match Games (#479) * track aborted games * refactor: improve production readiness and code quality - Replace doctrine/dbal-dependent migration with raw SQL - Add database indexes for query performance (ladder_id, created_at, qm_match_id, reason) - Fix Blade template null handling for PHP 8+ compatibility - Extract player colors to config for reusability - Add username validation and proper logging - Standardize Laravel output conventions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * Bump vite from 6.3.5 to 6.4.2 in /cncnet-api (#484) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.5 to 6.4.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.4.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.4.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.4.2 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump follow-redirects from 1.15.9 to 1.16.0 in /cncnet-api (#485) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.9 to 1.16.0. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](follow-redirects/follow-redirects@v1.15.9...v1.16.0) --- updated-dependencies: - dependency-name: follow-redirects dependency-version: 1.16.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump postcss from 8.5.6 to 8.5.13 in /cncnet-api (#483) Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.13. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.6...8.5.13) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump axios from 1.10.0 to 1.15.0 in /cncnet-api (#482) Bumps [axios](https://github.com/axios/axios) from 1.10.0 to 1.15.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.10.0...v1.15.0) --- updated-dependencies: - dependency-name: axios dependency-version: 1.15.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump symfony/process from 7.3.0 to 7.4.8 in /cncnet-api (#465) Bumps [symfony/process](https://github.com/symfony/process) from 7.3.0 to 7.4.8. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/8.1/CHANGELOG.md) - [Commits](symfony/process@v7.3.0...v7.4.8) --- updated-dependencies: - dependency-name: symfony/process dependency-version: 7.4.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump phpunit/phpunit from 11.5.34 to 11.5.50 in /cncnet-api (#464) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 11.5.34 to 11.5.50. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/11.5.50/ChangeLog-11.5.md) - [Commits](sebastianbergmann/phpunit@11.5.34...11.5.50) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-version: 11.5.50 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump symfony/http-foundation from 7.3.2 to 7.4.8 in /cncnet-api (#443) Bumps [symfony/http-foundation](https://github.com/symfony/http-foundation) from 7.3.2 to 7.4.8. - [Release notes](https://github.com/symfony/http-foundation/releases) - [Changelog](https://github.com/symfony/http-foundation/blob/8.1/CHANGELOG.md) - [Commits](symfony/http-foundation@v7.3.2...v7.4.8) --- updated-dependencies: - dependency-name: symfony/http-foundation dependency-version: 7.3.7 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * laravel fix * canceled matches housekeeping * move import script * canceled matches fix --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Sneer-ra2 <116219243+Sneer-ra2@users.noreply.github.com> Co-authored-by: TF338 <211804947+TF338@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent d1e2dc7 commit f496f9f

5 files changed

Lines changed: 30 additions & 12 deletions

File tree

cncnet-api/app/Console/Commands/DetectFailedGameLaunches.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function handle()
102102
$canceledMatch->map_name = $qmMatch->map->description ?? $qmMatch->map->map->name ?? 'Unknown';
103103
$canceledMatch->canceled_by_usernames = null; // No explicit cancellation
104104
$canceledMatch->affected_player_usernames = implode(',', $allPlayerUsernames);
105-
$canceledMatch->player_data = json_encode($playerData);
105+
$canceledMatch->player_data = $playerData; // Model has array cast, auto json_encodes
106106
$canceledMatch->reason = 'failed_launch';
107107
$canceledMatch->save();
108108

cncnet-api/app/Http/Controllers/Api/V2/Qm/MatchUpController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ private function onUpdate(Player $player, $request)
219219
$canceledMatch->map_name = $qmMatch->map->map->name ?? $qmMatch->map->description ?? 'Unknown';
220220
$canceledMatch->canceled_by_usernames = implode(',', $canceledByUsernames);
221221
$canceledMatch->affected_player_usernames = implode(',', $affectedPlayerUsernames);
222-
$canceledMatch->player_data = json_encode($playerData);
222+
$canceledMatch->player_data = $playerData; // Model has array cast, auto json_encodes
223223
$canceledMatch->reason = 'player_canceled';
224224
$canceledMatch->save();
225225
}

cncnet-api/resources/views/admin/canceled-matches.blade.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
@foreach ($canceled_matches as $canceled_match)
7070
@php
7171
$playerData = $canceled_match->player_data ?? [];
72-
$canceledByList = $canceled_match->canceled_by ? explode(',', $canceled_match->canceled_by) : [];
72+
$canceledByList = $canceled_match->canceled_by_usernames ? explode(',', $canceled_match->canceled_by_usernames) : [];
7373
@endphp
7474
<tr title="QM Match ID: {{ $canceled_match->qm_match_id }}"
7575
class="{{ $canceled_match->reason === 'failed_launch' ? 'table-warning' : '' }}">
@@ -99,11 +99,11 @@ class="{{ $canceled_match->reason === 'failed_launch' ? 'table-warning' : '' }}"
9999
@endforeach
100100
@else
101101
{{-- Fallback to legacy comma-separated format --}}
102-
@if($canceled_match->canceled_by)
103-
<strong>{{ $canceled_match->canceled_by }}</strong>
104-
@if($canceled_match->affected_players), @endif
102+
@if($canceled_match->canceled_by_usernames)
103+
<strong>{{ $canceled_match->canceled_by_usernames }}</strong>
104+
@if($canceled_match->affected_player_usernames), @endif
105105
@endif
106-
{{ $canceled_match->affected_players ?? '-' }}
106+
{{ $canceled_match->affected_player_usernames ?? '-' }}
107107
@endif
108108
</td>
109109
<td>{{ $canceled_match->map ?? 'Unknown' }}</td>
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,23 @@ All server connection variables are **required** if you want to download backups
7373
### 3. Make Script Executable
7474

7575
```bash
76-
chmod +x import-db-backup.sh
76+
chmod +x scripts/import-db-backup.sh
7777
```
7878

7979
## Usage
8080

81+
**Important**: Always run from the project root directory:
82+
83+
```bash
84+
cd /path/to/cncnet-ladder-api-main
85+
```
86+
8187
### Full Import (Default)
8288

8389
Run the complete workflow from download to import:
8490

8591
```bash
86-
./import-db-backup.sh
92+
./scripts/import-db-backup.sh
8793
```
8894

8995
Answer `y` (or press Enter for defaults) to proceed through each step.
@@ -93,7 +99,7 @@ Answer `y` (or press Enter for defaults) to proceed through each step.
9399
To download and extract the backup without importing:
94100

95101
```bash
96-
./import-db-backup.sh
102+
./scripts/import-db-backup.sh
97103
```
98104

99105
1. Confirm download and extraction steps (`y`)
@@ -104,7 +110,7 @@ To download and extract the backup without importing:
104110
If you've already downloaded a backup and just want to import:
105111

106112
```bash
107-
./import-db-backup.sh
113+
./scripts/import-db-backup.sh
108114
```
109115

110116
1. Decline re-download (`n`) - uses existing file
@@ -185,7 +191,9 @@ Total time: ~15-45 minutes for full workflow
185191

186192
```
187193
cncnet-ladder-api-main/
188-
├── import-db-backup.sh # This script
194+
├── scripts/
195+
│ ├── import-db-backup.sh # This script
196+
│ └── DATABASE_IMPORT_README.md # This file
189197
├── .env # Configuration (add SERVER_* variables here)
190198
├── cnc_comm_private_key.pem # SSH key (gitignored)
191199
└── backups/ # Created by script
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@
22

33
set -e # Exit on error
44

5+
# IMPORTANT: This script must be run from the project root directory
6+
# Example: cd /path/to/cncnet-ladder-api-main && ./scripts/import-db-backup.sh
7+
58
# Colors for output
69
RED='\033[0;31m'
710
GREEN='\033[0;32m'
811
YELLOW='\033[1;33m'
912
BLUE='\033[0;34m'
1013
NC='\033[0m' # No Color
1114

15+
# Verify script is run from project root
16+
if [ ! -f "docker-compose.dev.yml" ]; then
17+
echo -e "${RED}Error: This script must be run from the project root directory${NC}"
18+
echo "Example: cd /path/to/cncnet-ladder-api-main && ./scripts/import-db-backup.sh"
19+
exit 1
20+
fi
21+
1222
# Helper function to prompt for confirmation
1323
confirm() {
1424
local prompt="$1"

0 commit comments

Comments
 (0)