# evosysmenu — Product Requirements Document

## 1. Project Overview

**Product Name:** evosysmenu  
**Type:** MVC Restaurant Menu SPA (Single Page Application)  
**Platform:** Web (responsive, mobile-first)  
**Tech Stack:** PHP 8+ (MVC), MySQL, JavaScript (Vanilla), Tailwind CSS

---

## 2. Vision & Goals

Enable restaurants/cafes to serve digital menus instantly via QR codes or direct URLs, eliminating per-device setup while supporting both guest and authenticated orders.

### Primary Goals:

- One-click access: Customers scan QR → land on menu → order immediately
- Multi-branch support via unique MD5 business tokens
- Frictionless authentication: guest checkout + Google OAuth seamless upgrade
- Order tracking & customer history
- Minimal DevOps: PHP + MySQL, runs on shared hosting

---

## 3. User Personas

### 3.1 Customer / Guest

- **Goal:** Browse menu, add items, checkout, track order
- **Entry Point:** QR code or direct URL `/menu-pos-{token}`
- **Auth Options:**
  - Guest (localStorage session, no signup required)
  - Google Sign-In (full profile, order history)
- **Key Actions:**
  - View menu by category
  - Add to cart, manage quantities
  - Place order
  - View order history & tracking
  - Manage wishlist
  - Edit profile (post-login)

### 3.2 Restaurant Manager / Operator

- **Goal:** Monitor orders, manage business branch
- **Capabilities** (Backend driven):
  - View orders via admin portal (future phase)
  - Manage business token & settings
  - View customer insights

### 3.3 Developer / DevOps

- **Goal:** Deploy, configure, maintain
- **Requirements:**
  - Simple MySQL setup (schema.sql)
  - Minimal config: `app/Config/app.php`
  - Support multiple hosting environments (Apache, Nginx)

---

## 4. Core Features (MVP)

### 4.1 Authentication & Session Management

- **Guest User Flow:**
  - Auto-create guest session on first visit
  - localStorage stores: `pos_token`, `customer_uid`, `provider`
  - Session persists across reopens for same business
- **Google Sign-In:**
  - Client-side Google button triggers `auth.js`
  - Server validates token via Google API
  - Upgrades guest → google user (same UID)
  - Stores: `google_id`, `provider: 'google'`, user email + name
- **Token Validation:**
  - pos_token = 32-char MD5(branch name)
  - All API calls include both tokens for scope validation
  - Mismatched token → force re-login

### 4.2 Menu Navigation

- **Home Screen:**
  - Display categories (sidebar or tabs)
  - List items per category
  - Item detail: name, description, price, image, options (if any)
  - Add to cart button with quantity picker
- **Search/Filter (Optional MVP):**
  - Basic category filter
  - Full-text search (future)
- **Cart:**
  - Persistent (sessionStorage during session)
  - Edit quantities, remove items
  - Show subtotal, taxes, delivery fee, final total
  - Checkout button

### 4.3 Order Management

- **Order Submission:**
  - `POST /api/v1/orders.php`
  - Payload: `pos_token`, `customer_uid`, `items[]`, `delivery_address` (optional)
  - Server validates business + customer scope
  - Creates order record, returns `order_id`
- **Order History:**
  - Display past orders with status, date, total
  - Show individual order details
- **Order Tracking:**
  - Real-time status: "pending" → "accepted" → "ready" → "completed"
  - Estimated delivery/pickup time
  - (WebPush notifications framework exists, pending integration)

### 4.4 User Profile & Preferences

- **Profile Screen:**
  - Display: name, email, phone, saved addresses
  - Edit: name, email, phone
  - Switch provider (guest ↔ Google)
- **Wishlist:**
  - Save favorite items
  - Quick re-order from wishlist
- **Settings:**
  - Notification preferences
  - Language (translations.json ready)

### 4.5 Admin Features (Scoped, Post-MVP)

