Back to Blog
PAPA Development Journal [Day 4/7] - Tauri Desktop Edition: Cross-Platform Native Experience
📋 Case Study

PAPA Development Journal [Day 4/7] - Tauri Desktop Edition: Cross-Platform Native Experience

B
Blake
Sep 25, 2025 By Blake 33 min read
As Blake Lab's cultural-technology integration experiment, Day 4 dives into Tauri desktop development, showing how to create native desktop experiences for macOS and Windows using web technologies, with large-screen friendly interfaces designed specifically for elders.

🎯 Today's Challenge: Why Do We Need a Desktop Version?

Yesterday we completed the web version, but discussions with tribal offices revealed new requirements: The tribal activity centers need desktop versions for elders to use large screens and keyboards easily.

This requirement exposed real pain points:

  • Elders prefer desktop computers' large screens and keyboards

  • Cross-platform support needed for macOS and Windows

  • Need to export Excel reports for government subsidy applications

  • Native desktop application stability and performance

🔗 Smart API Configuration: One Codebase, Three Deployments

Environment-Aware API Architecture

After multiple deployment battles, I designed a smart environment detection system:

// config/api.ts - The essence of multi-environment API configuration
const getApiBaseUrl = () => {
  // Tauri desktop version: Connect to local Django backend
  if (window.__TAURI__) {
    return 'http://127.0.0.1:8000'
  }
  
  // Development mode: Handle CORS through Vite proxy
  if (import.meta.env.DEV) {
    return '' // Use relative paths, forwarded by proxy
  }
  
  // Production mode: Direct connect to Railway API
  return 'https://pangcah-accounting-system-production.up.railway.app'
}

// Unified API client configuration
export const apiClient = axios.create({
  baseURL: getApiBaseUrl(),
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
})

Design Highlights:

  • Zero-config switching: Same frontend codebase supports three deployment modes

  • Development experience optimization: Automatically handles CORS in local development

  • Production stability: Direct Railway connection ensures optimal performance

Seamless JWT Token Refresh Mechanism

// Response interceptor: Users never see login expiration
apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config
    
    // Smart 401 error handling
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true
      
      try {
        const refreshToken = localStorage.getItem('refresh_token')
        
        if (refreshToken) {
          // Attempt token refresh
          const response = await axios.post('/api/v1/auth/refresh/', {
            refresh: refreshToken,
          })
          
          const newToken = response.data.access
          localStorage.setItem('access_token', newToken)
          
          // Retry original request, completely seamless to user
          originalRequest.headers.Authorization = `Bearer ${newToken}`
          return apiClient(originalRequest)
        }
      } catch (refreshError) {
        // Actually expired, gracefully redirect to login
        localStorage.clear()
        window.location.href = '/login'
        return Promise.reject(new Error('Please log in again'))
      }
    }
    
    return Promise.reject(error)
  }
)

User Experience: During 8-hour family gatherings, users are never interrupted by token expiration.

🖥️ Tauri Desktop Version: Cross-Platform Native Experience

Why Choose Tauri?

After technical evaluation, Tauri best meets our macOS/Windows cross-platform needs:

// tauri.conf.json - Application configuration
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "build": {
    "beforeDevCommand": "npm run dev",
    "beforeBuildCommand": "npm run build",
    "devPath": "http://localhost:5173",
    "distDir": "../dist"
  },
  "package": {
    "productName": "PAPA Pangcah Family Accounting",
    "version": "1.0.0"
  },
  "tauri": {
    "allowlist": {
      "all": false,
      "shell": {
        "all": false,
        "open": true
      },
      "dialog": {
        "all": false,
        "open": true,
        "save": true
      },
      "fs": {
        "all": false,
        "readFile": true,
        "writeFile": true,
        "createDir": true
      }
    }
  }
}

Technical Advantages:

  • Small file size: 8MB vs Electron's 100MB+

  • Native performance: Rust core provides near-native speed

  • Security: Principle of least privilege, only expose necessary functions

  • Development efficiency: Reuse existing React code

