Mock application for testing and demonstrating the OneKey Cloud Sync Server component integration.
This is a sample Midway.js application that demonstrates how to integrate and use the @onekeyhq/cloud-sync-server component. It provides a complete working example with MongoDB and Kafka adapters, along with REST API endpoints for testing synchronization functionality.
- Complete Integration Example: Shows how to properly integrate the sync component
- MongoDB Adapter Implementation: Working example of MongoDB adapter
- Kafka Adapter Implementation: Example Kafka integration for event streaming
- REST API Endpoints: Ready-to-use endpoints for testing sync operations
- Dependency Provider: Example implementation of required dependencies
- Development Ready: Hot reload and debugging support
- Node.js >= 24
- MongoDB instance (local or remote)
- Kafka broker (optional, for event streaming)
- Yarn package manager
# From the monorepo root
yarn install
# Or from this directory
cd examples/mock-app
yarn install
Create a .env file in the mock-app directory:
# Server Configuration
PORT=7001
NODE_ENV=development
# MongoDB Configuration
MONGODB_URI=mongodb://localhost:27017/onekey-sync
MONGODB_USER=
MONGODB_PASSWORD=
# Kafka Configuration (Optional)
KAFKA_BROKERS=localhost:9092
KAFKA_CLIENT_ID=mock-app
KAFKA_GROUP_ID=sync-group
# Sync Component Configuration
SYNC_ENABLE_CACHE=true
SYNC_CACHE_PREFIX=sync:
SYNC_CACHE_TTL=300
The application configuration is located in src/config/:
// src/config/config.default.ts
export default {
port: 7001,
koa: {
port: 7001,
},
sync: {
enableCache: true,
cachePrefix: 'sync:',
cacheTTL: 300,
},
mongodb: {
uri: process.env.MONGODB_URI || 'mongodb://localhost:27017/onekey-sync',
},
kafka: {
brokers: process.env.KAFKA_BROKERS?.split(',') || ['localhost:9092'],
clientId: process.env.KAFKA_CLIENT_ID || 'mock-app',
},
};
# Development mode with hot reload
yarn dev
# Production mode
yarn build
yarn start
# Run tests
yarn test
# Generate test coverage
yarn cov
Once the application is running, the following endpoints are available:
POST http://localhost:7001/sync/download?userId={userId}
Request Body:
{
"since": 1234567890,
"limit": 100,
"deviceId": "device-123"
}
Response:
{
"items": [...],
"hasMore": false,
"lastSync": 1234567890
}
POST http://localhost:7001/sync/upload?userId={userId}
Request Body:
{
"items": [
{
"id": "item-1",
"data": {...},
"version": 1,
"timestamp": 1234567890
}
],
"deviceId": "device-123"
}
Response:
{
"success": true,
"processed": 1,
"conflicts": []
}
POST http://localhost:7001/sync/check?userId={userId}
Request Body:
{
"items": ["item-1", "item-2"],
"deviceId": "device-123"
}
Response:
{
"status": "synced",
"pendingItems": [],
"lastSync": 1234567890
}
POST http://localhost:7001/sync/lock?userId={userId}
Request Body:
{
"action": "lock", // or "unlock"
"itemId": "item-1",
"deviceId": "device-123"
}
Response:
{
"success": true,
"lockId": "lock-123"
}
POST http://localhost:7001/sync/flush?userId={userId}
Request Body:
{
"force": true,
"deviceId": "device-123"
}
Response:
{
"success": true,
"flushed": 10
}
mock-app/
├── src/
│ ├── adapter/ # Adapter implementations
│ │ ├── mongodb.adapter.ts # MongoDB adapter
│ │ └── kafka.adapter.ts # Kafka adapter
│ ├── config/ # Application configuration
│ │ └── config.default.ts # Default configuration
│ ├── controller/ # REST API controllers
│ │ └── sync.controller.ts # Sync endpoints
│ ├── service/ # Service layer
│ │ └── dependencies.provider.ts # Dependencies provider
│ └── configuration.ts # Midway.js configuration
├── test/ # Test files
│ └── sync.test.ts # Sync controller tests
├── logs/ # Application logs
├── bootstrap.js # Application bootstrap
├── package.json
├── tsconfig.json
└── jest.config.js
The MongoDB adapter (src/adapter/mongodb.adapter.ts) implements the IMongodbAdapter interface:
export class MongodbAdapterImpl implements IMongodbAdapter {
async findUserById(userId: string): Promise<any> {
// Implementation using mongoose models
}
async findSyncDataByUserId(userId: string): Promise<any[]> {
// Query sync data for user
}
async bulkWriteSyncData(operations: any[]): Promise<void> {
// Bulk write operations
}
// ... other methods
}
The Kafka adapter (src/adapter/kafka.adapter.ts) handles event streaming:
export class KafkaAdapterImpl implements IKafkaAdapter {
async sendPrimeNotification(data: ISyncNotificationData): Promise<void> {
// Send notification to Kafka topic
}
}
The dependencies provider (src/service/dependencies.provider.ts) supplies required dependencies:
export class SyncDependenciesProvider implements ISyncDependenciesProvider {
async updateUser(userId: string, data: any): Promise<void> {
// Update user implementation
}
getTraceHeaders(): ITraceHeaders {
// Return trace headers for logging
}
get errors(): ISyncErrors {
// Return custom error classes
}
}
# Run all tests
yarn test
# Run tests in watch mode
yarn test -- --watch
# Generate coverage report
yarn cov
Use the provided test file (test/sync.test.ts) as a template:
import { createApp, close, createHttpRequest } from '@midwayjs/mock';
describe('test/sync.test.ts', () => {
it('should POST /sync/upload', async () => {
const app = await createApp();
const result = await createHttpRequest(app)
.post('/sync/upload?userId=test-user')
.send({
items: [{
id: 'test-item',
data: { test: true },
}],
});
expect(result.status).toBe(200);
expect(result.body.success).toBe(true);
await close(app);
});
});
- Start MongoDB:
docker run -d -p 27017:27017 mongo:latest
- Start Kafka (optional):
docker run -d -p 9092:9092 confluentinc/cp-kafka:latest
- Start the application:
yarn dev
- Test with curl or Postman:
# Upload data
curl -X POST http://localhost:7001/sync/upload?userId=test-user \
-H "Content-Type: application/json" \
-d '{"items":[{"id":"item-1","data":{"test":true}}]}'
# Download data
curl -X POST http://localhost:7001/sync/download?userId=test-user \
-H "Content-Type: application/json" \
-d '{"since":0,"limit":10}'
- Use VS Code's built-in debugger with the provided launch configuration
- Set breakpoints in TypeScript files
- Run the debugger with F5
The application uses Midway.js logger:
import { ILogger } from '@midwayjs/logger';
import { Logger } from '@midwayjs/core';
export class SyncController {
@Logger()
logger: ILogger;
async upload() {
this.logger.info('Processing upload request');
// ...
}
}
Logs are stored in the logs/ directory:
midway-app.log- Application logsmidway-core.log- Framework logscommon-error.log- Error logs
Development mode includes hot reload:
yarn dev
# Make changes to source files
# Application automatically restarts
# Build TypeScript to JavaScript
yarn build
# Start production server
NODE_ENV=production yarn start
FROM node:24-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY yarn.lock ./
# Install dependencies
RUN yarn install --production
# Copy source code
COPY . .
# Build application
RUN yarn build
# Expose port
EXPOSE 7001
# Start application
CMD ["yarn", "start"]
// ecosystem.config.js
module.exports = {
apps: [{
name: 'mock-app',
script: './bootstrap.js',
instances: 2,
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 7001,
},
}],
};
-
MongoDB Connection Failed
Error: MongooseServerSelectionErrorSolution: Ensure MongoDB is running and accessible
-
Kafka Connection Issues
Error: KafkaJSConnectionErrorSolution: Check Kafka broker configuration
-
Port Already in Use
Error: EADDRINUSE: address already in use :::7001Solution: Change port in configuration or kill existing process
-
TypeScript Compilation Errors
Error: Cannot find module '@onekeyhq/cloud-sync-server'Solution: Run
yarn installfrom monorepo root
Enable debug logging:
DEBUG=midway* yarn dev
- Error Handling: Always implement proper error handling in adapters
- Validation: Use DTOs for input validation
- Logging: Log important operations for debugging
- Testing: Write tests for custom implementations
- Configuration: Use environment variables for sensitive data
- Monitoring: Implement health checks and metrics
- Fork the repository
- Create your feature branch
- Make changes and add tests
- Ensure all tests pass
- Submit a pull request
This project is part of the OneKey ecosystem.
For issues and questions, please open an issue on GitHub or contact the OneKey development team.