- Order management dashboard (status updates)
- Customer insights (repeat orders, favorites)
- Business settings (operating hours, delivery zones)

---

## 5. Architecture & Technical Design

### 5.1 Overall Flow

```
Browser
  ↓
GET /menu-pos-{token}
  ↓
public/index.php (Front Controller)
  ↓
BusinessMiddleware::require({token})
  → Validates MD5, fetches Business from DB
  → Aborts 404 if invalid
  ↓
MenuController::index()
  → Injects config as window.__evosysmenu_CONFIG__
  ↓
Views/menu/index.php (SPA shell)
  ↓
session.js boots
  → Checks localStorage for matching token
  → If none: POST /api/v1/customers.php → create guest
  → If mismatch: clear + show login
  → If valid: GET /api/v1/customers.php → load customer
  ↓
auth.js enables Google Sign-In
  ↓
menu.js renders UI + handles interactions
```

### 5.2 Directory Structure

```
evosysmenu/
├── public/
│   ├── index.php          ← Front Controller & router
│   └── .htaccess          ← Rewrite rules
├── app/
│   ├── Config/
│   │   ├── app.php        ← All constants (DB, Google API key, etc.)
│   │   └── Database.php   ← PDO singleton + connection
│   ├── Controllers/
│   │   └── MenuController.php  ← Renders menu SPA
│   ├── Models/
│   │   ├── Business.php   ← Query by token, find/create
│   │   ├── Customer.php   ← CRUD, Google upsert
│   │   ├── Order.php      ← CRUD + validation
│   │   ├── MenuItem.php   ← Menu items by category
│   │   ├── Category.php   ← Menu categories
│   │   ├── PushSubscription.php  ← WebPush subscriptions
│   ├── Middleware/
│   │   └── BusinessMiddleware.php  ← Token validation gate
│   ├── Helpers/
│   │   ├── Response.php      ← JSON response + CORS headers
│   │   ├── Token.php         ← MD5 validation & generation
│   │   └── WebPush.php       ← Push notification sender
│   └── Views/
│       ├── menu/
│       │   ├── index.php     ← Main SPA shell + config injection
│       │   ├── screens/      ← Each screen as partial
│       │   │   ├── home.php
│       │   │   ├── cart.php
│       │   │   ├── history.php
│       │   │   ├── profile.php
│       │   │   ├── tracking.php
│       │   │   └── wishlist.php
│       │   └── partials/
│       │       ├── modals.php
│       │       ├── toast.php
│       │       └── bottom-nav.php
│       └── errors/
│           └── 404.php
├── api/
│   └── v1/
│       ├── customers.php     ← GET (fetch), POST (create/update)
│       ├── orders.php        ← POST (create order)
│       ├── menu.php
│       ├── push.php
│       ├── wishlists.php
│       └── auth/
│           └── google.php    ← Google token verification
├── assets/
│   ├── menu.js              ← Main app logic
│   ├── auth.js              ← Google Sign-In + login flow
│   ├── session.js           ← localStorage manager
│   ├── sw.js                ← Service Worker (PWA ready)
│   ├── styles.css           ← App styles
│   ├── tailwind.config.js   ← Tailwind config
│   └── translations.json    ← i18n strings
├── storage/
│   ├── schema.sql           ← Full DB schema (run once)
│   ├── migrations/
│   │   ├── add_categories_menu_items.sql
│   │   ├── add_wishlist_delivery.sql
│   │   └── ...
│   └── sessions/            ← Session file storage (optional)
├── logs/
│   ├── php_errors.log
│   └── orders_errors.log
├── README.md
└── PRD/
    └── PRD.md              ← This document
```

### 5.3 Data Models

#### Businesses

```sql
id (PK)
name VARCHAR
md5_token CHAR(32) UNIQUE
created_at TIMESTAMP
```

#### Customers

