# Best Practices

Professional development guidelines for VibesEZ-Laptop apps and integrations.

## Code Quality

### JavaScript/TypeScript

#### Type Safety

Always use TypeScript:

```typescript
// Good
interface WeatherData {
    temperature: number;
    condition: string;
    city: string;
}

const data: WeatherData = {
    temperature: 72,
    condition: 'Sunny',
    city: 'Los Santos'
};

// Avoid
const data = {
    temp: 72,
    cond: 'Sunny'
};
```

#### Error Handling

```typescript
// Good
try {
    const response = await fetch('/api/data');
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.json();
} catch (error) {
    console.error('Failed to fetch:', error);
    return null;
}

// Avoid
const response = await fetch('/api/data');
return await response.json();
```

#### Naming Conventions

```typescript
// Good
const maxPlayerCount = 128;
const isPlayerOnline = true;
const getPlayerBalance = async (id: string) => { };

// Avoid
const mpc = 128;
const online = true;
const gPBal = async (i) => { };
```

### Lua

#### Validation

```lua
-- Good
local function transfer(from, to, amount)
    if not from or not to then
        return false, 'Invalid parameters'
    end
    if type(amount) ~= 'number' or amount <= 0 then
        return false, 'Invalid amount'
    end
    -- Perform transfer
end

-- Avoid
local function transfer(from, to, amount)
    -- No validation, just do it
end
```

#### Error Handling

```lua
-- Good
local success, result = pcall(function()
    return exports['VibesEZ-Laptop']:GetBalance(id, currency)
end)

if success then
    print('Balance: ' .. result)
else
    print('Error: ' .. result)
end

-- Avoid
local balance = exports['VibesEZ-Laptop']:GetBalance(id, currency)
print('Balance: ' .. balance)  -- Will crash if export fails
```

***

## Security

### Input Validation

**Always validate user input:**

```typescript
function processTransfer(amount: any, recipient: any): boolean {
    // Validate amount
    if (!Number.isFinite(amount) || amount <= 0) {
        throw new Error('Invalid amount');
    }
    
    // Validate recipient
    if (typeof recipient !== 'string' || recipient.length === 0) {
        throw new Error('Invalid recipient');
    }
    
    // Safe to proceed
    return true;
}
```

### Sensitive Data

**Never expose:**

* Password hashes
* Private keys
* Admin tokens
* API credentials
* Personal information

**Store securely:**

```typescript
// Good - stored on server
const config = {
    apiKey: process.env.EXTERNAL_API_KEY || '',
    dbPassword: process.env.DB_PASSWORD || ''
};

// Bad - hardcoded in code
const config = {
    apiKey: 'sk_live_1234567890',
    dbPassword: 'admin123'
};
```

### Authorization

**Check permissions:**

```lua
local function requireAdmin(playerId)
    local player = QBCore.Functions.GetPlayer(playerId)
    if not hasAdminPerms(player) then
        return false, 'Insufficient permissions'
    end
    return true
end
```

***

## Performance

### Optimization Techniques

#### Lazy Loading

```typescript
// Load data when needed, not upfront
const getWeatherData = async () => {
    const cached = cache.get('weather');
    if (cached) return cached;
    
    const data = await fetchWeather();
    cache.set('weather', data, 300000);  // 5 min cache
    return data;
};
```

#### Batch Operations

```lua
-- Good: Batch transfers
local transfers = {
    { to = 'id1', amount = 100 },
    { to = 'id2', amount = 200 }
}

for _, transfer in ipairs(transfers) do
    exports['VibesEZ-Laptop']:AddCrypto(
        playerId, 'BTC', transfer.amount, 'Batch payout'
    )
end

-- Avoid: Separate DB calls
exports['VibesEZ-Laptop']:AddCrypto(playerId, 'BTC', 100, 'Payout 1')
exports['VibesEZ-Laptop']:AddCrypto(playerId, 'BTC', 200, 'Payout 2')
```

#### Caching

```typescript
class DataService {
    private cache = new Map<string, CachedData>();
    
    get(key: string) {
        const cached = this.cache.get(key);
        if (cached && !this.isExpired(cached)) {
            return cached.value;
        }
        return null;
    }
    
    set(key: string, value: any, ttl: number) {
        this.cache.set(key, {
            value,
            expiration: Date.now() + ttl
        });
    }
    
    private isExpired(data: CachedData) {
        return Date.now() > data.expiration;
    }
}
```

### Memory Management

```typescript
// Use cleanup functions
useEffect(() => {
    const interval = setInterval(updateData, 5000);
    
    // Cleanup on unmount
    return () => clearInterval(interval);
}, []);
```

