Files
MyClub/DOCS/UMAMI_WEBSITE_CREATION_FIX.md
Tomas Dvorak 77213f4e83 dev day #65
2025-10-19 17:16:57 +02:00

10 KiB

Umami Website Creation Fix

Problem

The Umami tracking website creation was not working properly because:

  1. The auto-creation wasn't being triggered during initial setup
  2. No frontend UI existed to manually trigger website creation if needed

Solution

Automatic Creation During Setup

The initial setup process now automatically creates the Umami website:

  • When you complete the setup wizard, it fetches /umami/config
  • Backend detects that UMAMI credentials are in .env but no UMAMI_WEBSITE_ID exists
  • Backend automatically creates the website using the domain from your site
  • Analytics tracking starts working immediately

Manual Creation (Backup Option)

Added a new "Umami Analytics" tab to the Settings Admin Page that allows:

  • Viewing current Umami configuration status
  • Manually creating a new Umami website with custom name and domain
  • Refreshing the Umami configuration

Changes Made

Frontend Changes

File: frontend/src/pages/SetupPage.tsx Added automatic Umami initialization during setup:

// Step 3: Initialize Umami Analytics (auto-create website)
setSetupProgress('Konfiguruji analytiku...');
try {
  // Trigger Umami config fetch - backend will auto-create website if credentials are present
  const axios = (await import('axios')).default;
  const apiUrl = (API_URL || '').replace(/\/$/, '');
  await axios.get(`${apiUrl}/umami/config`);
  console.log('Umami analytics initialized');
} catch (err) {
  console.warn('Umami initialization failed (non-critical):', err);
}

File: frontend/src/pages/admin/SettingsAdminPage.tsx

  1. Added new imports:

    • import api from '../../services/api';
  2. Added new state variables:

    const [umamiWebsiteId, setUmamiWebsiteId] = useState<string>('');
    const [umamiDomain, setUmamiDomain] = useState<string>('');
    const [umamiName, setUmamiName] = useState<string>('');
    const [umamiInitializing, setUmamiInitializing] = useState<boolean>(false);
    const [umamiConfig, setUmamiConfig] = useState<any>(null);
    
  3. Added fetchUmamiConfig() function to load current Umami status

  4. Added "Umami Analytics" tab to the settings page with:

    • Status indicator (green for active, yellow for not configured)
    • Form fields for website name and domain
    • "Create Website" button that calls /admin/umami/initialize
    • "Refresh Status" button to reload configuration

Backend API

Authentication with Token Verification

File: internal/services/umami_service.go

The backend implements smart token management:

  1. Initial Authentication (POST /api/auth/login)

    • Sends username and password in JSON format (from .env)
    • Receives JWT token with 24-hour expiration
    • Stores token with expiration timestamp
  2. Token Verification (twice daily - every 12 hours)

    • Uses POST /api/auth/verify endpoint
    • Checks if existing token is still valid
    • Only re-authenticates if verification fails
    • Reduces unnecessary login requests
  3. Automatic Re-authentication

    • If token expires or verification fails
    • Automatically gets a new token
    • Seamless for the application

Token Lifecycle:

Initial: Login → Get Token (valid 24h)
After 12h: Verify Token → Still valid? Continue using it
After 24h: Token expired → Re-authenticate → Get new token

All API calls use: Authorization: Bearer <token> header

Website Creation Endpoint

Endpoint: POST /admin/umami/initialize File: internal/controllers/umami_controller.go

Request body:

{
  "name": "Your Club Name",
  "domain": "yourclub.example.com"
}

Response (success):

{
  "message": "Umami initialized successfully",
  "website_id": "abc123-def456-...",
  "script_url": "https://umami.tdvorak.dev/script.js"
}

Testing Instructions

1. Verify Environment Variables