```sql
id (PK)
uid VARCHAR(190) UNIQUE       -- customer_uid (from guest gen or Google)
name VARCHAR
email VARCHAR
phone VARCHAR
google_id VARCHAR UNIQUE      -- Google ID (nullable)
provider VARCHAR              -- 'guest', 'google'
created_at TIMESTAMP
updated_at TIMESTAMP
```

#### Orders

```sql
id (PK)
business_id FK
customer_id FK
items JSON                     -- array of { menu_item_id, qty, options }
total DECIMAL(10,2)
status VARCHAR                 -- 'pending', 'accepted', 'ready', 'completed'
notes TEXT
created_at TIMESTAMP
updated_at TIMESTAMP
```

#### MenuItems

```sql
id (PK)
business_id FK
category_id FK
name VARCHAR
description TEXT
price DECIMAL(10,2)
image_url VARCHAR
created_at TIMESTAMP
```

#### Categories

```sql
id (PK)
business_id FK
name VARCHAR
sort_order INT
created_at TIMESTAMP
```

#### Wishlists

```sql
id (PK)
customer_id FK
menu_item_id FK
created_at TIMESTAMP
```

#### PushSubscriptions

```sql
id (PK)
customer_id FK
endpoint VARCHAR
auth_secret VARCHAR
p256dh VARCHAR
created_at TIMESTAMP
```

---

## 6. API Design

### 6.1 Authentication & Customer Endpoints

#### POST /api/v1/customers.php (Create Guest)

**Request:**

```json
{}
```

**Response (success):**

```json
{
	"success": true,
	"data": {
		"customer": {
			"uid": "abc...",
			"name": "Guest",
			"provider": "guest",
			"created_at": "2026-03-31T10:00:00Z"
		}
	}
}
```

#### GET /api/v1/customers.php?uid={uid} (Fetch Customer)

**Response:**

```json
{
  "success": true,
  "data": {
    "customer": { ... },
    "is_new": false
  }
}
```

#### POST /api/v1/auth/google.php (Google Login)

**Request:**

```json
{
	"id_token": "...",
	"pos_token": "...",
	"customer_uid": "..."
}
```

**Response:**

```json
{
	"success": true,
	"data": {
		"customer": {
			"uid": "...",
			"name": "John Doe",
			"email": "john@example.com",
			"google_id": "...",
			"provider": "google"
		}
	}
}
```

### 6.2 Order Endpoints

#### POST /api/v1/orders.php (Create Order)

**Request:**

```json
{
	"pos_token": "a1b2c3...",
	"customer_uid": "cust_123",
	"items": [
		{
			"menu_item_id": 5,
			"quantity": 2,
			"options": {}
		}
	],
	"delivery_address": "123 Main St",
	"notes": "Extra sauce"
}
```

**Response:**

```json
{
	"success": true,
	"data": {
		"order_id": 42,
		"total": 25.5,
		"status": "pending",
		"created_at": "2026-03-31T10:15:00Z"
	}
}
```

### 6.3 Menu Endpoints

#### GET /api/v1/menu.php?pos_token=...

**Response:**

```json
{
	"success": true,
	"data": {
		"categories": [
			{
				"id": 1,
				"name": "Main Dishes",
				"items": [
					{
						"id": 5,
						"name": "Burger",
						"price": 12.99,
						"description": "..."
					}
				]
			}
		]
	}
}
```

---

## 7. User Experience & Flows

### 7.1 Onboarding (First Visit)

1. User scans QR → `GET /menu-pos-{token}`
2. Middleware validates token
3. `session.js` checks localStorage → no session
4. Auto-creates guest via `POST /api/v1/customers.php`
5. Stores `pos_token`, `customer_uid`, `provider='guest'` → localStorage
6. Renders home screen with categories + items

### 7.2 Guest → Google Upgrade