💻 Core Feature Implementation of Tauri Desktop Version

Large-Screen Friendly Interface Design

The desktop version's greatest value is the large-screen friendly interface designed for elders:

// hooks/useDesktop.ts - Desktop feature detection
export const useDesktop = () => {
  const [isDesktop, setIsDesktop] = useState(false)
  const [desktopAPI, setDesktopAPI] = useState<any>(null)
  
  useEffect(() => {
    // Detect Tauri environment
    if (window.__TAURI__) {
      setIsDesktop(true)
      
      // Dynamically load Tauri API
      import('@tauri-apps/api').then((tauri) => {
        setDesktopAPI(tauri)
      })
    }
  }, [])
  
  // Desktop-exclusive feature: large font settings
  const enableLargeTextMode = () => {
    document.documentElement.style.fontSize = '120%'
    localStorage.setItem('fontSize', 'large')
  }
  
  // Export report feature
  const exportToExcel = async (eventData: EventData) => {
    if (!isDesktop || !desktopAPI) return false
    
    try {
      const { save } = desktopAPI.dialog
      
      const filePath = await save({
        defaultPath: `${eventData.name}_Financial_Report.xlsx`,
        filters: [{
          name: 'Excel files',
          extensions: ['xlsx']
        }]
      })
      
      if (filePath) {
        const excelData = generateExcelReport(eventData)
        await desktopAPI.fs.writeTextFile(filePath, excelData)
        
        showSnackbar(`Report saved to ${filePath}`, 'success')
        return true
      }
    } catch (error) {
      showSnackbar('Export failed: ' + error.message, 'error')
    }
    
    return false
  }
  
  return { isDesktop, exportToExcel, enableLargeTextMode }
}

Desktop-Exclusive Features:

  • Large screen optimization: Elder-friendly interface design

  • File system access: Direct Excel/PDF export

  • Native system integration: System notifications, file associations

  • Cross-platform support: Unified macOS and Windows experience

🚀 Deployment Battle: Railway + Vercel Cloud-Native Architecture

Railway's Smart Startup Strategy

# start.sh - Production environment stability guarantee
#!/bin/bash
echo "🚀 Starting PAPA System..."

# Health check: Ensure database connection
python manage.py migrate --check
if [ $? -ne 0 ]; then
    echo "❌ Database migration check failed"
    exit 1
fi

# Database migration
python manage.py migrate --settings=pangcah_accounting.settings.railway

# Static file handling
python manage.py collectstatic --noinput

# Server startup: Prioritize gunicorn
if command -v gunicorn &> /dev/null; then
    echo "✅ Starting with Gunicorn + Uvicorn worker"
    gunicorn pangcah_accounting.asgi:application \
      -k uvicorn.workers.UvicornWorker \
      -b 0.0.0.0:$PORT \
      --workers 1 \
      --worker-connections 10 \
      --max-requests 100 \
      --timeout 120
else
    echo "✅ Fallback to Daphne"
    daphne -b 0.0.0.0 -p $PORT pangcah_accounting.asgi:application
fi

Vercel Frontend Performance Optimization Configuration

{
  "version": 2,
  "builds": [{
    "src": "package.json",
    "use": "@vercel/static-build",
    "config": { "distDir": "dist" }
  }],
  "routes": [
    {
      "src": "/assets/(.*)",
      "headers": { "cache-control": "max-age=31536000" }
    },
    {
      "src": "/(.*)",
      "dest": "/index.html"
    }
  ],
  "env": {
    "VITE_API_URL": "https://pangcah-accounting-system-production.up.railway.app"
  }
}

Deployment Effects:

  • Cold start time: Railway < 2 seconds, Vercel < 1 second

  • Static resource caching: 1-year validity, global CDN acceleration

  • Zero downtime deployment: Git push triggers automatic deployment

📱 Cross-Platform Architecture: macOS + Windows Unified Experience

Tauri's Cross-Platform Configuration

The desktop version's core value is providing unified cross-platform experience:

// Cross-platform desktop management
class DesktopManager {
  private apiClient: APIClient
  
