Skip to content

NitinMoturu72/FoodTrack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

FoodTrack — Food Truck Analytics Platform

ASU SER517 Capstone Project · Group 7 · Fall 2025

A full-stack financial analytics and management platform for food truck operators — tracking purchases, sales, inventory, and menu items, with real-time reporting and secure file storage.

Note: This repository contains documentation and architecture only. The source code is maintained in a private organizational repository.


What It Does

FoodTrack gives food truck operators a single platform to manage their business finances. Operators can log purchases and sales, track ingredient inventory with automatic FIFO depletion, manage menu item compositions, upload receipts to cloud storage, and generate P&L and financial reports — all behind a secure JWT-authenticated API.


My Contributions (Backend & Database)

The frontend UI was inherited from a previous team. Our team (Group 7) designed and implemented the entire backend from scratch:

  • Designed the full relational database schema (10 tables, 7 migrations through November 2025)
  • Implemented the 3-layer Controller → Service → Prisma architecture
  • Built the complete purchases module: CRUD, batch CSV upload, inventory sync
  • Built the complete sales module: CRUD, batch upload, FIFO inventory deduction on sync
  • Built the inventory module: CRUD, batch tracking, FIFO depletion, low-stock alerts
  • Built the menu module: CRUD with ingredient composition via the Uses junction table
  • Implemented JWT authentication: signup/login, 60-min access tokens, 7-day refresh tokens, OTP forgot-password via email
  • Integrated AWS S3 for file upload, retrieval, rename, and delete
  • Built all reports endpoints: Financial Report, P&L, Inventory Report, Sales Analytics
  • Created the deployment plan (PM2, environment configuration, infrastructure documentation)

Tech Stack

Layer Technologies
Frontend Next.js 15 + TypeScript, Tailwind CSS, Redux Toolkit, Recharts, Framer Motion
Backend Node.js + Express 4 + TypeScript
ORM Prisma 6
Database PostgreSQL (10 tables, 7 migrations)
Cloud Storage AWS S3 (foodtruck-userfiles, ca-central-1)
Email Nodemailer via Gmail SMTP
Process Management PM2
Auth JWT (access + refresh tokens), bcrypt

Database Schema

The schema is user-scoped throughout — every table uses Email as part of its composite primary key, so all data is naturally partitioned per user with no risk of cross-user data leakage.

┌─────────────────────────────────────────────────────────────────────────────────┐
│  USER (PK: Email)                                                               │
│  Email · Password · BusinessName · Province · LastSaleSync · LastPurchaseSync  │
└──────────────┬──────────────────────────────────────────────────────────────────┘
               │ (cascade delete on all child tables)
       ┌───────┼────────────────────────────────────────┐
       │       │                │            │           │
       ▼       ▼                ▼            ▼           ▼
┌──────────┐ ┌────────────┐ ┌──────────┐ ┌──────┐  ┌──────────┐
│PURCHASE  │ │ INGREDIENT │ │ MENUITEM │ │ SALE │  │OTHERCOST │
│PK: Email │ │PK: Email   │ │PK: Email │ │PK:   │  │PK: Email │
│+DateTime │ │   +Name    │ │   +Name  │ │Email │  │+CostDate │
│+Location │ │Amount      │ │Cost      │ │+Start│  │+CostName │
│Cost      │ │AmountUnits │ │          │ │+End  │  │CostCat.  │
└────┬─────┘ │EstimatedAmt│ └────┬─────┘ │Rev.  │  │Cost      │
     │       └──────┬─────┘      │       │Hours │  └──────────┘
     │              │            │       │Loc.  │
     ▼              ▼            │       │Wthr. │
┌──────────┐ ┌──────────────┐   │       └──┬───┘
│INCLUDES  │ │INGREDIENTBATCH│  │          │
│(line item)│ │PK: Email     │  │          ▼
│PK: Email │ │+IngName      │  │       ┌──────┐
│+DateTime │ │+BatchId      │  │       │ SOLD │
│+Location │ │PurchaseDate  │  │       │PK:   │
│+IngName  │ │PurchaseLoc.  │  │       │Email │
│Price     │ │PurchasedAmt  │  │       │+Start│
│Amount    │ │PricePerUnit  │  │       │+End  │
│Units     │ │RemainingAmt  │  │       │+Menu │
└──────────┘ │AmountUnits   │  │       │Count │
             │EstimatedAmt  │  │       └──────┘
             └──────────────┘  │
                               ▼
                         ┌──────────┐
                         │   USES   │
                         │PK: Email │
                         │+Menu     │
                         │+Ingred.  │
                         │Amount    │
                         │Price     │
                         │Units     │
                         └──────────┘
┌──────────────────────┐
│ CODE (OTP)           │
│ PK: Email (1-to-1)   │
│ Code · ExpireAt      │
│ Used (bool)          │
└──────────────────────┘

Key Design Decisions

  • Email as primary identifier throughout — no surrogate user ID. Every composite PK includes Email, so all rows are naturally user-scoped.
  • FIFO inventory via IngredientBatch — each purchase creates a batch with RemainingAmount. Sales sync depletes the oldest batch first until the quantity is satisfied.
  • Incremental sync with LastSaleSyncSold.CreatedAt timestamps drive sync; only items sold after LastSaleSync get deducted from inventory, preventing double-depletion on repeated syncs.
  • OTP is 1-to-1 with User via upsert — each forgot-password request overwrites the previous code, eliminating stale token accumulation.
  • Cascade deletes — deleting a user removes all their data atomically across all 10 tables.

Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                          CLIENT BROWSER                                     │
│                    Next.js 15 + Redux + RTK Query                           │
│                                                                             │
│  ┌──────────┐  ┌──────────┐  ┌───────────┐  ┌────────┐  ┌──────────────┐  │
│  │ Landing  │  │  Login / │  │ Dashboard │  │ Redux  │  │ tokenAuth.tsx│  │
│  │   Page   │  │  Signup  │  │  Pages    │  │ Store  │  │ (auto-refresh│  │
│  └──────────┘  └────┬─────┘  └─────┬─────┘  └───┬────┘  │  @ 55 min)  │  │
└─────────────────────┼──────────────┼─────────────┼────────┴─────────────────┘
                      │    HTTP + Bearer Token (JWT)
                      ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                     EXPRESS SERVER  (port 3001)                             │
│                                                                             │
│  ┌──────────────────────────────────────────────┐                          │
│  │           MIDDLEWARE LAYER                   │                          │
│  │  Helmet · Morgan · CORS · body-parser        │                          │
│  │  authenticateToken (JWT verify on all        │                          │
│  │  routes except /auth/*)                      │                          │
│  └──────────────────┬───────────────────────────┘                          │
│                     │                                                       │
│  ┌──────────────────▼───────────────────────────┐                          │
│  │            CONTROLLER LAYER                  │                          │
│  │  /auth  /purchases  /sales  /inventory       │                          │
│  │  /menu  /dashboard  /files  /delete          │                          │
│  └──────────────────┬───────────────────────────┘                          │
│                     │                                                       │
│  ┌──────────────────▼───────────────────────────┐                          │
│  │             SERVICE LAYER                    │                          │
│  │  authService · purchaseService · salesSvc    │                          │
│  │  inventoryService · menuService              │                          │
│  │  reportsService · fileService · emailSvc     │                          │
│  └──────┬───────────┬─────────────┬─────────────┘                          │
└─────────┼───────────┼─────────────┼─────────────────────────────────────────┘
          │           │             │
          ▼           ▼             ▼
┌──────────────┐  ┌────────────┐  ┌──────────────────┐
│  PostgreSQL  │  │  AWS S3    │  │  Gmail SMTP       │
│  (Prisma 6)  │  │ ca-central │  │  Nodemailer       │
│  10 tables   │  │    -1      │  │  Welcome email    │
│  7 migrations│  │            │  │  OTP reset        │
└──────────────┘  └────────────┘  └──────────────────┘

JWT Auth Flow

  CLIENT                          SERVER                        DB
    │                               │                           │
    │──── POST /auth/login ────────▶│                           │
    │     { email, password }        │──── bcrypt.compare ──────▶│
    │                               │◀─── User row ─────────────│
    │◀─── { accessToken (60min),    │                           │
    │       refreshToken (7days) }──│                           │
    │                               │                           │
    │──── GET /any-route ──────────▶│                           │
    │     Authorization: Bearer <AT>│── jwt.verify(AT) ─────────│
    │◀─── 200 + data ───────────────│   req.user = { email }    │
    │                               │                           │
    │  [tokenAuth.tsx fires @ 55min]│                           │
    │──── POST /auth/refresh ──────▶│                           │
    │     { refreshToken }           │── jwt.verify(RT)          │
    │◀─── { new accessToken } ───────│   issue new AT            │

What's Implemented

Module Status Notes
Auth (signup/login/refresh/OTP) ✅ Complete JWT access + refresh, bcrypt, email OTP
Purchases ✅ Complete CRUD + batch CSV upload + inventory sync
Sales ✅ Complete CRUD + batch upload + FIFO inventory deduction
Inventory ✅ Complete CRUD + batch tracking + FIFO depletion + low-stock alerts
Menu ✅ Complete CRUD + ingredient composition via Uses table
File Storage ✅ Complete Upload/retrieve/rename/delete via AWS S3
Reports (backend) ✅ Complete P&L, financial report, inventory report, sales analytics
Dashboard metrics (frontend wiring) 🔶 Partial Endpoints exist; frontend still uses hardcoded mock data
Budget page ❌ Stub Renders placeholder only
Expenses page ❌ Stub Renders placeholder only
Deployment 📋 Planned PM2 config complete; Dockerfile and CI/CD not implemented

Known Technical Debt

These were identified and documented as pre-deployment requirements:

  1. Gmail SMTP app password is hardcoded in emailService.ts — must move to environment variable
  2. Default JWT secret is "your-secret-key" in source — dangerous without env override
  3. PM2 config uses npm run dev instead of npm start
  4. Hardcoded dev email in the inventory page

Local Setup

Full setup instructions are in the private organizational repository. High-level steps:

# 1. Start PostgreSQL (Docker)
docker run --name ftaac-postgres \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=ftaac_dev \
  -p 5432:5432 -d postgres:15

# 2. Server setup
cd codebase/server
npm install
# Add .env with DATABASE_URL, JWT_SECRET, AWS credentials, SMTP config
npx prisma migrate dev
npm run seed
npm run dev

# 3. Client setup
cd codebase/client
npm install --legacy-peer-deps
npm run dev

Organization

This project was built for the Food Truck Association of Canada as part of the ASU SER517 capstone program.

Source code available upon request.

About

Full-stack financial analytics platform for food truck operators, built for the Food Truck Association of Canada (ASU SER517 Capstone, Fall 2025). Features purchase/sales tracking, FIFO inventory management, menu composition, AWS S3 receipt storage, and P&L reporting — backed by a JWT-authenticated

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors