Prerequisites

Before setting up the development environment, ensure you have the following installed:

Node.js

Version 18.0 or higher Download Node.js

pnpm

Version 8.0 or higher

npm install -g pnpm

PostgreSQL

Version 14.0 or higher Download PostgreSQL

Redis

Version 6.0 or higher Download Redis

Project Structure

The SG Cars Trends backend is organized as a monorepo with the following structure:

backend/
├── apps/
│   └── api/                    # Main API application
│       ├── src/
│       │   ├── config/         # Configuration files
│       │   ├── db/             # Database schema
│       │   ├── lib/            # Utility functions and workflows
│       │   ├── queries/        # Database queries
│       │   ├── routes/         # API routes
│       │   ├── schemas/        # Validation schemas
│       │   ├── types/          # Type definitions
│       │   ├── utils/          # Utility functions
│       │   └── v1/             # API version 1 routes
│       ├── migrations/         # Database migrations
│       └── sst.config.ts       # SST configuration
├── packages/
│   ├── schema/                 # Shared database schema
│   ├── types/                  # Shared TypeScript types
│   └── utils/                  # Shared utility functions
├── docs/                       # Documentation (this site)
└── mint.json                   # Mintlify configuration

Environment Setup

1. Clone the Repository

git clone https://github.com/sgcarstrends/backend.git
cd backend

2. Install Dependencies

pnpm install

3. Environment Variables

Create a .env.local file in the root directory with the following variables:

# Database Configuration
DATABASE_URL="postgresql://username:password@localhost:5432/sgcarstrends"

# Redis Configuration
UPSTASH_REDIS_REST_URL="redis://localhost:6379"
UPSTASH_REDIS_REST_TOKEN="your_redis_token"

# API Configuration
SG_CARS_TRENDS_API_TOKEN="your_api_token_here"
UPDATER_API_TOKEN="your_updater_token_here"

# LTA DataMall API
LTA_DATAMALL_API_KEY="your_lta_datamall_api_key"

# QStash Configuration (for workflows)
QSTASH_URL="https://qstash.upstash.io"
QSTASH_TOKEN="your_qstash_token"

# Social Media API Keys (optional for development)
LINKEDIN_ACCESS_TOKEN="your_linkedin_token"
TWITTER_BEARER_TOKEN="your_twitter_token"
DISCORD_WEBHOOK_URL="your_discord_webhook"
TELEGRAM_BOT_TOKEN="your_telegram_token"
TELEGRAM_CHAT_ID="your_telegram_chat_id"

Most environment variables are optional for basic development. The API will work with just the database and Redis configuration.

4. Database Setup

Local PostgreSQL

# Connect to PostgreSQL
psql -U postgres

# Create database
CREATE DATABASE sgcarstrends;

# Create user (optional)
CREATE USER sgcarstrends WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE sgcarstrends TO sgcarstrends;

# Exit PostgreSQL
\q

Run Migrations

pnpm migrate

Verify Database Setup

pnpm migrate:check

5. Redis Setup

Local Redis

brew install redis
brew services start redis

Verify Redis Connection

redis-cli ping
# Should return: PONG

Development Workflow

1. Start Development Server

pnpm dev

This will start the development server using SST dev mode on http://localhost:3000.

2. Available Scripts

ScriptDescription
pnpm devStart development server
pnpm buildBuild for production
pnpm testRun all tests
pnpm test:watchRun tests in watch mode
pnpm test:coverageRun tests with coverage
pnpm lintRun linting
pnpm migrateRun database migrations
pnpm migrate:checkCheck migration status

3. Development URLs

Once the development server is running, you can access:

  • API: http://localhost:3000
  • Health Check: http://localhost:3000/health
  • API Documentation: http://localhost:3000/docs
  • OpenAPI Schema: http://localhost:3000/docs/openapi.json

Testing

Running Tests

pnpm test

Test Structure

Tests are organized alongside the source code:

src/
├── utils/
│   ├── slugify.ts
│   └── __tests__/
│       └── slugify.test.ts
└── lib/
    ├── getLatestMonth.ts
    └── __tests__/
        └── getLatestMonth.test.ts

