Skip to content

dave1725/xeno-frontend

Repository files navigation

Xeno Analytics

Multi-tenant ecommerce analytics dashboard with Email authentication by Google sign-in, Prisma/MySQL to store ingested data from shopify, and a polished App Router UI for a powerful dashboard.

Next.js React Prisma MySQL Railway Vercel NextAuth.js Tailwind CSS Recharts

Banner

Features

  • Google OAuth sign-in (JWT sessions)
  • Protected dashboard and APIs (NextAuth session checks)
  • Key metrics: revenue, orders, customers, inventory (with low/out-of-stock)
  • Trends with WoW/MoM deltas, returning customer rate
  • Inventory table with quick filters and search
  • Clean, responsive UI with micro sparklines

Dashboard

Dashboard

Getting Started

Prerequisites

  • Node.js 18+
  • MySQL database (e.g., Railway) and DATABASE_URL
  • Google OAuth client (Client ID and Secret)

1) Install

npm install

2) Environment

Create .env from .env.example (or set via your hosting provider):

DATABASE_URL="mysql://user:pass@host:port/db"
TENANT_SHOP="your-shop.myshopify.com"

NEXTAUTH_SECRET="generate-a-strong-secret"
NEXTAUTH_URL="http://localhost:3000"

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

Google Console (OAuth):

  • Authorized redirect URI (dev): http://localhost:3000/api/auth/callback/google
  • Authorized JavaScript origin (dev): http://localhost:3000

3) Run

npm run dev

Open http://localhost:3000 and click “Continue with Google”.

Deployment

  • Set NEXTAUTH_URL to your production origin, e.g. https://your-domain.com
  • Add production redirect URI: https://your-domain.com/api/auth/callback/google
  • Configure all env vars in your hosting provider (Vercel/Railway/etc.)

API Endpoints

All metrics routes are protected—require a valid NextAuth session.

  • GET /api/metrics?start=YYYY-MM-DD&end=YYYY-MM-DD&shop=<shop>
    • Returns totals (orders, revenue, products, customers), series, trends, insights, and low-stock counts.
  • GET /api/metrics/products?shop=<shop>
    • Returns { id, title, inventory, threshold, lowStock, outOfStock }[] for the tenant.
  • GET /api/metrics/tenants
    • Returns tenant list for selector.

Auth endpoints (NextAuth):

  • GET/POST /api/auth/* via app/api/auth/[...nextauth]/route.js

Database Schema (Prisma)

Core models (simplified):

model Tenant {
	id        String   @id @default(uuid())
	name      String
	shop      String   @unique
	createdAt DateTime @default(now())
	customers Customer[]
	orders    Order[]
	products  Product[]
	events    Event[]
}

model Product {
	id                String   @id @default(uuid())
	shopifyId         String   @unique
	title             String
	price             Float
	inventory         Int      @default(0)
	lowStockThreshold Int      @default(10)
	tenantId          String
	tenant            Tenant   @relation(fields: [tenantId], references: [id])
}

model Order {
	id         String   @id @default(uuid())
	shopifyId  String   @unique
	totalPrice Float
	createdAt  DateTime @default(now())
	tenantId   String
	tenant     Tenant   @relation(fields: [tenantId], references: [id])
	customerId String?
	customer   Customer? @relation(fields: [customerId], references: [id])

	@@map("orders")
}

model Event {
	id        String   @id @default(uuid())
	type      String
	createdAt DateTime @default(now())
	tenantId  String
	tenant    Tenant   @relation(fields: [tenantId], references: [id])
	@@index([type, tenantId])
	@@index([createdAt, tenantId])
}

Note: The repo also includes standard NextAuth models (User, Account, Session, VerificationToken) which enable database sessions if we plan to switch from JWT sessions later.

Tech Stack

  • Next.js (App Router), React 19
  • NextAuth (Google OAuth, JWT sessions)
  • Prisma ORM + MySQL (Railway)
  • Tailwind CSS 4
  • Recharts

Known Limitations / Assumptions

  • Preview deploys: Google OAuth requires exact redirect URIs; previews may need a separate OAuth client or be disabled for login.
  • Multi-tenant selection expects existing tenants in DB.
  • Inventory thresholds default to 10 when missing.
  • Returning rate and some trends require enough historical data.
  • Cart and Checkout Abandonment caveats:
    • Many stores don’t emit explicit cart_abandoned or checkout_abandoned events. When missing, we use a heuristic: cart_abandoned ≈ checkout_started − orders in the selected window.
    • Checkout abandonment uses checkout_abandoned when present; otherwise it falls back to the computed cart_abandoned value. Rates are clamped to [0, 1].
    • The denominator for cart-to-checkout uses distinct carts inferred from cart_updated events (deduped by shopifyId). If shopifyId is missing/unstable or if bots cause noisy cart_updated traffic, the rate can be biased.
    • These are proxies; for production-grade accuracy, instrument explicit checkout/cart lifecycle events (or webhook-based signals) with stable identifiers and consistent firing semantics.

Author

Built by Dave Meshak J | Portfolio

License

GNU General Public License. See LICENSE for more details.

About

A multi-tenant Shopify Data Ingestion & Insights Service

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published