Build Your First App
Create a complete delivery tracking application from scratch using De. Platform.
What You'll Build
A real-time delivery tracking app with:
- Interactive map with pickup and delivery locations
- Live vehicle tracking
- Route visualization with traffic
- Delivery status updates
- Customer notifications
Time to complete: 30 minutes
Prerequisites
Workspace Created
Have a De. workspace and access token
Project Setup
1
Create Project Directory
Set up your project structure
bash
mkdir delivery-tracker
cd delivery-tracker
npm init -y2
Install Dependencies
Add required packages
bash
npm install @de./sdk
npm install --save-dev vite typescript @types/node3
Project Structure
Create the following file structure
delivery-tracker/
├── src/
│ ├── main.ts
│ ├── auth.ts
│ ├── map.ts
│ └── tracking.ts
├── public/
│ └── index.html
├── .env
├── package.json
├── tsconfig.json
└── vite.config.tsConfiguration Files
4
Configure TypeScript
Create tsconfig.json
json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}5
Configure Vite
Create vite.config.ts
typescript
import { defineConfig } from 'vite'
export default defineConfig({
server: {
port: 3000
},
build: {
outDir: 'dist',
sourcemap: true
}
})6
Environment Variables
Create .env file
env
VITE_DE_WORKSPACE_ID=your_workspace_id
VITE_DE_ACCESS_TOKEN=your_access_token
VITE_DE_API_URL=https://api.dedot.io
VITE_DE_MSI_URL=https://map.dedot.ioHTML Structure
7
Create HTML Template
Set up public/index.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Delivery Tracker - De. Platform</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f5;
}
#app {
display: flex;
height: 100vh;
}
#sidebar {
width: 350px;
background: white;
border-right: 1px solid #e0e0e0;
overflow-y: auto;
padding: 20px;
}
#map-container {
flex: 1;
position: relative;
}
.header {
margin-bottom: 30px;
}
.header h1 {
font-size: 24px;
color: #0ea5e9;
margin-bottom: 8px;
}
.header p {
color: #666;
font-size: 14px;
}
.section {
margin-bottom: 30px;
}
.section h2 {
font-size: 16px;
font-weight: 600;
margin-bottom: 15px;
color: #333;
}
.input-group {
margin-bottom: 15px;
}
.input-group label {
display: block;
font-size: 13px;
color: #666;
margin-bottom: 5px;
}
.input-group input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
}
.btn {
width: 100%;
padding: 12px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: #0ea5e9;
color: white;
}
.btn-primary:hover {
background: #0284c7;
}
.status-card {
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin-bottom: 10px;
}
.status-card h3 {
font-size: 14px;
color: #333;
margin-bottom: 8px;
}
.status-card p {
font-size: 13px;
color: #666;
}
.status-indicator {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
}
.status-indicator.active {
background: #10b981;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
#loading {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1000;
}
#loading.show {
display: block;
}
</style>
</head>
<body>
<div id="app">
<div id="sidebar">
<div class="header">
<h1>Delivery Tracker</h1>
<p>Powered by De. Platform</p>
</div>
<div class="section">
<h2>Delivery Details</h2>
<div class="input-group">
<label>Pickup Address</label>
<input type="text" id="pickup-address" placeholder="123 Main St, City">
</div>
<div class="input-group">
<label>Delivery Address</label>
<input type="text" id="delivery-address" placeholder="456 Oak Ave, City">
</div>
<button class="btn btn-primary" id="create-delivery">
Create Delivery
</button>
</div>
<div class="section" id="tracking-section" style="display: none;">
<h2>Tracking Status</h2>
<div id="status-container"></div>
</div>
</div>
<div id="map-container"></div>
</div>
<div id="loading">
<p>Loading map...</p>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>Authentication Module
8
Create Authentication Module
Set up src/auth.ts
typescript
import De from '@de./sdk'
export class AuthManager {
private access: any
constructor() {
this.access = new De.Access({
workspace: import.meta.env.VITE_DE_WORKSPACE_ID,
accessToken: import.meta.env.VITE_DE_ACCESS_TOKEN,
env: 'prod'
})
}
getAccess() {
return this.access
}
async getCurrentUser() {
try {
const response = await this.access.request({
url: '/user',
method: 'GET'
})
return response.data
} catch (error) {
console.error('Failed to get user:', error)
return null
}
}
}Map Integration
9
Create Map Module
Set up src/map.ts
typescript
import De from '@de./sdk'
export class MapManager {
private msi: any
private controls: any
private handles: any
async initialize() {
try {
// Show loading
document.getElementById('loading')?.classList.add('show')
// Initialize MSI
this.msi = new De.MSI({
element: 'map-container',
accessToken: import.meta.env.VITE_DE_ACCESS_TOKEN
})
// Load map
const result = await this.msi.load()
this.controls = result.controls
this.handles = result.handles
// Hide loading
document.getElementById('loading')?.classList.remove('show')
console.log('Map initialized successfully')
return true
} catch (error) {
console.error('Failed to initialize map:', error)
return false
}
}
async setPickupLocation(coords: { lng: number; lat: number }, label: string) {
if (!this.handles) {
throw new Error('Map not initialized')
}
await this.handles.pickupPoint(coords, {
label: label,
sublabel: 'Pickup Location',
draggable: false
})
}
async setDeliveryLocation(coords: { lng: number; lat: number }, label: string) {
if (!this.handles) {
throw new Error('Map not initialized')
}
await this.handles.dropoffPoint(coords, {
label: label,
sublabel: 'Delivery Location',
draggable: false
})
}
async drawRoute(origin: { lng: number; lat: number }, destination: { lng: number; lat: number }) {
if (!this.controls) {
throw new Error('Map not initialized')
}
const route = await this.controls.setRoute({
origin: origin,
destination: destination,
options: {
profile: 'driving-traffic',
alternatives: false
}
})
return route
}
async trackVehicle(coords: { lng: number; lat: number }, label: string) {
if (!this.handles) {
throw new Error('Map not initialized')
}
const stream = await this.handles.peerLocation(coords, {
label: label,
sublabel: 'En Route',
icon: 'delivery-truck'
})
return stream
}
async simulateMovement(
start: { lng: number; lat: number },
end: { lng: number; lat: number },
durationMs: number = 30000
) {
const steps = 100
const interval = durationMs / steps
let currentStep = 0
const stream = await this.trackVehicle(start, 'Delivery Vehicle')
const timer = setInterval(() => {
currentStep++
const progress = currentStep / steps
const currentLng = start.lng + (end.lng - start.lng) * progress
const currentLat = start.lat + (end.lat - start.lat) * progress
stream.live(async (controls: any) => {
await controls.move({
position: { lng: currentLng, lat: currentLat }
})
})
if (currentStep >= steps) {
clearInterval(timer)
console.log('Vehicle arrived at destination')
}
}, interval)
return stream
}
}Tracking Module
10
Create Tracking Module
Set up src/tracking.ts
typescript
export class TrackingManager {
private statusContainer: HTMLElement | null
constructor() {
this.statusContainer = document.getElementById('status-container')
}
updateStatus(status: string, message: string, isActive: boolean = false) {
if (!this.statusContainer) return
const statusCard = document.createElement('div')
statusCard.className = 'status-card'
statusCard.innerHTML = `
<h3>
<span class="status-indicator ${isActive ? 'active' : ''}"></span>
${status}
</h3>
<p>${message}</p>
`
this.statusContainer.appendChild(statusCard)
// Show tracking section
const trackingSection = document.getElementById('tracking-section')
if (trackingSection) {
trackingSection.style.display = 'block'
}
}
clearStatus() {
if (this.statusContainer) {
this.statusContainer.innerHTML = ''
}
}
async simulateDeliveryFlow() {
this.clearStatus()
// Order created
this.updateStatus('Order Created', 'Your delivery order has been created', false)
await this.delay(2000)
// Driver assigned
this.updateStatus('Driver Assigned', 'A driver has been assigned to your delivery', false)
await this.delay(2000)
// Pickup
this.updateStatus('Picked Up', 'Package picked up from warehouse', false)
await this.delay(2000)
// In transit
this.updateStatus('In Transit', 'Package is on the way to you', true)
await this.delay(25000)
// Nearby
this.updateStatus('Nearby', 'Driver is approaching your location', true)
await this.delay(3000)
// Delivered
this.updateStatus('Delivered', 'Package delivered successfully!', false)
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
}Main Application
11
Create Main Application
Set up src/main.ts
typescript
import { AuthManager } from './auth'
import { MapManager } from './map'
import { TrackingManager } from './tracking'
class DeliveryTrackerApp {
private auth: AuthManager
private map: MapManager
private tracking: TrackingManager
constructor() {
this.auth = new AuthManager()
this.map = new MapManager()
this.tracking = new TrackingManager()
}
async initialize() {
console.log('Initializing Delivery Tracker...')
// Check authentication
const user = await this.auth.getCurrentUser()
if (user) {
console.log('Authenticated as:', user.profile.firstName)
}
// Initialize map
const mapInitialized = await this.map.initialize()
if (!mapInitialized) {
alert('Failed to initialize map. Please check your credentials.')
return
}
// Setup event listeners
this.setupEventListeners()
console.log('App ready!')
}
private setupEventListeners() {
const createDeliveryBtn = document.getElementById('create-delivery')
createDeliveryBtn?.addEventListener('click', async () => {
await this.createDelivery()
})
}
private async createDelivery() {
const pickupInput = document.getElementById('pickup-address') as HTMLInputElement
const deliveryInput = document.getElementById('delivery-address') as HTMLInputElement
const pickup = pickupInput.value
const delivery = deliveryInput.value
if (!pickup || !delivery) {
alert('Please enter both pickup and delivery addresses')
return
}
try {
// For demo purposes, use fixed coordinates
// In production, use geocoding to convert addresses to coordinates
const pickupCoords = { lng: -74.0060, lat: 40.7128 } // NYC
const deliveryCoords = { lng: -73.9855, lat: 40.7580 } // Times Square
// Set locations on map
await this.map.setPickupLocation(pickupCoords, pickup)
await this.map.setDeliveryLocation(deliveryCoords, delivery)
// Draw route
const route = await this.map.drawRoute(pickupCoords, deliveryCoords)
console.log('Route created:', route)
// Start vehicle simulation
await this.map.simulateMovement(pickupCoords, deliveryCoords, 30000)
// Update tracking status
await this.tracking.simulateDeliveryFlow()
} catch (error) {
console.error('Error creating delivery:', error)
alert('Failed to create delivery. Please try again.')
}
}
}
// Initialize app when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
const app = new DeliveryTrackerApp()
app.initialize()
})Update Package.json
12
Add Scripts
Update package.json with development scripts
json
{
"name": "delivery-tracker",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@de./sdk": "^latest"
},
"devDependencies": {
"vite": "^5.0.0",
"typescript": "^5.3.0",
"@types/node": "^20.0.0"
}
}Run Your App
13
Start Development Server
Launch your application
bash
npm run devOpen your browser to http://localhost:3000
What You Built
Core Features
- Interactive map with De. MSI
- Pickup and delivery location markers
- Traffic-aware route visualization
- Real-time vehicle tracking simulation
- Delivery status updates
Technologies Used
- De. SDK for map and tracking
- TypeScript for type safety
- Vite for fast development
- Modern ES modules
- Real-time simulations
Enhancements
Production Checklist
Before Deploying
Security:
- [ ] Move credentials to environment variables
- [ ] Enable HTTPS
- [ ] Implement proper authentication
- [ ] Add rate limiting
- [ ] Sanitize user inputs
Performance:
- [ ] Minify and bundle code
- [ ] Enable caching
- [ ] Optimize map loading
- [ ] Add loading states
- [ ] Implement error boundaries
Monitoring:
- [ ] Add error tracking (Sentry)
- [ ] Implement analytics
- [ ] Set up logging
- [ ] Monitor API usage
- [ ] Track performance metrics
Next Steps
Your Development Journey
First App Built
→
Add Features
→
Deploy to Production
Complete Source Code
The complete source code for this tutorial is available on GitHub:

