VINLAB Project Details and Handover Guide
=========================================

Project Summary
---------------
VINLAB is a Laravel catalog and lead-generation website for:
- Nursing and medical training products
- Laboratory equipment
- Education maps, charts, globes, models, and GIS learning products

The public website shows home pages, product listings, product detail pages, services, industries, blog, contact, and quote forms. The admin dashboard manages categories, products, media, services, blog posts, inquiries, and site settings.

Local Environment
-----------------
Project path:
- c:\xampp\htdocs\vinlab-laravel

Main local URL:
- http://127.0.0.1:8000

Common local command:
- php artisan serve

Database from .env:
- DB_CONNECTION=mysql
- DB_HOST=127.0.0.1
- DB_PORT=3306
- DB_DATABASE=vinlab
- DB_USERNAME=root
- DB_PASSWORD is blank

Admin Access
------------
Admin login URL:
- http://127.0.0.1:8000/admin/login

Current admin credentials from .env:
- Username: admin
- Password: admin123

Important:
- This project does not currently use the users table for admin login.
- Admin login is handled by app/Http/Controllers/AdminController.php using ADMIN_USERNAME and ADMIN_PASSWORD_HASH from .env.
- Admin session access is checked by app/Http/Middleware/EnsureVinlabAdmin.php.

How to change admin username:
1. Open .env.
2. Change:
   ADMIN_USERNAME=admin

How to change admin password:
1. Generate a new bcrypt hash:
   php -r "echo password_hash('your-new-password', PASSWORD_BCRYPT), PHP_EOL;"
2. Copy the generated hash.
3. Update .env:
   ADMIN_PASSWORD_HASH=generated-hash-here
4. Clear config cache:
   php artisan optimize:clear

There is no database table to edit for the current admin login credentials.

Site Settings
-------------
Admin settings page:
- /admin/settings

Settings include:
- Site name
- Tagline
- Admin email
- Footer phone/email/about/social links
- Logo
- Favicon
- Virtual tour image/text
- Map title/address/embed URL

Storage location:
- storage/app/site-settings.json

This is not stored in a database table right now. The public layout reads these settings through the shared siteSettings data.

Main File Structure
-------------------
Routes:
- routes/web.php

Frontend controller:
- app/Http/Controllers/FrontendController.php

Admin controller:
- app/Http/Controllers/AdminController.php

Models:
- app/Models/Category.php
- app/Models/Product.php
- app/Models/Service.php
- app/Models/BlogPost.php
- app/Models/Inquiry.php

Public views:
- resources/views/public/home.blade.php
- resources/views/public/home-2.blade.php
- resources/views/public/home-3.blade.php
- resources/views/public/about.blade.php
- resources/views/public/products.blade.php
- resources/views/public/product-detail.blade.php
- resources/views/public/services.blade.php
- resources/views/public/service-detail.blade.php
- resources/views/public/industries.blade.php
- resources/views/public/blog.blade.php
- resources/views/public/blog-detail.blade.php
- resources/views/public/contact.blade.php
- resources/views/public/quote.blade.php

Product detail components:
- resources/views/components/product/type1.blade.php
- resources/views/components/product/type2.blade.php
- resources/views/components/product/type3.blade.php

Admin views:
- resources/views/admin/dashboard.blade.php
- resources/views/admin/categories.blade.php
- resources/views/admin/products.blade.php
- resources/views/admin/product-form.blade.php
- resources/views/admin/media.blade.php
- resources/views/admin/settings.blade.php
- resources/views/admin/services.blade.php
- resources/views/admin/blog.blade.php
- resources/views/admin/inquiries.blade.php

Shared layouts:
- resources/views/layouts/public.blade.php
- resources/views/layouts/admin.blade.php

Shared partials:
- resources/views/partials/product-card.blade.php
- resources/views/partials/inquiry-form.blade.php

Main CSS:
- public/assets/css/styles.css

Main JavaScript:
- public/assets/js/app.js

Uploaded media:
- public/assets/uploads/products
- public/assets/uploads/branding
- public/assets/uploads/virtual-tour

Database Structure
------------------
Main migrations:
- database/migrations/2026_04_29_000003_create_vinlab_catalog_tables.php
- database/migrations/2026_04_29_000004_add_multi_type_product_fields.php
- database/migrations/2026_04_30_000001_add_soft_deletes_to_admin_content.php

Main tables:
- categories
- products
- services
- blog_posts
- inquiries

categories table:
- id
- parent_id
- name
- slug
- description
- image_url
- meta_title
- meta_description
- sort_order
- created_at
- deleted_at, if soft delete migration has run

products table:
- id
- category_id
- product_type
- name
- slug
- short_description
- description
- price
- stock
- features
- specification_pairs
- faq
- gallery_type
- catalog_items
- enable_cart
- status
- specifications
- use_cases
- images
- brochure_url
- meta_title
- meta_description
- is_featured
- created_at
- updated_at
- deleted_at

services table:
- id
- title
- slug
- summary
- overview
- offer_items
- process_items
- industries
- image_url
- meta_title
- meta_description
- deleted_at

blog_posts table:
- id
- title
- slug
- category
- excerpt
- body
- image_url
- meta_title
- meta_description
- published_at
- deleted_at

inquiries table:
- id
- product_id
- name
- organization
- email
- phone
- category
- requirement
- message
- source_page
- status
- created_at
- deleted_at

Product Category Model
----------------------
There are 3 main parent categories:
- Nursing and Medical
- Laboratory
- Education Maps and Charts

Products must be assigned to a child category under one of those parents.

Public product domain filters are defined in:
- app/Http/Controllers/FrontendController.php

Look for:
- public function products(Request $request)
- $domainGroups

Admin product category selection is in:
- resources/views/admin/product-form.blade.php

Product Types
-------------
type1: E-commerce style
- Price
- Stock
- Add to cart
- Buy now
- Features
- Specifications

type2: Inquiry style
- Request quote
- Features
- Specification rows
- FAQ

type3: Catalog style
- Gallery display
- Grouped catalog item list
- Catalog item images

Frontend product detail selection:
- resources/views/public/product-detail.blade.php

Components:
- type1: resources/views/components/product/type1.blade.php
- type2: resources/views/components/product/type2.blade.php
- type3: resources/views/components/product/type3.blade.php

How to Add a New Public Page
----------------------------
Example: Add a new page called Certifications.

1. Add a route in routes/web.php:
   Route::get('/certifications', [FrontendController::class, 'certifications'])->name('certifications');

2. Add a method in app/Http/Controllers/FrontendController.php:
   public function certifications(): View
   {
       return view('public.certifications');
   }

3. Create the Blade file:
   resources/views/public/certifications.blade.php

4. Use the public layout:
   @extends('layouts.public')
   @section('content')
   <main>
       <section class="inner-hero">
           <div>
               <p class="eyebrow">VINLAB</p>
               <h1>Certifications</h1>
               <p>Page description here.</p>
           </div>
       </section>
   </main>
   @endsection

5. Add the nav link in:
   resources/views/layouts/public.blade.php

6. Add CSS in:
   public/assets/css/styles.css

How to Add a New Admin Page
---------------------------
1. Add routes inside the admin route group in routes/web.php.
2. Add methods in app/Http/Controllers/AdminController.php.
3. Create a view in resources/views/admin.
4. Add a sidebar link in resources/views/layouts/admin.blade.php.
5. If database storage is needed, create a migration and model.

Media and Image Uploads
-----------------------
Admin media page:
- /admin/media

Upload handling:
- app/Http/Controllers/AdminController.php
- uploadMedia()
- storePublicUpload()

Product form media gallery:
- resources/views/admin/product-form.blade.php
- public/assets/js/app.js

Uploaded product images are usually stored under:
- public/assets/uploads/products

Logo and favicon uploads are stored under:
- public/assets/uploads/branding

Inquiry and Cart Flow
---------------------
Public forms post to:
- POST /inquiry

Route name:
- inquiry.store

Controller method:
- FrontendController::inquiry()

Inquiry data is saved in:
- inquiries table

Admin page:
- /admin/inquiries

Cart behavior:
- Cart items are stored in browser localStorage as vinlab_cart.
- Cart UI and checkout drawer are in resources/views/layouts/public.blade.php.
- Cart JavaScript is in public/assets/js/app.js.
- Cart details are submitted into the inquiry message through the hidden cart_details field.

Email notifications:
- The current .env uses MAIL_MAILER=log, so emails are logged instead of sent.
- To send real email, update MAIL_* settings in .env.
- Recipient is taken from admin_email in site settings, falling back to config mail from address.

Useful SQL Commands
-------------------
Show parent categories:
SELECT id, name, slug FROM categories WHERE parent_id IS NULL AND deleted_at IS NULL ORDER BY sort_order, name;

Show child categories with parent:
SELECT c.id, p.name AS parent, c.name, c.slug
FROM categories c
LEFT JOIN categories p ON p.id = c.parent_id
WHERE c.parent_id IS NOT NULL AND c.deleted_at IS NULL
ORDER BY p.name, c.name;

Show latest products:
SELECT id, name, slug, product_type, category_id, status, is_featured, updated_at
FROM products
WHERE deleted_at IS NULL
ORDER BY updated_at DESC
LIMIT 20;

Mark a product as featured:
UPDATE products SET is_featured = 1 WHERE id = 1;

Deactivate a product:
UPDATE products SET status = 'draft' WHERE id = 1;

Restore a soft-deleted product:
UPDATE products SET deleted_at = NULL WHERE id = 1;

Show latest inquiries:
SELECT id, name, organization, email, phone, status, created_at
FROM inquiries
ORDER BY created_at DESC
LIMIT 20;

Mark an inquiry as contacted:
UPDATE inquiries SET status = 'contacted' WHERE id = 1;

Update a product slug:
UPDATE products SET slug = 'new-product-slug' WHERE id = 1;

Maintenance Commands
--------------------
Clear Laravel caches:
php artisan optimize:clear

Compile Blade views:
php artisan view:cache

Run migrations:
php artisan migrate

Run all seeders:
php artisan db:seed

Run a specific seeder:
php artisan db:seed --class=LaboratoryProductSeeder

Check routes:
php artisan route:list

Design Notes
------------
Most visual styling is currently in:
- public/assets/css/styles.css

This file has many override sections because the site has gone through several design revisions. When making a new design fix, add the final override near the bottom of the file or carefully check whether a later CSS rule is overriding your change.

JavaScript Notes
----------------
Main JavaScript file:
- public/assets/js/app.js

Current responsibilities:
- Mobile menu
- Product gallery thumbnail switching
- Product filter tabs
- Admin product type panels
- Admin product form tabs
- Admin media popup selection
- Cart localStorage behavior
- Quote modal
- Virtual tour drag behavior

Recommended Rules for Future Work
---------------------------------
- Add new public content in resources/views/public.
- Add reusable UI blocks in resources/views/components.
- Keep admin features in resources/views/admin and AdminController.
- Keep public website behavior in FrontendController.
- Use slugs for public URLs.
- Keep products under the 3 parent category structure.
- After changing routes, views, or config, run php artisan optimize:clear.
- After Blade edits, run php artisan view:cache to catch template errors.

