Get posts
GET api/v1/post?city = ?&category = ?
response {List of links of post}
Get a particular posts
GET api/v1/post/{post ID}
response {post metadata}
Create a new post
POST api/v1/post/new
response {post iD , post link}
Delete/Edit a post
DELETE/PUT api/v1/post/{postID}
There will be three main components to this.
Post Service : This service will be responsible for creating new post, updating a post, deleting a post. This talks to a database which store the metadata of the post details, it writes to DB if there is any new post is created or existing one is updated.
Search Service : This service is responsible for searching posts from the application. This uses elastic search for full text search, fuzzy search.
Post Detail Service : This service is responsible for returning all the metadata for a particular post. This service talks to Post DB to fetch metadata for a post and also fetches
For Post Metadata:
Relational DB (Postgres/MySQL) is good because:
Search is offloaded to Elasticsearch.
So:
Post DB = relational (source of truth)
Search DB = Elasticsearch
Cache = Redis
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255) UNIQUE,
phone VARCHAR(20),
created_at TIMESTAMP,
updated_at TIMESTAMP
);
Indexes:
email unique indexCraigslist is category-driven.
CREATE TABLE categories (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
parent_id BIGINT NULL,
created_at TIMESTAMP
);
CREATE TABLE posts (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
category_id BIGINT NOT NULL,
title VARCHAR(255),
description TEXT,
price DECIMAL(10,2),
currency VARCHAR(10),
location_city VARCHAR(100),
location_state VARCHAR(100),
latitude DOUBLE,
longitude DOUBLE,
status VARCHAR(20), -- ACTIVE, SOLD, DELETED
created_at TIMESTAMP,
updated_at TIMESTAMP,
expires_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (category_id) REFERENCES categories(id)
);
Primary key handles this.
CREATE INDEX idx_posts_user ON posts(user_id);
CREATE INDEX idx_posts_category ON posts(category_id);
If simple:
CREATE INDEX idx_posts_city ON posts(location_city);
If geo-based:
Use spatial index (Postgres example):
CREATE INDEX idx_posts_location ON posts USING GIST (geography(point(latitude, longitude)));
Important:
CREATE INDEX idx_posts_status ON posts(status);
Often combined:
CREATE INDEX idx_posts_category_status
ON posts(category_id, status, created_at DESC);
All traffic first hits API Gateway.
Responsibilities:
You’ve separated:
That’s good. In production:
After gateway:
API Gateway → Load Balancer → Services
The LB distributes traffic to:
This ensures:
This is the write path.
Flow:
Client
→ API Gateway
→ Load Balancer
→ Post Service
You correctly separated:
Never store images in the DB.
Blob Storage → CDN → Client
Flow when viewing a post:
Client → CDN → Blob Storage (if cache miss)
This handles:
GET /post/{id}
Flow:
Client
→ API Gateway
→ LB
→ Post Detail Service
→ Redis Cache
→ Post DB
Because:
Typical pattern:
post = redis.get(postId)
if null:
post = db.get(postId)
redis.set(postId, post, TTL)
Cache-aside pattern.
This is very important for Craigslist.
Flow:
Client → Search Service → Elasticsearch DB
You have Redis next to Search Service.
Possible uses:
Example:
search?q=iphone&location=delhi
If 10k people search it:
Separated:
Benefits:
This follows CQRS-style.
Post Service→ Message Queue (Kafka)→ Search Indexer→Elasticsearch
Without this:
Search will become stale.
Horizontal scaling:
These can be: