Database Schema
This document describes the PostgreSQL database schema used by the SG Cars Trends platform, including table structures, relationships, and indexing strategies.Entity Relationship Diagram
Table Specifications
Cars Table
Purpose: Stores monthly vehicle registration data from LTA DataMall Table Definition:id
: UUID primary key (auto-generated)month
: Registration month in YYYY-MM format (e.g., “2024-01”)make
: Vehicle manufacturer name (e.g., “TOYOTA”, “BMW”)importer_type
: Registration type classificationfuel_type
: Fuel type (“Petrol”, “Diesel”, “Electric”, “Hybrid”)vehicle_type
: Vehicle category (“Cars”, “Motor cycles”, “Buses”, etc.)number
: Number of registrations for the specific combination
- Monthly registration summaries by make
- Fuel type distribution analysis
- Vehicle type breakdowns
- Historical trend analysis
COE Bidding Results Table
Purpose: Stores Certificate of Entitlement bidding exercise results Table Definition:id
: UUID primary keymonth
: Bidding month (YYYY-MM format)bidding_no
: Bidding exercise number (1 or 2 per month)vehicle_class
: COE category classificationquota
: Number of certificates availablebids_success
: Number of successful bidsbids_received
: Total number of bids submittedpremium
: Winning premium amount in SGD
- Latest bidding results by category
- Premium trend analysis
- Bidding success rate calculations
- Historical premium comparisons
COE Prevailing Quota Premium Table
Purpose: Stores monthly PQP rates for immediate vehicle registration Table Definition:id
: UUID primary keymonth
: Month in YYYY-MM formatvehicle_class
: COE categorypqp
: Prevailing Quota Premium rate in SGD
Blog Posts Table
Purpose: Stores LLM-generated blog content with comprehensive metadata Table Definition:id
: UUID primary keytitle
: Blog post titleslug
: URL-friendly identifier (unique)content
: Markdown-formatted blog contentmetadata
: JSON blob containing tags, reading time, data source info, etc.published_at
: Publication timestamp (NULL for drafts)created_at
: Creation timestampmodified_at
: Last modification timestamp
- Published posts ordered by date
- Posts filtered by tags
- Posts by data month or type
- Blog post analytics
Analytics Table
Purpose: Tracks page views and visitor metrics for performance monitoring Table Definition:id
: Auto-incrementing primary keydate
: Event timestamp with timezonepathname
: Page URL path being accessedreferrer
: Referring URL (if available)country
: Visitor country (from geolocation)flag
: Country flag emojicity
: Visitor citylatitude
: Geographic latitudelongitude
: Geographic longitude
- Page view counts by pathname
- Geographic visitor distribution
- Referrer analysis
- Traffic trends over time
Indexing Strategy
Performance Optimization
Composite Indexes: Created for common multi-column queries(month, make)
: Cars filtered by month and manufacturer(month, vehicle_class)
: COE data by month and category(month, bidding_no, vehicle_class)
: Complex COE queries
- Date/month columns for temporal queries
- Category columns for grouping operations
- Numeric columns for range queries and sorting
Index Maintenance
Automatic Maintenance: PostgreSQL automatically maintains indexes Query Analysis: UseEXPLAIN ANALYZE
to verify index usage
Performance Monitoring: Monitor slow queries and add indexes as needed
Data Relationships
Conceptual Relationships
While the schema doesn’t use foreign key constraints, there are logical relationships: Posts → Cars/COE Data: Blog posts are generated from specific month’s dataposts.metadata.data_month
relates tocars.month
orcoe.month
posts.metadata.data_type
indicates source table (“cars” or “coe”)
- Both tables share
month
andvehicle_class
fields - PQP rates complement bidding results for complete COE picture
Data Integrity
Unique Constraints: Blog post slugs must be unique NOT NULL Constraints: Essential fields are required Application-Level Validation: Business logic enforces data consistencyMigration Management
Drizzle ORM Integration
Schema Definition: Tables defined using Drizzle ORM TypeScript schema Migration Generation:pnpm generate
creates SQL migration files
Migration Execution: pnpm migrate
applies pending migrations
Migration Workflow: