diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 73ebce0..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(php artisan test:*)", - "Bash(php artisan:*)", - "Bash(./vendor/bin/phpunit:*)", - "Bash(cat:*)", - "Bash(npm run build:*)", - "WebFetch(domain:dev-tools.online)", - "WebSearch", - "Bash(curl:*)", - "Bash(git add:*)", - "Bash(git cherry-pick:*)" - ], - "deny": [], - "ask": [] - } -} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 10c5af9..4bf060d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,35 +4,91 @@ on: release: types: [published] workflow_dispatch: + inputs: + force_full: + description: 'Force full deploy (rebuild and upload vendor + assets)' + type: boolean + default: false jobs: deploy: runs-on: ubuntu-latest name: Deploy via SFTP + env: + # Required at build time only: composer install runs package:discover, + # which boots the visitor-tracker package and trips its dashboard guard + # if no auth method is configured. The runner has no .env, so set this + # here to match prod posture (server's .env handles the actual setting). + VISITOR_TRACKER_ALLOW_UNPROTECTED: true + steps: - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Determine what changed since last release + id: changes + run: | + set -euo pipefail + + if [[ "${{ github.event.inputs.force_full }}" == "true" ]]; then + echo "Force full deploy requested via workflow_dispatch." + echo "composer_changed=true" >> "$GITHUB_OUTPUT" + echo "assets_changed=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Baseline = previous release tag (skip current HEAD if it IS a tag). + # Falls back to HEAD^ if there's no prior tag in history. + BASE=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || git rev-parse HEAD^) + echo "Diff baseline: $BASE" + + CHANGED=$(git diff --name-only "$BASE" HEAD) + echo "Changed files since $BASE:" + echo "$CHANGED" + + # Vendor needs rebuild + upload only when composer dependencies change. + if echo "$CHANGED" | grep -qE '^composer\.(json|lock)$'; then + echo "composer_changed=true" >> "$GITHUB_OUTPUT" + else + echo "composer_changed=false" >> "$GITHUB_OUTPUT" + fi + + # Compiled assets need rebuild + upload when their source or build + # config changes. public/build/ filenames are content-hashed by Vite, + # so leaving stale ones on the server is harmless. + if echo "$CHANGED" | grep -qE '^(package(-lock)?\.json|vite\.config\.js|resources/(css|js)/)'; then + echo "assets_changed=true" >> "$GITHUB_OUTPUT" + else + echo "assets_changed=false" >> "$GITHUB_OUTPUT" + fi - name: Setup PHP + if: steps.changes.outputs.composer_changed == 'true' uses: shivammathur/setup-php@v2 with: php-version: 8.3 extensions: mbstring, xml, ctype, json - name: Install production dependencies + if: steps.changes.outputs.composer_changed == 'true' run: composer install --no-dev --optimize-autoloader --no-interaction - name: Setup Node.js + if: steps.changes.outputs.assets_changed == 'true' uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install npm dependencies + if: steps.changes.outputs.assets_changed == 'true' run: npm ci - name: Build assets + if: steps.changes.outputs.assets_changed == 'true' run: npm run build - name: Prepare production files diff --git a/app/Http/Controllers/ToolController.php b/app/Http/Controllers/ToolController.php index 8e5e20c..d163904 100644 --- a/app/Http/Controllers/ToolController.php +++ b/app/Http/Controllers/ToolController.php @@ -153,12 +153,6 @@ public function index(): View 'route' => 'tools.sort-lines', 'icon' => 'sort', ], - [ - 'name' => 'Visitor Tracker', - 'description' => 'Server-side visitor analytics for Laravel applications', - 'route' => 'tools.visitor-tracker', - 'icon' => 'chart', - ], ]; return view('home', compact('tools')); @@ -283,31 +277,4 @@ public function sortLines(): View { return view('tools.sort-lines'); } - - public function visitorTracker(): View - { - $stats = app(\Ghdj\VisitorTracker\Services\StatisticsService::class); - $parser = new \Ghdj\VisitorTracker\Services\UserAgentParser(); - $botDetector = new \Ghdj\VisitorTracker\Services\BotDetector(); - - $userAgent = request()->userAgent(); - $parsedUA = $parser->parse($userAgent); - $isBot = $botDetector->isBot($userAgent); - $botName = $isBot ? $botDetector->getBotName($userAgent) : null; - $botCategory = $isBot ? $botDetector->getBotCategory($userAgent) : null; - - return view('tools.visitor-tracker', [ - 'summary' => $stats->summary(), - 'browsers' => $stats->browserStats(5), - 'platforms' => $stats->platformStats(5), - 'devices' => $stats->deviceStats(), - 'topPages' => $stats->mostVisitedPages(5), - 'userAgent' => $userAgent, - 'parsedUA' => $parsedUA, - 'isBot' => $isBot, - 'botName' => $botName, - 'botCategory' => $botCategory, - 'visitorIp' => request()->ip(), - ]); - } } diff --git a/resources/views/tools/visitor-tracker.blade.php b/resources/views/tools/visitor-tracker.blade.php deleted file mode 100644 index 1f15265..0000000 --- a/resources/views/tools/visitor-tracker.blade.php +++ /dev/null @@ -1,299 +0,0 @@ -@extends('layouts.app') - -@section('title', 'Laravel Visitor Tracker - Server-Side Analytics Demo | Dev Tools') -@section('meta_description', 'Laravel Visitor Tracker - A server-side analytics package for Laravel with bot detection, device parsing, and GDPR compliance. Unblockable by ad blockers.') -@section('meta_keywords', 'laravel visitor tracker, laravel analytics, server-side tracking, bot detection, user agent parser, gdpr analytics, laravel package') - -@push('schema') - -@endpush - -@section('content') -
Server-side analytics for Laravel - Unblockable by ad blockers
-Real data collected by this package running on this site:
- -{{ number_format($summary['total_visitors']) }}
-Total Visitors
-{{ number_format($summary['total_page_views']) }}
-Page Views
-{{ number_format($summary['online_visitors']) }}
-Online Now
-{{ number_format($summary['today_visitors']) }}
-Today
-This is what the package detects about your current visit:
- -User Agent:
-{{ $userAgent }}
-No data yet
- @endforelse -No data yet
- @endforelse -| Path | -Views | -Unique | -
|---|---|---|
| /{{ $page->path }} | -{{ number_format($page->visits) }} | -{{ number_format($page->unique_visitors) }} | -
Unblockable
-Server-side tracking can't be blocked by ad blockers
-Native Detection
-100+ bot patterns, browser/device parsing - no dependencies
-GDPR Compliant
-GDPR Safe Mode, IP anonymization, DNT support
-Zero Dependencies
-Only uses Laravel's built-in features
-Geolocation
-IP-based location via free APIs (optional)
-Built-in Dashboard
-Tailwind CSS dashboard with token auth
-1. Install via Composer:
-composer require ghdj/laravel-visitor-tracker
- 2. Publish config and run migrations:
-php artisan vendor:publish --tag="visitor-tracker-config"
-php artisan migrate
- 3. Add middleware to your routes:
-// In bootstrap/app.php (Laravel 11+)
-->withMiddleware(function (Middleware $middleware) {
- $middleware->web(append: [
- \Ghdj\VisitorTracker\Middleware\TrackVisitor::class,
- ]);
-})
- 4. Use it:
-use Ghdj\VisitorTracker\Facades\VisitorTracker;
-
-// Get statistics
-$stats = VisitorTracker::stats()->summary();
-$online = VisitorTracker::stats()->onlineVisitors();
-$topPages = VisitorTracker::stats()->mostVisitedPages(10);
- Laravel Visitor Tracker v1.0.0 - MIT License
-- Documentation - · - Packagist -
-