A full-featured e-commerce web application for a stationery store, built with Next.js, TypeScript, PostgreSQL, and Prisma.
The core functionality currently being developed and tracked in this project is the product review system. Users can leave a rating, title, and description for a product. When a review is created or updated, an event is also published to a Kafka topic, in addition to being persisted in PostgreSQL via Prisma.
This event-streaming part of the review flow is implemented using Kafka with Avro schemas registered in a Schema Registry, so that review events can later be consumed and written into a Cassandra database for analytics/streaming purposes.
This application acts as a Kafka producer only. The Kafka cluster itself (broker, schema registry, Kafka Connect, and the Cassandra sink connector) is set up and configured in a separate repository, using Docker Compose. The connection parameters used in this project (broker address, schema registry URL) are taken directly from that cluster setup.
const kafka = new Kafka({
clientId: 'my-producer-app',
brokers: ['localhost:9092']
});
export const registry = new SchemaRegistry({
host: 'http://localhost:8085'
});The Cassandra sink connector that reads from the Kafka topic and writes into the Cassandra table is also configured in that other repository and documented there.
Two Avro schemas are defined for review events — one for the message key, one for the value — and are registered in the Schema Registry at runtime, before the producer sends any messages.
lib/actions/kafka/schemas/review-schemas.ts:
export const reviewKeySchema = {
type: 'record',
name: 'ReviewKey',
namespace: 'com.product.reviews',
fields: [
{ name: 'productId', type: 'string' },
{ name: 'userId', type: 'string' }
]
};
export const reviewValueSchema = {
type: 'record',
name: 'ReviewValue',
namespace: 'com.product.reviews',
fields: [
{ name: 'rating', type: 'int' },
{ name: 'productId', type: 'string' },
{ name: 'title', type: 'string' },
{
name: 'description',
type: ['null', 'string'],
default: null
}
]
};When a user creates or updates a review **(createUpdateReview in lib/actions/review.actions.ts), the review is first saved to PostgreSQL. After that, a review event is sent to the product-reviews Kafka topic, encoded with the registered Avro schemas:
sendReviewMessage(
'product-reviews',
{
productId: review.productId,
userId: review.userId,
},
{
rating: review.rating,
productId: review.productId,
title: review.title,
description: review.description || null,
}
).catch((error) => {
console.error('Failed to send Kafka message:', error);
// Kafka failures don't block review creation
});The producer (lib/actions/kafka/services/producer.ts) connects lazily, registers both schemas with the Schema Registry on first use, and encodes each key/value pair before sending it to the topic.
Note: The Kafka cluster (broker, schema registry, Kafka Connect, and Cassandra sink connector) must be running for the producer to work. See the cluster setup repository for instructions on starting that infrastructure.
npm installIf you run into peer dependency errors:
npm install --legacy-peer-depsCrate .env and fill in the required values.
NEXT_PUBLIC_APP_NAME="Stationery Store"
NEXT_PUBLIC_APP_DESCRIPTION="A stationery e-commerce store built with Next.js"
NEXT_PUBLIC_SERVER_URL="http://localhost:3000"
DATABASE_URL=""
NEXTAUTH_SECRET=""
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_URL_INTERNAL="http://localhost:3000"Generate NEXTAUTH_SECRET with:
openssl rand -base64 32Payment-related environment variables are part of the original template but are not required to run or present this project. They can be left empty for the purposes of this demo.
Set up PostgreSQL and apply the Prisma schema:
npx prisma generate
npx prisma db push(Optional) Open Prisma Studio to inspect the data:
npx prisma studio(Optional) Seed the database with sample data:
npx tsx ./db/seedMake sure the Kafka cluster (broker, schema registry, Kafka Connect, Cassandra sink connector) from the companion infrastructure repository is up and running before testing the review feature end-to-end.
npm run devOpen http://localhost:3000 in your browser. Once the application is running and the database has been seeded, you can register a new user, browse the seeded products, and submit a review on any product page. This triggers sending the review event to the
product-reviewsKafka topic, from where the sink connector writes it into Cassandra.