ποΈ System Architecture
Frontend
Next.js
Kepler.gl (Modified)
React + TypeScript
MapLibre GL
Backend
NestJS
Tippecanoe (Async)
Data Processing
Authentication
Storage
PostgreSQL (Metadata)
AWS S3 (Data/Tiles)
AWS SQS (Queue)
Redis (Cache)
β‘ Key Features
π Multi-Project
Create unlimited projects with separate map configurations and data
π Role-Based Access
RBAC per project - admin, editor, viewer roles
π Auto Tile Generation
JSON upload β automatic Tippecanoe conversion β MVT tiles
π Modified Kepler.gl
Save projects to database (original only loads in browser)
β‘ Async Processing
SQS queue handles large data without blocking UI
πΊοΈ Vector Tiles (MVT)
Optimized for fast rendering of large datasets
π Data Upload Workflow
Upload
JSON/GeoJSON file
Validate
Check format
Queue
SQS message
Process
Tippecanoe
Store
S3 + DB
Ready
MVT tiles
π¦ Data Storage Structure (S3)
# S3 Bucket Structure
s3://geospatial-viewer-data/
βββ projects/
β βββ {project_id}/
β β βββ raw/
β β β βββ data_001.geojson
β β β βββ data_002.json
β β βββ tiles/
β β β βββ data_001/{z}/{x}/{y}.mvt
β β β βββ data_002/{z}/{x}/{y}.mvt
β β βββ metadata.json
β βββ ...
βββ temp/
βββ (processing queue files)
ποΈ Database Schema (PostgreSQL)
-- Projects Table
CREATE TABLE projects (
id UUID PRIMARY KEY,
name VARCHAR(255),
config JSONB, -- Kepler.gl config
owner_id UUID,
created_at TIMESTAMP
);
-- Project Members (RBAC)
CREATE TABLE project_members (
project_id UUID,
user_id UUID,
role VARCHAR(20), -- admin/editor/viewer
PRIMARY KEY (project_id, user_id)
);
-- Data Layers
CREATE TABLE data_layers (
id UUID PRIMARY KEY,
project_id UUID,
name VARCHAR(255),
s3_raw_path VARCHAR(500),
s3_tiles_path VARCHAR(500),
status VARCHAR(20), -- pending/processing/ready
created_at TIMESTAMP
);
π¬ Modified Kepler.gl Integration
β Original Kepler.gl
- Data loads in browser only
- No persistence between sessions
- Manual export/import required
- Limited to browser memory
β Modified Version
- Auto-save projects to database
- Server-side data conversion
- Multi-user collaboration
- Handles GB+ datasets
- Role-based access control
βοΈ Backend Processing (NestJS + SQS)
// NestJS Queue Processor for Tile Generation
@Processor('tile-generation')
export class TileGenerationProcessor {
@Process()
async handleTileGeneration(job: Job<TileJobDto>) {
const { layerId, s3RawPath, projectId } = job.data;
// 1. Download from S3
const rawData = await this.s3Service.download(s3RawPath);
// 2. Run Tippecanoe (async)
const tilesPath = await this.tippecanoeService.convert(rawData, {
maxZoom: 14,
minZoom: 0,
layerName: layerId
});
// 3. Upload tiles to S3
await this.s3Service.uploadTiles(tilesPath, projectId, layerId);
// 4. Update database status
await this.dataLayerService.updateStatus(layerId, 'ready');
}
}