Online Bookstore & Admin Dashboard

An end-to-end system covering product catalog, inventory management, order lifecycle, and administrative operations.

NestJSNextJSTypeScriptTailwindDrizzle
app-screenshoot

Scope & Constraints

Defined boundaries and non-negotiable requirements that shape the system design.

The system serves two primary user groups: customers who browse and purchase books, and administrators who manage products, inventory, and orders.

Engineering Decisions

Key technical choices made to balance security, maintainability, and real-world constraints.

Hybrid Authentication Strategy (Web & Mobile)

The system uses a hybrid authentication approach to accommodate different client environments. Web clients authenticate via secure, httpOnly cookies to minimize XSS risks and leverage automatic credential handling by the browser, while mobile clients use JWT-based authentication with tokens stored securely and sent through Authorization headers due to the lack of automatic cookie management in mobile environments.

Idempotency Key for Order & Payment Processes

To prevent duplicate order creation and the risk of double payments, write operations like order creation and payment initiation are designed to be idempotent using an idempotency key. Each order creation request includes a unique idempotency key generated on the client side. This approach protects the system from network retries, page refreshes, and duplicate submissions from users.

Validation at System Boundaries

All incoming requests are validated using Zod to ensure type safety and prevent invalid data from propagating into the domain layer.

API Rate Limiting for Abuse Prevention

Rate limiting is applied at the API layer to protect critical endpoints from abuse, brute-force attempts, and traffic spikes. This ensures system stability and fair resource usage, especially on authentication and order-related endpoints.

Server Actions for Data Mutations

Server Actions are used for form submissions and mutations to reduce API boilerplate, improve type safety, and ensure mutations execute securely on the server.

Hybrid Data Fetching Strategy

The frontend combines Server Component data fetching for initial renders with React Query on the client for interactive, frequently-updated data, balancing performance and user experience.

Order Flow

High-level visualization of how an order progresses through the system, including normal and cancellation paths.

Main Flow
PENDING
PAY (CUSTOMER)
PAID
SHIP (ADMIN)
DELIVERED
COMPLETE (CUSTOMER)
COMPLETED
CANCELLED
Cancellation Paths
PENDING
CANCEL (CUSTOMER)
CANCELLED
EXPIRED (SYSTEM)
CANCELLED
CANCEL (ADMIN)
CANCELLED

Order Status Transition

Explicit rules that define valid state changes across the order lifecycle.

Current StatusActionActorNext StatusNotes
PENDINGPAYCUSTOMERPAIDPayment confirmed via Midtrans webhook
PENDINGCONTINUE_PAYMENTCUSTOMERPENDINGReuse or regenerate Snap token
PENDINGCANCELCUSTOMERCANCELLEDUSER_CANCEL
PENDINGCANCELSYSTEMCANCELLEDPAYMENT_EXPIRED
PENDINGCANCELADMINCANCELLEDADMIN_CANCEL
PAIDSHIPADMINDELIVEREDManual admin fulfillment flow
DELIVEREDCOMPLETECUSTOMERCOMPLETEDCustomer confirms order received
PAIDCANCELN/A-Cancellation is not allowed for paid orders

Payment Status Mapping

Mapping between order lifecycle states and their corresponding payment states.

Order StatusPayment StatusNotes
PENDINGUNPAIDPayment initiated but not yet confirmed
PAIDPAIDConfirmed via Midtrans webhook
CANCELLEDEXPIREDPayment expired after 24 hours
CANCELLEDUNPAIDCancelled manually by customer or admin

Tech Stack

A curated set of technologies chosen to balance scalability, maintainability, and developer experience.

Frontend Platform

Next.js (App Router)

Next.js App Router provides a unified framework for routing, layouts, server rendering, and data mutations. It allows building SEO-friendly pages while keeping UI and data logic cohesive, reducing boilerplate and improving long-term maintainability.

Frontend Styling

Tailwind CSS

Tailwind CSS enables utility-first styling with centralized design tokens, allowing rapid UI iteration while maintaining visual consistency and avoiding the complexity of large custom CSS files.

Component Library

Shadcn/UI

Shadcn/UI builds on Radix primitives to provide accessible, composable components without locking the project into a rigid design system, offering flexibility and full control over styling.

Backend API Framework

NestJS

NestJS enforces a modular, domain-oriented architecture that scales well as the codebase grows. Its dependency injection and clear separation of concerns make the system easier to test, extend, and maintain.

Validation & Type Safety

Zod

Zod ensures runtime validation aligned with TypeScript types, reducing invalid data at system boundaries and making request, response, and domain validation explicit and reliable.

Database

MySQL

MySQL is a proven relational database well-suited for transactional workloads such as orders and inventory, providing strong consistency guarantees and predictable performance.

ORM / Query Layer

Drizzle ORM

Drizzle ORM offers a lightweight, type-safe SQL-first approach that keeps queries explicit while avoiding the overhead and hidden abstractions common in heavier ORMs.

Server State Management

React Query

React Query handles server-state caching, synchronization, and background refetching, reducing manual data-fetching logic and ensuring UI consistency with backend state.

Client UI State Management

Zustand

Zustand provides a minimal and predictable state management solution for local UI state, avoiding unnecessary complexity while keeping state logic easy to reason about.

What I’d Improve If This Were Production

Planned improvements and architectural enhancements for a real-world, large-scale deployment.