***

## User Experience

### Loading States

```typescript
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(null);

useEffect(() => {
    fetchData()
        .then(setData)
        .catch(setError)
        .finally(() => setIsLoading(false));
}, []);

return (
    <>
        {isLoading && <LoadingSpinner />}
        {error && <ErrorMessage error={error} />}
        {data && <DataDisplay data={data} />}
    </>
);
```

### Error Messages

Create user-friendly error messages:

```typescript
function getUserFriendlyError(error: Error): string {
    if (error.message.includes('ECONNREFUSED')) {
        return 'Connection failed. Please check your network.';
    }
    if (error.message.includes('TIMEOUT')) {
        return 'Request took too long. Please try again.';
    }
    return 'Something went wrong. Please try again later.';
}
```

### Responsive Design

```css
/* Mobile-first approach */
.container {
    padding: 1rem;
}

@media (min-width: 768px) {
    .container {
        padding: 2rem;
        display: grid;
        grid-template-columns: 1fr 1fr;
    }
}
```

***

## Testing

### Unit Tests

```typescript
describe('CryptoService', () => {
    it('should transfer crypto between wallets', async () => {
        const result = await service.transfer(
            'player1', 'player2', 'BTC', 50
        );
        expect(result).toBe(true);
    });
    
    it('should reject transfer with insufficient funds', async () => {
        const result = await service.transfer(
            'poorPlayer', 'richPlayer', 'BTC', 9999
        );
        expect(result).toBe(false);
    });
});
```

### Integration Tests

```typescript
describe('Laptop Integration', () => {
    it('should create wallet on first open', async () => {
        const player = new MockPlayer();
        await player.openLaptop();
        expect(player.hasWallet('BTC')).toBe(true);
    });
});
```

***

## Documentation

### Code Comments

```typescript
/**
 * Transfers cryptocurrency between two players
 * 
 * @param from - Sender player identifier
 * @param to - Receiver player identifier
 * @param currency - Currency code (BTC, ETH)
 * @param amount - Amount to transfer (must be positive)
 * @returns {Promise<boolean>} True if successful, false otherwise
 * 
 * @throws {Error} If identifiers are invalid or currency not found
 * 
 * @example
 * const success = await transfer('player1', 'player2', 'BTC', 50);
 */
async function transfer(
    from: string,
    to: string,
    currency: string,
    amount: number
): Promise<boolean> {
    // Implementation...
}
```

### README Files

Every project needs a README:

```markdown
# Weather App

Simple weather information display for VibesEZ-Laptop.

## Features
- Current weather
- 5-day forecast
- Auto-refresh

## Installation
1. Copy to resources/[apps]/weather_app
2. Add to server.cfg
3. Restart server

## Configuration
Edit `config.lua` to change update interval

## Support
Report issues on GitHub
```

***

## Deployment

### Version Management

```json
{
    "name": "weather-app",
    "version": "1.0.0",
    "description": "Weather display app",
    "author": "Your Name"
}
```

### Semantic Versioning

* **1.0.0** - {Major}.{Minor}.{Patch}
  * Major: Breaking changes
  * Minor: New features
  * Patch: Bug fixes

### Release Checklist

* [ ] Tests passing
* [ ] Documentation updated
* [ ] Version number bumped
* [ ] Changelog updated
* [ ] Build successful
* [ ] Code reviewed
* [ ] Security check done

***

## Monitoring

### Logging

```typescript
interface LogEntry {
    level: 'debug' | 'info' | 'warn' | 'error';
    message: string;
    timestamp: number;
    context?: Record<string, any>;
}

const log = (level: string, message: string, context?: any) => {
    const entry: LogEntry = {
        level: level as any,
        message,
        timestamp: Date.now(),
        context
    };
    console.log(JSON.stringify(entry));
};
```

### Health Checks

```lua
RegisterCommand('health', function()
    print('Database: ' .. (databaseHealthOK() and 'OK' or 'DOWN'))
    print('API: ' .. (apiHealthOk() and 'OK' or 'DOWN'))
    print('Memory: ' .. (math.floor(collectgarbage('count') / 1024)) .. 'MB')
end)
```

***

## Summary

✓ Write clean, typed code

✓ Validate all inputs

✓ Handle errors gracefully

✓ Optimize for performance

✓ Document thoroughly

✓ Test comprehensively

✓ Monitor in production

✓ Secure sensitive data

***

For code examples, see [Examples & Templates](/vibesez/docs/laptop/for-developers/examples.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://vibesez.gitbook.io/vibesez/docs/laptop/for-developers/best-practices.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
