Sync Fields

Sync fields determine which data from your models is synchronized to clients. Proper field selection is crucial for performance, security, and user experience.

Field Selection Strategies

1. Essential Fields Only

Start with the minimum required fields and add more as needed:
class Message extends Model
{
    use Harmonics;
    
    // Minimal sync fields for basic functionality
    protected $syncFields = [
        'id',          // Required: Primary key
        'body',        // Required: Main content
        'user_id',     // Required: Ownership
        'created_at'   // Required: Ordering/timestamps
    ];
}

2. Progressive Field Selection

Add fields based on feature requirements:
class Message extends Model
{
    use Harmonics;
    
    protected $syncFields = [
        // Core fields (always needed)
        'id',
        'body',
        'user_id',
        'created_at',
        
        // UI enhancement fields
        'updated_at',      // For "edited" indicators
        'is_edited',       // Edit status
        
        // Feature-specific fields
        'reply_to_id',     // Threading support
        'attachment_url',  // File attachments
        'reaction_counts', // Emoji reactions
        
        // Meta fields
        'platform_id',     // Multi-platform support
        'channel_id'       // Channel organization
    ];
}

3. Role-Based Field Selection

Sync different fields based on user permissions:
class User extends Model
{
    use Harmonics;
    
    public function getSyncFields(): array
    {
        $fields = [
            'id',
            'name',
            'avatar_url',
            'is_online',
            'created_at'
        ];
        
        // Add contact info for team members
        if ($this->isTeamMember(auth()->user())) {
            $fields[] = 'email';
            $fields[] = 'phone';
        }
        
        // Add admin fields for administrators
        if (auth()->user()?->isAdmin()) {
            $fields[] = 'last_login_at';
            $fields[] = 'login_count';
            $fields[] = 'is_verified';
        }
        
        return $fields;
    }
    
    private function isTeamMember(User $user): bool
    {
        return $this->teams()->whereHas('users', function($query) use ($user) {
            $query->where('user_id', $user->id);
        })->exists();
    }
}

Relationship-Based Fields

Include different fields based on model relationships:
class Comment extends Model
{
    use Harmonics;
    
    public function getSyncFields(): array
    {
        $fields = [
            'id',
            'content',
            'post_id',
            'user_id',
            'created_at'
        ];
        
        // Include moderation fields for post authors and moderators
        if (auth()->user()?->can('moderate', $this->post)) {
            $fields[] = 'is_flagged';
            $fields[] = 'flag_reason';
            $fields[] = 'moderator_notes';
        }
        
        // Include private fields for comment author
        if ($this->user_id === auth()->id()) {
            $fields[] = 'is_draft';
            $fields[] = 'edit_history';
        }
        
        return $fields;
    }
}

Performance Optimization

Field Size Considerations

Be mindful of field sizes to optimize sync performance:
class Article extends Model
{
    use Harmonics;
    
    public function getSyncFields(): array
    {
        $fields = [
            'id',
            'title',
            'excerpt',      // ✅ Good: Short summary
            'status',
            'author_id',
            'created_at',
            'updated_at'
            // 'content'    // ❌ Avoid: Large text field
            // 'raw_html'   // ❌ Avoid: Even larger processed content
        ];
        
        // Only include full content when specifically requested
        if ($this->shouldSyncFullContent()) {
            $fields[] = 'content';
        }
        
        return $fields;
    }
    
    private function shouldSyncFullContent(): bool
    {
        // Include full content only in specific contexts
        return request()->routeIs('articles.show') ||
               auth()->user()?->can('edit', $this);
    }
}

Security Best Practices

Field Whitelisting

Always use explicit whitelisting rather than blacklisting:
class UserProfile extends Model
{
    use Harmonics;
    
    // ✅ Good: Explicit whitelist
    protected $syncFields = [
        'id',
        'username',
        'display_name',
        'bio',
        'avatar_url',
        'is_verified'
    ];
    
    // ❌ Avoid: Blacklisting (easy to forget sensitive fields)
    // public function getSyncFields(): array
    // {
    //     return array_diff(
    //         array_keys($this->getAttributes()),
    //         ['password', 'remember_token'] // Easy to miss new sensitive fields
    //     );
    // }
}

Sensitive Data Handling

Never sync sensitive information:
class PaymentMethod extends Model
{
    use Harmonics;
    
    protected $syncFields = [
        'id',
        'type',              // ✅ 'credit_card', 'paypal', etc.
        'last_four',         // ✅ Last 4 digits only
        'brand',             // ✅ 'visa', 'mastercard', etc.
        'expires_at',        // ✅ Expiration date
        'is_default',        // ✅ Default payment method flag
        'created_at'
        // 'card_number'     // ❌ Never sync full card number
        // 'cvv'             // ❌ Never sync security code
        // 'stripe_token'    // ❌ Never sync payment tokens
    ];
}

Field Validation

Testing Sync Fields

Unit Tests

Test your sync field configuration:
// tests/Unit/Models/UserTest.php
class UserTest extends TestCase
{
    public function test_sync_fields_include_required_fields()
    {
        $user = User::factory()->create();
        $syncFields = $user->getSyncFields();
        
        // Assert required fields are present
        $this->assertContains('id', $syncFields);
        $this->assertContains('name', $syncFields);
        $this->assertContains('email', $syncFields);
    }
    
    public function test_sync_fields_exclude_sensitive_data()
    {
        $user = User::factory()->create();
        $syncFields = $user->getSyncFields();
        
        // Assert sensitive fields are excluded
        $this->assertNotContains('password', $syncFields);
        $this->assertNotContains('remember_token', $syncFields);
        $this->assertNotContains('email_verified_at', $syncFields);
    }
    
    public function test_admin_users_get_additional_fields()
    {
        $admin = User::factory()->admin()->create();
        $this->actingAs($admin);
        
        $user = User::factory()->create();
        $syncFields = $user->getSyncFields();
        
        $this->assertContains('last_login_at', $syncFields);
        $this->assertContains('is_verified', $syncFields);
    }
}

Next Steps


You now understand how to effectively configure sync fields for optimal performance and security. Next, learn how to apply sync filters to control which records each user receives.