Skip to main content

Best Practices

This document provides best practice guidelines for development based on the Lovrabet platform.

Prerequisites

If you're not familiar with Lovrabet's tool ecosystem, we recommend reading Developer Tools Overview first.


Core Philosophy

AI handles standardized repetitive tasks, humans focus on creative value output

  • AI's Strength - Fast generation, standardization, zero-error basic functionality
  • Human's Strength - Creative thinking, industry insights, user empathy
  • Perfect Collaboration - AI provides infrastructure, humans build unique value

Application Scenarios

1. Mini Program Ecosystem Extension

Build WeChat Mini Programs and Alipay Mini Programs based on enterprise data:

import { createClient } from "@lovrabet/sdk";

const client = createClient({
appCode: "your-enterprise-app",
token: wx.getStorageSync("userToken"),
});

const customerData = await client.models.customers.filter({
region: "East China",
level: "VIP",
});

2. Workflow Automation

Build complex approval processes and data processing pipelines:

const approvalWorkflow = {
trigger: await client.models.orders.filter({ status: "pending" }),
conditions: [
{ field: "amount", operator: ">", value: 10000 },
{ field: "customer.level", operator: "=", value: "VIP" },
],
actions: ["sendNotification", "createApprovalTask", "updateOrderStatus"],
};

3. Multi-System Integration Hub

Connect Lovrabet with existing enterprise systems (ERP, CRM, OA):

const dataHub = {
lovrabet: await lovrabetClient.models.products.filter(),
erp: await erpConnector.getInventory(),
crm: await crmConnector.getCustomers(),
synchronize: () => {
// Complex data synchronization and transformation logic
},
};

Client Management

Frontend: Singleton Pattern Reuse

// ✅ Recommended: Singleton pattern, global reuse
// src/api/client.ts
import { createClient } from "@lovrabet/sdk";

export const client = createClient({
appCode: "your-app-code",
});

// Use in components
import { client } from "@/api/client";
// ❌ Not recommended: Creating new instance every time
function MyComponent() {
const client = createClient({ appCode: "..." }); // Creates on every render
}

Backend: Spring Bean Singleton

// ✅ Recommended: Use @Bean singleton
@Configuration
public class LovrabetConfig {
@Bean
public LovrabetSDKClient lovrabetSDKClient() {
return new LovrabetSDKClient(accessKey, baseUrl);
}
}

Security

AccessKey Management

# ✅ Use environment variables
export LOVRABET_ACCESS_KEY="ak-your-access-key"
// ❌ Never hardcode AccessKey in frontend
const client = createClient({
accessKey: "ak-xxx", // Dangerous! Will be exposed in browser
});

// ✅ Use Cookie or Token in browser
const client = createClient({
appCode: "your-app-code",
// Automatically uses Cookie authentication
});

Sensitive Data Masking

// Frontend: Mask phone number
const maskPhone = (phone: string) => {
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
};
// 138****8000
// Backend: Log masking
String maskedPhone = phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
log.info("Customer phone: {}", maskedPhone);

Performance Optimization

Pagination and Debouncing

// ✅ Use pagination
const { data } = await client.models.customers.filter({
currentPage: 1,
pageSize: 20,
});

// ✅ Search debouncing
import { debounce } from "lodash-es";

const handleSearch = debounce(async (keyword) => {
await client.models.customers.filter({ searchKeyword: keyword });
}, 300);

Code Splitting

// ✅ Route lazy loading
import { lazy } from "react";

const CustomerAnalysis = lazy(() => import("./pages/CustomerAnalysis"));

Backend Caching

// Use Caffeine cache
private final Cache<String, Object> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();

Error Handling

Frontend Unified Handling

try {
const result = await client.models.customers.filter(params);
if (result.success) {
setData(result.data);
} else {
message.error(result.message);
}
} catch (error) {
console.error("API call failed:", error);
message.error("Network error, please try again later");
}

Backend Retry Mechanism

public <T> LovrabetResult<T> executeWithRetry(
Supplier<LovrabetResult<T>> operation, int maxRetries) {
for (int attempt = 0; attempt <= maxRetries; attempt++) {
try {
LovrabetResult<T> result = operation.get();
if (result.isSuccess()) return result;
Thread.sleep((long) Math.pow(2, attempt) * 1000);
} catch (Exception e) {
if (attempt == maxRetries) throw new RuntimeException("Retry failed", e);
}
}
return null;
}

Logging Standards

Structured Logging

@Slf4j
public class DataService {
public void createData(Map<String, Object> data) {
long startTime = System.currentTimeMillis();

log.info("Start operation - operation={}, dataSize={}", "create", data.size());

LovrabetResult<String> result = sdkClient.create(request);
long duration = System.currentTimeMillis() - startTime;

if (result.isSuccess()) {
log.info("Operation succeeded - id={}, duration={}ms", result.getData(), duration);
} else {
log.error("Operation failed - code={}, duration={}ms", result.getResultCode(), duration);
}
}
}

Testing Strategy

Frontend Unit Testing

import { render, screen, waitFor } from "@testing-library/react";

test("should load customers", async () => {
render(<CustomerList />);
await waitFor(() => {
expect(screen.getByText("Zhang San")).toBeInTheDocument();
});
});

Backend Integration Testing

@SpringBootTest
public class DataServiceIntegrationTest {
@Autowired
private DataService dataService;

@Test
public void testGetCustomers() {
List<Map<String, Object>> customers = dataService.getCustomers(1, 10);
assertNotNull(customers);
assertTrue(customers.size() > 0);
}
}

Deployment Recommendations

Frontend Deployment

lovrabet build
# Artifacts in dist/ directory, deploy to CDN

Nginx Configuration:

server {
listen 80;
root /var/www/your-app/dist;

location / {
try_files $uri $uri/ /index.html;
}

location ~* \.(js|css|png|jpg|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}

Backend Docker Deployment

FROM openjdk:11-jre-slim
WORKDIR /app
COPY target/myapp.jar app.jar
ENV LOVRABET_ACCESS_KEY=""
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Health Check

@GetMapping("/health/lovrabet")
public Map<String, Object> checkHealth() {
Map<String, Object> health = new HashMap<>();
try {
long start = System.currentTimeMillis();
LovrabetResult<?> result = sdkClient.getDatasetCodeList(request);
health.put("status", result.isSuccess() ? "UP" : "DOWN");
health.put("responseTime", (System.currentTimeMillis() - start) + "ms");
} catch (Exception e) {
health.put("status", "DOWN");
health.put("error", e.getMessage());
}
return health;
}

Summary

Practice AreaKey Points
Client ManagementUse singleton pattern for both frontend and backend
SecurityNever hardcode AccessKey in frontend
Performance OptimizationPagination, caching, code splitting
Error HandlingUnified handling + retry mechanism
Log ManagementStructured logging, sensitive info masking
Testing StrategyUnit testing + integration testing
DeploymentHealth checks, containerization