1. User taps "Sign in with Google"
2. `auth.js` opens Google Sign-In dialog
3. User grants permission, Google returns `id_token`
4. JS posts to `POST /api/v1/auth/google.php` with token + current session IDs
5. Server validates token, upserts customer (same UID, new google_id)
6. Response updates localStorage: `provider='google'`, `email`, `name`
7. UI updates profile section

### 7.3 Order Placement

1. User browsing categories
2. Taps item → sees detail modal (name, price, description, options)
3. Selects quantity, taps "Add to Cart"
4. Cart updates in bottom nav with item count
5. User taps "Cart" → reviews items, edits quantities
6. Taps "Checkout"
7. Optional: enter delivery address (modal)
8. Taps "Place Order"
9. JS posts to `POST /api/v1/orders.php`
10. Server validates, creates order, returns `order_id`
11. JS shows success toast + redirects to tracking screen
12. Tracking screen polls for status updates

### 7.4 Session Persistence Across Browsers

1. User visits same business URL from different browser
2. `session.js` finds no localStorage
3. Shows login screen (not auto-guest, to prevent spam)
4. User can:
   - Tap "Continue as Guest" → new guest session
   - Tap "Sign in with Google" → existing customer restored

---

## 8. Non-Functional Requirements

### 8.1 Security

- **Token Validation:** All endpoints validate `pos_token` (MD5) + `customer_uid`
- **CORS:** `Response` helper enforces CORS headers per config
- **SQL Injection:** PDO with prepared statements throughout
- **XSS:** User-generated content (names, notes) escaped on output
- **HTTPS:** Recommended for production (Google OAuth requires it)

### 8.2 Performance

- **SPA Strategy:** Minimal page reloads, JS-driven navigation
- **Lazy Loading:** Categories + items loaded on demand
- **localStorage Caching:** Menu categories cached client-side (invalidate on reload)
- **API Response Times:** Target <200ms for core endpoints (DB indexed on pos_token, customer_uid)

### 8.3 Scalability

- **Database Indexing:**
  ```sql
  INDEX businesses(md5_token)
  INDEX customers(uid)
  INDEX orders(business_id, customer_id)
  ```
- **Statelessness:** All server endpoints stateless; session stored client-side
- **Multi-tenant:** pos_token enforces data isolation

### 8.4 Reliability & Error Handling

- **Graceful Degradation:**
  - Network error on order → toast "Try again" + save to sessionStorage
  - Token mismatch → clear localStorage + redirect login
- **Logging:**
  - `logs/php_errors.log` → PHP errors
  - `logs/orders_errors.log` → Order creation failures
- **Retry Logic:** Client retries failed API calls with exponential backoff

### 8.5 Accessibility

- Semantic HTML (nav, main, section tags)
- ARIA labels on buttons
- Keyboard navigation (Tab, Enter)
- Responsive design (mobile-first, Tailwind)

### 8.6 Internationalization

- `assets/translations.json` structure prepared
- Planned support: English, Spanish, French (future phase)

---

## 9. Deployment & Setup

### 9.1 Prerequisites

- PHP 8.0+
- MySQL 5.7+ or MariaDB
- Apache 2.4+ (with mod_rewrite) OR Nginx 1.18+
- OpenSSL (for Google OAuth)

### 9.2 Installation Steps

1. **Clone/Extract Project**

   ```bash
   cd /var/www
   git clone https://repo.git evosysmenu
   cd evosysmenu
   ```

2. **Create MySQL Database**

   ```bash
   mysql -u root -p -e "CREATE DATABASE evosyspos_dbevosyspos CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
   mysql -u root -p evosyspos_dbevosyspos < storage/schema.sql
   ```

3. **Configure `app/Config/app.php`**

   ```php
   define('DB_HOST', 'localhost');
   define('DB_USER', 'your_user');
   define('DB_PASS', 'your_password');
   define('DB_NAME', 'evosyspos_dbevosyspos');
   define('GOOGLE_CLIENT_ID', 'your-client-id.apps.googleusercontent.com');
   define('GOOGLE_VERIFY_URL', 'https://www.googleapis.com/oauth2/v3/tokeninfo');
   ```