Your .env file already has the correct credentials (they don't change):

UMAMI_URL=https://umami.tdvorak.dev
UMAMI_USERNAME=admin
UMAMI_PASSWORD=eevRQ6h3G@!c#y4A1T
UMAMI_WEBSITE_ID=  # Leave empty - will be auto-created during setup

Important: These credentials are permanent and don't need to be modified.

2. Run Initial Setup

  1. Navigate to /setup route
  2. Complete the setup wizard (club info, admin account, etc.)
  3. During setup, you'll see: "Konfiguruji analytiku..." (Configuring analytics)
  4. Backend automatically creates Umami website using your domain
  5. Setup completes and analytics are ready!

3. Verify Umami is Working

After setup, check the analytics:

  1. Login to admin panel
  2. Navigate to SettingsUmami Analytics tab
  3. You should see green status: "✓ Umami je aktivní"
  4. Website ID should be displayed

4. Manual Creation (If Needed)

If auto-creation didn't work during setup, you can manually create:

  1. Navigate to SettingsUmami Analytics tab
  2. Fill in the form:
    • Name: Your club name
    • Domain: Your website domain
  3. Click "Vytvořit webovou stránku" (Create Website)
  4. Success message will show the Website ID

4. Verify via API (PowerShell)

You can also verify directly with PowerShell:

# Login to get token
$body = @{
    username = "admin"
    password = "eevRQ6h3G@!c#y4A1T"
} | ConvertTo-Json

$response = Invoke-RestMethod -Uri "https://umami.tdvorak.dev/api/auth/login" `
    -Method Post `
    -ContentType "application/json" `
    -Body $body

$token = $response.token
Write-Output "Token: $token"

# List websites to verify creation
$headers = @{
    Authorization = "Bearer $token"
}

$websites = Invoke-RestMethod -Uri "https://umami.tdvorak.dev/api/websites" `
    -Headers $headers `
    -Method Get

$websites.data

5. Website ID Persistence

The Website ID is stored in-memory by the backend after auto-creation. To make it permanent across server restarts:

Option 1: Let it auto-create on each restart (Recommended)

  • Leave UMAMI_WEBSITE_ID= empty in .env
  • Backend checks if website exists and reuses it (or creates new one if missing)
  • Works seamlessly

Option 2: Store Website ID in .env

  • Copy the Website ID from Settings → Umami Analytics tab
  • Add to .env: UMAMI_WEBSITE_ID=abc123-def456-...
  • Restart backend server
  • Backend will use this ID directly without checking/creating

How It Works

Frontend Flow

  1. User opens Settings → Umami Analytics tab
  2. fetchUmamiConfig() is called on page load
  3. Backend checks if UMAMI_WEBSITE_ID is set
  4. If not set and credentials are available, backend may auto-create on first request
  5. User can manually create via the UI by clicking "Create Website"
  6. Frontend calls POST /admin/umami/initialize with name and domain
  7. Backend authenticates with Umami and creates the website
  8. Backend returns the Website ID
  9. Frontend displays success and refreshes the configuration

Backend Flow

  1. Receives request at /admin/umami/initialize
  2. Validates request payload (name and domain required)
  3. Calls umamiService.authenticate():
    • POST to Umami https://umami.tdvorak.dev/api/auth/login
    • Payload: {"username": "admin", "password": "..."}
    • Receives JWT token
  4. Calls umamiService.EnsureWebsite():
    • First checks if website exists: GET /api/websites?query={domain}
    • If exists, returns existing ID
    • If not, creates new website: POST /api/websites
    • Payload: {"name": "...", "domain": "..."}
    • Authorization header: Bearer {token}
  5. Updates in-memory config with Website ID
  6. Returns success response to frontend

Troubleshooting

Error: "authentication failed"

  • Check UMAMI_USERNAME and UMAMI_PASSWORD in .env
  • Verify credentials work by testing with PowerShell script above

Error: "create website failed"

  • Check if website already exists (list via PowerShell)
  • Verify token has correct permissions
  • Check Umami server logs

Website ID not persisting

  • The Website ID is stored in memory only
  • Update .env with UMAMI_WEBSITE_ID=... for persistence
  • Restart backend server after updating .env

Additional Notes

  • The backend automatically tries to create a website on first request to /umami/config if credentials are set
  • In production, it only auto-creates for non-localhost domains
  • In development, it allows localhost
  • The manual UI provides explicit control over website creation
  • You can create multiple websites for different domains if needed

Umami v2 Compatibility Update (Latest Fix)

Problem with Umami v2

In Umami v2, when users are part of teams, creating a website may require specifying a teamId. Without this parameter, the website creation request could fail.

Solution Implemented

Updated CreateWebsite() method in umami_service.go to:

  1. Fetch current user information via POST /api/auth/verify
  2. Retrieve user's teams via GET /api/users/:userId/teams
  3. Automatically use the first available team when creating a website
  4. Gracefully degrade if teams cannot be fetched (continues without teamId)

New Methods Added

// GetCurrentUser - Retrieves authenticated user info from Umami
func (u *UmamiService) GetCurrentUser() (map[string]interface{}, error)

// GetUserTeams - Retrieves user's teams from Umami
func (u *UmamiService) GetUserTeams(userID string) ([]UmamiTeam, error)

Updated CreateWebsite Flow

1. Authenticate with Umami
2. Get current user info (to obtain user ID)
3. Fetch user's teams (if user has teams)
4. Prepare website creation request with:
   - name: Website name
   - domain: Website domain
   - teamId: First available team ID (optional)
5. Send POST /api/websites with Authorization Bearer token
6. Return website ID on success

Enhanced Error Logging

All error messages now include detailed response bodies from Umami API for easier debugging:

  • Authentication failures show full error response
  • Website creation errors display Umami's error message
  • Team fetch failures log warnings but don't block website creation

Testing the Fix

To verify the fix works:

  1. Check backend logs during website creation - you should see:

    Creating Umami website: name='...', domain='...'
    Using team ID: xxx-xxx-xxx (team name: ...)
    Sending website creation request to Umami API: https://umami.tdvorak.dev/api/websites
    Successfully created Umami website: ... (ID: xxx, Domain: ...)
    
  2. If teams aren't available, you'll see:

    Failed to fetch user teams (continuing without team): ...
    Successfully created Umami website: ... (ID: xxx, Domain: ...)
    
  3. Monitor for creation errors - detailed error messages will help diagnose issues

This update ensures compatibility with both Umami v1 (no teams) and Umami v2 (with teams).