  async initialize() {
    // Detect operating system
    const { platform } = await import('@tauri-apps/api/os')
    const currentPlatform = await platform()
    
    // Adjust UI based on platform
    this.adjustPlatformUI(currentPlatform)
  }
  
  adjustPlatformUI(platform: string) {
    const root = document.documentElement
    
    switch (platform) {
      case 'darwin': // macOS
        root.style.setProperty('--title-bar-height', '28px')
        root.style.setProperty('--button-spacing', '8px')
        break
        
      case 'win32': // Windows
        root.style.setProperty('--title-bar-height', '32px')
        root.style.setProperty('--button-spacing', '4px')
        break
    }
    
    // Elder-friendly settings
    if (localStorage.getItem('elderMode') === 'true') {
      root.style.fontSize = '120%'
      root.style.setProperty('--button-size', '48px')
      root.style.setProperty('--input-height', '44px')
    }
  }
  
  async saveExpense(expense: CreateExpenseRequest) {
    try {
      // Direct cloud API connection
      const result = await this.apiClient.post('/expenses/', expense)
      return result.data
    } catch (error) {
      showSnackbar('Save failed, please check network connection', 'error')
      throw error
    }
  }
}

Cross-Platform Advantages:

  • macOS native experience: Complies with Apple design guidelines

  • Windows native experience: Integrates Windows UI standards

  • Elder-friendly design: Large fonts, large buttons, clear interface

  • Keyboard operation optimization: Complete keyboard shortcut support

iPhone/Android Quick Expense Recording Design

Mobile version focuses on quick expense recording during events, perfectly complementing the desktop version:

Mobile Features:

  • One-tap recording: Large bottom add button

  • Simplified dashboard: Key information at a glance

  • Large font design: Cross-generational friendly reading

  • Touch optimization: Finger-friendly button sizes

📊 Excel Report Generation: Essential Feature for Government Subsidy Applications

Large-Screen Friendly Report Interface

When tribes apply for government subsidies, they need specific format financial reports. Desktop version designed specifically for large-screen operation:

// Excel report generation system
interface GovernmentReportFormat {
  eventInfo: {
    name: string
    date: string
    totalParticipants: number
    totalBudget: number
  }
  
  expenseBreakdown: Array<{
    category: string
    amount: number
    percentage: number
    receipts: string[]  // Receipt file paths
  }>
  
  participantList: Array<{
    name: string
    idNumber?: string  // Optional ID number
    contribution: number
    splitAmount: number
  }>
}

// Generate government format reports
const generateGovernmentReport = async (eventData: EventData) => {
  const { save } = await import('@tauri-apps/api/dialog')
  const { writeTextFile } = await import('@tauri-apps/api/fs')
  
  // Choose save location
  const filePath = await save({
    defaultPath: `${eventData.name}_Government_Subsidy_Report.xlsx`,
    filters: [{ name: 'Excel files', extensions: ['xlsx'] }]
  })
  
  if (filePath) {
    const reportData = {
      // Event basic information
      EventName: eventData.name,
      EventDate: formatDate(eventData.start_date),
      ParticipantCount: eventData.participants.length,
      TotalBudget: eventData.budget,
      ActualExpenses: eventData.total_expenses,
      
      // Expense details (categorized per government requirements)
      FoodExpenses: calculateCategoryTotal(eventData.expenses, 'Food'),
      TransportExpenses: calculateCategoryTotal(eventData.expenses, 'Transport'),
      VenueExpenses: calculateCategoryTotal(eventData.expenses, 'Venue'),
      OtherExpenses: calculateCategoryTotal(eventData.expenses, 'Other'),
      
      // Participant list (government format compliant)
      ParticipantList: eventData.participants.map(p => ({
        Name: p.user.name,
        Contribution: p.contribution,
        SplitAmount: p.split_amount
      }))
    }
    
    await writeTextFile(filePath, JSON.stringify(reportData, null, 2))
    showSnackbar('Government report exported', 'success')
  }
}