4. **Configure Webserver (Apache)**

   ```apache
   <VirtualHost *:80>
       ServerName evosysmenu.test
       DocumentRoot /var/www/evosysmenu/public
       <Directory /var/www/evosysmenu/public>
           AllowOverride All
           Require all granted
       </Directory>
   </VirtualHost>
   ```

   Add to `/etc/hosts`: `127.0.0.1 evosysmenu.test`

5. **Create Logs Directory**

   ```bash
   mkdir -p logs && chmod 775 logs
   ```

6. **Insert Sample Business**

   ```sql
   INSERT INTO businesses (name, md5_token, created_at)
   VALUES ('My Restaurant', MD5('my-restaurant'), NOW());
   ```

7. **Test**
   Visit: `http://evosysmenu.test/menu-pos-[MD5_TOKEN_HERE]`

---

## 10. Success Metrics & KPIs

### 10.1 Product Metrics

- **Adoption:** # of unique businesses > 100 (6mo target)
- **Usage:** Daily active customers per business > 10
- **Conversion:** Guest → Google login rate > 30%
- **Order Success Rate:** >99% order completion (no crashes/errors)

### 10.2 Performance Metrics

- **Page Load:** <2s at 3G speed (Lighthouse)
- **API Latency:** 50th percentile <100ms, 99th <500ms
- **Uptime:** 99.5% availability per month

### 10.3 User Satisfaction

- **NPS (Net Promoter Score):** >50
- **App Rating:** >4.5 stars (if published as PWA)

---

## 11. Roadmap & Future Phases

### Phase 1 (MVP - Q2 2026)

- ✅ Guest + Google auth
- ✅ Menu browsing + cart
- ✅ Order creation
- ✅ Order history
- ✅ Wishlist
- ✅ Profile screen
- ✅ Responsive design

### Phase 2 (Q3 2026)

- Admin dashboard (order management, status updates)
- Merchant menu CRUD (add/edit items, categories)
- Order notifications (email + WebPush)
- Advanced search & filtering

### Phase 3 (Q4 2026)

- Multi-language support (i18n)
- Delivery time estimation
- Customer ratings & reviews
- Payment integration (Stripe/PayPal)

### Phase 4 (2027)

- Inventory management
- Delivery driver app
- Advanced analytics
- Mobile app (React Native / Flutter)

---

## 12. Known Constraints & Assumptions

### 12.1 Constraints

- No server-side menu edit UI (Phase 2)
- No payment processing (Phase 3)
- No real-time order status updates (polling only in MVP)
- Single business token per URL (no multi-app on one POS terminal)

### 12.2 Assumptions

- Customers have smartphones or tablets
- Restaurant has reliable internet
- Google OAuth available in customer region
- MySQL available (no SQLite multi-tenant)
- Business maintains MD5 token securely

---

## 13. Glossary

| Term                 | Definition                                              |
| -------------------- | ------------------------------------------------------- |
| **pos_token**        | 32-char MD5 hash identifying a restaurant branch        |
| **customer_uid**     | Unique identifier for a customer (guest or Google user) |
| **SPA**              | Single Page Application; all navigation via JavaScript  |
| **Provider**         | Auth method (guest, google)                             |
| **Upsert**           | Update if exists, insert if not                         |
| **Middleware**       | Request validator (fires before controller)             |
| **Front Controller** | Single entry point (public/index.php) for all requests  |

---

## 14. Document History

| Version | Date       | Author       | Changes                            |
| ------- | ---------- | ------------ | ---------------------------------- |
| 1.0     | 2026-03-31 | AI Assistant | Initial PRD from codebase analysis |

---

**Last Updated:** 2026-03-31  
**Status:** APPROVED FOR IMPLEMENTATION