Writing Tests

import { describe, it, expect } from 'vitest';
import { slugify } from '../slugify';

describe('slugify', () => {
  it('should convert string to slug', () => {
    expect(slugify('Hello World')).toBe('hello-world');
  });

  it('should handle special characters', () => {
    expect(slugify('Hello, World!')).toBe('hello-world');
  });

  it('should handle empty string', () => {
    expect(slugify('')).toBe('');
  });
});

Code Quality

Linting

The project uses Biome for linting and formatting:

pnpm lint

Configuration

Biome configuration is in biome.json:

{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": ["node_modules/**", ".sst/**", "dist/**"]
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

Database Operations

Migrations

# Modify schema in packages/schema/src/index.ts
# Then generate migration
pnpm migrate

Schema Changes

Database schema is managed with Drizzle ORM:

// packages/schema/src/index.ts
import { pgTable, text, integer, timestamp } from 'drizzle-orm/pg-core';

export const cars = pgTable('cars', {
  id: integer('id').primaryKey().generatedAlwaysAsIdentity(),
  month: text('month').notNull(),
  make: text('make').notNull(),
  fuelType: text('fuel_type').notNull(),
  vehicleType: text('vehicle_type').notNull(),
  number: integer('number').notNull(),
  createdAt: timestamp('created_at').defaultNow(),
  updatedAt: timestamp('updated_at').defaultNow(),
});

API Testing

Manual Testing

curl http://localhost:3000/health

API Documentation

The API documentation is available at http://localhost:3000/docs when running locally.

Troubleshooting

Common Issues

Debug Mode

Enable debug logging:

export DEBUG=sgcarstrends:*
pnpm dev

IDE Configuration

VS Code

Recommended extensions:

  • Biome: For linting and formatting
  • TypeScript: For type checking
  • PostgreSQL: For database management
  • Rest Client: For API testing

Settings

{
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },
  "typescript.preferences.includePackageJsonAutoImports": "auto"
}

Docker Setup (Optional)

For containerized development:

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

Next Steps

Prerequisites

Before setting up the development environment, ensure you have the following installed:

Node.js

Version 18.0 or higher Download Node.js

pnpm

Version 8.0 or higher

npm install -g pnpm

PostgreSQL

Version 14.0 or higher Download PostgreSQL

Redis

Version 6.0 or higher Download Redis

Project Structure

The SG Cars Trends backend is organized as a monorepo with the following structure:

backend/
├── apps/
│   └── api/                    # Main API application
│       ├── src/
│       │   ├── config/         # Configuration files
│       │   ├── db/             # Database schema
│       │   ├── lib/            # Utility functions and workflows
│       │   ├── queries/        # Database queries
│       │   ├── routes/         # API routes
│       │   ├── schemas/        # Validation schemas
│       │   ├── types/          # Type definitions
│       │   ├── utils/          # Utility functions
│       │   └── v1/             # API version 1 routes
│       ├── migrations/         # Database migrations
│       └── sst.config.ts       # SST configuration
├── packages/
│   ├── schema/                 # Shared database schema
│   ├── types/                  # Shared TypeScript types
│   └── utils/                  # Shared utility functions
├── docs/                       # Documentation (this site)
└── mint.json                   # Mintlify configuration

Environment Setup

1. Clone the Repository

git clone https://github.com/sgcarstrends/backend.git
cd backend

2. Install Dependencies

pnpm install

3. Environment Variables

Create a .env.local file in the root directory with the following variables:

# Database Configuration
DATABASE_URL="postgresql://username:password@localhost:5432/sgcarstrends"

# Redis Configuration
UPSTASH_REDIS_REST_URL="redis://localhost:6379"
UPSTASH_REDIS_REST_TOKEN="your_redis_token"

# API Configuration
SG_CARS_TRENDS_API_TOKEN="your_api_token_here"
UPDATER_API_TOKEN="your_updater_token_here"

# LTA DataMall API
LTA_DATAMALL_API_KEY="your_lta_datamall_api_key"

# QStash Configuration (for workflows)
QSTASH_URL="https://qstash.upstash.io"
QSTASH_TOKEN="your_qstash_token"

# Social Media API Keys (optional for development)
LINKEDIN_ACCESS_TOKEN="your_linkedin_token"
TWITTER_BEARER_TOKEN="your_twitter_token"
DISCORD_WEBHOOK_URL="your_discord_webhook"
TELEGRAM_BOT_TOKEN="your_telegram_token"
TELEGRAM_CHAT_ID="your_telegram_chat_id"

Most environment variables are optional for basic development. The API will work with just the database and Redis configuration.

4. Database Setup

Local PostgreSQL

# Connect to PostgreSQL
psql -U postgres

# Create database
CREATE DATABASE sgcarstrends;

# Create user (optional)
CREATE USER sgcarstrends WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE sgcarstrends TO sgcarstrends;

# Exit PostgreSQL
\q

Run Migrations

pnpm migrate

Verify Database Setup

pnpm migrate:check

5. Redis Setup

Local Redis

brew install redis
brew services start redis

Verify Redis Connection

redis-cli ping
# Should return: PONG

Development Workflow

1. Start Development Server

pnpm dev

This will start the development server using SST dev mode on http://localhost:3000.

2. Available Scripts

ScriptDescription
pnpm devStart development server
pnpm buildBuild for production
pnpm testRun all tests
pnpm test:watchRun tests in watch mode
pnpm test:coverageRun tests with coverage
pnpm lintRun linting
pnpm migrateRun database migrations
pnpm migrate:checkCheck migration status

3. Development URLs

Once the development server is running, you can access:

  • API: http://localhost:3000
  • Health Check: http://localhost:3000/health
  • API Documentation: http://localhost:3000/docs
  • OpenAPI Schema: http://localhost:3000/docs/openapi.json

Testing

Running Tests

pnpm test

Test Structure

Tests are organized alongside the source code:

src/
├── utils/
│   ├── slugify.ts
│   └── __tests__/
│       └── slugify.test.ts
└── lib/
    ├── getLatestMonth.ts
    └── __tests__/
        └── getLatestMonth.test.ts

Writing Tests

import { describe, it, expect } from 'vitest';
import { slugify } from '../slugify';

describe('slugify', () => {
  it('should convert string to slug', () => {
    expect(slugify('Hello World')).toBe('hello-world');
  });

  it('should handle special characters', () => {
    expect(slugify('Hello, World!')).toBe('hello-world');
  });

  it('should handle empty string', () => {
    expect(slugify('')).toBe('');
  });
});

Code Quality

Linting

The project uses Biome for linting and formatting:

pnpm lint

Configuration

Biome configuration is in biome.json:

{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": ["node_modules/**", ".sst/**", "dist/**"]
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

Database Operations

Migrations

# Modify schema in packages/schema/src/index.ts
# Then generate migration
pnpm migrate

Schema Changes

Database schema is managed with Drizzle ORM:

// packages/schema/src/index.ts
import { pgTable, text, integer, timestamp } from 'drizzle-orm/pg-core';

export const cars = pgTable('cars', {
  id: integer('id').primaryKey().generatedAlwaysAsIdentity(),
  month: text('month').notNull(),
  make: text('make').notNull(),
  fuelType: text('fuel_type').notNull(),
  vehicleType: text('vehicle_type').notNull(),
  number: integer('number').notNull(),
  createdAt: timestamp('created_at').defaultNow(),
  updatedAt: timestamp('updated_at').defaultNow(),
});

API Testing

Manual Testing

curl http://localhost:3000/health

API Documentation

The API documentation is available at http://localhost:3000/docs when running locally.

Troubleshooting

Common Issues

Debug Mode

Enable debug logging:

export DEBUG=sgcarstrends:*
pnpm dev

IDE Configuration

VS Code

Recommended extensions:

  • Biome: For linting and formatting
  • TypeScript: For type checking
  • PostgreSQL: For database management
  • Rest Client: For API testing

Settings

{
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },
  "typescript.preferences.includePackageJsonAutoImports": "auto"
}

Docker Setup (Optional)

For containerized development:

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

Next Steps