Government Application Support:

  • Standard format: Complies with Indigenous Affairs Council requirements

  • Complete records: Expense details + participant list

  • One-click export: Directly generates submittable reports

  • Privacy protection: Sensitive data stored locally only

🧪 Test-Driven Quality Assurance

Real-World Application of End-to-End Testing

# test_split_api.py - Complete testing of split functionality
class ExpenseSplitAPITest:
    def test_complex_split_scenario(self):
        """Test complex split scenario: Real family gathering situation"""
        
        # Create test event: Family dinner
        event_data = {
            "name": "Spring Festival Family Dinner",
            "budget": 5000,
            "participant_count": 8
        }
        
        # Test time-sensitive splitting
        # Xiao Ming joins midway, doesn't split previous expenses
        late_joiner_test = {
            "user": "Xiao Ming",
            "joined_at": "2025-01-02",
            "split_option": "NO_SPLIT_BEFORE_JOIN"
        }
        
        # Create expense: Day 1 BBQ costs
        expense_day1 = {
            "amount": 2000,
            "date": "2025-01-01",  # Before Xiao Ming joined
            "description": "Day 1 BBQ costs"
        }
        
        # Verify: Xiao Ming shouldn't split this expense
        response = self.client.post('/api/v1/expenses/', expense_day1)
        expense_id = response.json()['id']
        
        splits = self.client.get(f'/api/v1/expenses/{expense_id}/splits/')
        
        # Assert: Xiao Ming not in split list
        participant_names = [s['participant']['user']['name'] for s in splits.json()]
        assert "Xiao Ming" not in participant_names
        
        # Create expense: Day 2 transport (after Xiao Ming joined)
        expense_day2 = {
            "amount": 1000,
            "date": "2025-01-02",
            "description": "Day 2 transport costs"
        }
        
        response = self.client.post('/api/v1/expenses/', expense_day2)
        expense_id = response.json()['id']
        
        splits = self.client.get(f'/api/v1/expenses/{expense_id}/splits/')
        participant_names = [s['participant']['user']['name'] for s in splits.json()]
        
        # Assert: Xiao Ming should split this expense
        assert "Xiao Ming" in participant_names

🎯 Today's Achievements and Tomorrow's Outlook

Technical Achievements

  • ✅ Smart environment detection API architecture

  • ✅ Seamless JWT refresh mechanism

  • ✅ Tauri cross-platform desktop version (macOS + Windows)

  • ✅ Elder-friendly large-screen interface design

  • ✅ Native desktop experience and performance optimization

  • ✅ End-to-end testing covering core functionality

Key Insights

  1. Architectural flexibility beats over-engineering: One API configuration supports three deployment modes

  2. User experience is priceless: Seamless token refresh makes collaboration smoother

  3. Cross-platform is essential: Unified macOS and Windows support reduces learning costs

  4. Elder-friendly design: Large-screen interfaces improve usability and operation confidence

AI-Assisted Development Effects

  • GitHub Copilot generated 50% of test cases

  • Claude 3.5 helped design reconnection strategies and error handling

  • But core architectural decisions still require battle-tested experience guidance

🏀 Tomorrow's Preview

Day 5 will share Team Collaboration and Product Management Battle Experience, including:

  • How to balance the dual roles of engineer and PM

  • Agile development application in cultural technology projects

  • User feedback-driven product iteration strategies

Technology's ultimate goal is serving people, not showing off skills. PAPA's frontend-backend integration proves: When technology deeply integrates with culture, truly valuable solutions are created.


🚀 Blake Lab - Leading in Both AI and Cultural Technology
💡 20 years of government projects | 🤖 AI Indigenous applications | 🎯 Indigenous language NLP development | 📈 Cultural-sensitive design
🌐 wchung.tw | 📧 [email protected]

Follow Blake Lab to explore the infinite possibilities of technology and culture together!

Enjoyed this article? Show some love!

0
Clap

Enjoyed this article?

Subscribe for engineering notes and AI development insights

We respect your privacy. No spam, unsubscribe anytime.

Share this article

Comments