Skip to main content

Overview

Quality Hub GINEZ uses Google Sheets as the data source for its product catalog. This approach provides:
  • ✅ Real-time updates without code deployment
  • ✅ Familiar spreadsheet interface for non-technical users
  • ✅ Easy collaboration on product data
  • ✅ Version history and audit trail
  • ✅ No database schema changes needed
The system consumes two separate sheets:
  1. Materia Prima (MP) - Raw materials catalog
  2. Producto Terminado (PT) - Finished products catalog

Architecture

Data is fetched on-demand when users access the catalog. Consider implementing Next.js revalidation for production deployments.

Setup Instructions

Step 1: Create Google Sheets

Create two separate Google Sheets for your product data:
1

Create Raw Materials Sheet

  1. Go to Google Sheets
  2. Create new spreadsheet: “Quality Hub - Materia Prima”
  3. Add columns (see schema below)
2

Create Finished Products Sheet

  1. Create another spreadsheet: “Quality Hub - Producto Terminado”
  2. Add columns (see schema below)
3

Populate Data

Fill in your product information following the schema requirements

Step 2: Sheet Schema

Both sheets should follow this structure:
Codigo,Nombre,Familia,Categoria,Tipo,FichaTecnica,HojaSeguridad

Column Definitions

Codigo
string
required
Product Code - Unique identifier (e.g., “LIMLIM”, “TRALIM”)
  • Must be unique within the sheet
  • Used for matching with production records
  • Should match codes in production-constants.ts
Nombre
string
required
Product Name - Full descriptive nameExample: “Limpiador Multiusos Limón 5L”
Familia
string
required
Product Family - High-level categorizationCommon values:
  • Cuidado del Hogar
  • Cuidado Personal
  • Lavandería
  • Línea Automotriz
  • Línea Antibacterial
  • Productos Intermedios
Categoria
string
required
Product Category - Specific product typeExamples:
  • Limpiadores Multiusos
  • Detergentes para Trastes
  • Suavizantes de Telas
  • Jabones Líquidos
  • Shampoos
Tipo
string
required
Type - Material classificationValues:
  • Materia Prima - Raw materials
  • Producto Terminado - Finished products
  • Producto Intermedio - Intermediate products
FichaTecnica
url
Technical Data Sheet URL - Link to product specification PDF
  • Should be a Google Drive public link or direct download URL
  • Example: https://drive.google.com/file/d/ABC123/view?usp=sharing
  • Downloads are tracked in admin audit log
HojaSeguridad
url
Safety Data Sheet (SDS) URL - Link to safety documentation
  • Should be a Google Drive public link or direct download URL
  • Critical for chemical products
  • Downloads are tracked in admin audit log

Step 3: Publish to Web

Each sheet must be published as CSV to generate the URL needed for the application.
1

Open Publish Dialog

In your Google Sheet:
  1. Click FileSharePublish to web
2

Configure Publication

In the publish dialog:
  1. Link tab: Select the specific sheet/tab (e.g., “Sheet1”)
  2. Format: Choose Comma-separated values (.csv)
  3. ✅ Check “Automatically republish when changes are made”
  4. Click Publish
3

Copy URL

Copy the generated URL. It should look like:
https://docs.google.com/spreadsheets/d/e/2PACX-1vQxyz.../pub?gid=0&single=true&output=csv
4

Add to Environment

Add the URLs to your .env.local:
SHEET_MP_CSV_URL="https://docs.google.com/spreadsheets/d/e/.../pub?gid=123&single=true&output=csv"
SHEET_PT_CSV_URL="https://docs.google.com/spreadsheets/d/e/.../pub?gid=456&single=true&output=csv"
Make sure to select CSV format, not HTML. The URL must end with output=csv.

Document Storage (Google Drive)

The FichaTecnica and HojaSeguridad columns should link to PDF documents stored in Google Drive.
1

Upload Documents

  1. Create a Google Drive folder: “Quality Hub - Documentos”
  2. Upload all technical data sheets and safety sheets as PDFs
  3. Organize in subfolders if needed (e.g., by product family)
2

Set Permissions

For each document:
  1. Right-click → Share
  2. Click Change to anyone with the link
  3. Set permission to Viewer
  4. Click Copy link
3

Add Links to Sheet

Paste the Google Drive links into the respective columns:
https://drive.google.com/file/d/1ABC123xyz/view?usp=sharing
Use descriptive filenames for PDFs (e.g., FT-LIMLIM-2024.pdf) to make management easier.

Data Validation

Implement these validation rules in your Google Sheets:

Required Field Validation

=AND(LEN(A2)>0, COUNTIF($A:$A, A2)=1)
Apply these using Data → Data validation in Google Sheets.

Syncing and Caching

Current Behavior

// Data fetched on page load (client-side)
const response = await fetch(process.env.SHEET_MP_CSV_URL)
const csvText = await response.text()
const products = parseCSV(csvText)
Current implementation fetches fresh data on every page load. This ensures data is always current but may impact performance.
For better performance, implement server-side caching:
import { NextResponse } from 'next/server'

export const revalidate = 300 // Revalidate every 5 minutes

export async function GET() {
  try {
    const [mpResponse, ptResponse] = await Promise.all([
      fetch(process.env.SHEET_MP_CSV_URL!, { next: { revalidate } }),
      fetch(process.env.SHEET_PT_CSV_URL!, { next: { revalidate } })
    ])
    
    const [mpData, ptData] = await Promise.all([
      mpResponse.text(),
      ptResponse.text()
    ])
    
    return NextResponse.json({
      materiaPrima: parseCSV(mpData),
      productoTerminado: parseCSV(ptData)
    })
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch catalog' },
      { status: 500 }
    )
  }
}
Adjust revalidate time based on how frequently your catalog changes. For stable catalogs, use 3600 (1 hour) or more.

Troubleshooting

Possible causes:
  1. Sheet not published to web
  2. Wrong URL format (not CSV)
  3. Sheet permissions too restrictive
Solution:
# Test URL directly in browser
curl "YOUR_SHEET_URL" | head -20
Should return CSV text, not HTML.
Check:
  1. CSV structure matches schema (headers in row 1)
  2. No empty required fields
  3. Encoding is UTF-8 (special characters display correctly)
  4. No duplicate Codigo values
Debug:
console.log('Raw CSV:', await response.text())
console.log('Parsed products:', products)
Cause: Encoding issueSolution:
  1. Google Sheets should auto-publish as UTF-8
  2. In your fetch code, ensure:
const response = await fetch(url)
const text = await response.text() // Automatically handles UTF-8
  1. If issues persist, manually specify:
const buffer = await response.arrayBuffer()
const decoder = new TextDecoder('utf-8')
const text = decoder.decode(buffer)
If using caching:
  1. Wait for revalidation period to expire
  2. Or manually clear cache:
mutate('/api/catalog') // If using SWR
router.refresh() // If using Next.js App Router
If no caching:
  1. Hard refresh browser (Ctrl+Shift+R)
  2. Verify sheet has “auto-republish” enabled
  3. Check published URL returns latest data

Best Practices

Data Governance

  • Limit edit access to quality/product managers
  • Use protected ranges for critical columns
  • Maintain change log sheet for audit trail

Performance

  • Keep sheets under 10,000 rows for best performance
  • Use separate sheets for historical/archived products
  • Implement server-side caching for production

Data Quality

  • Use data validation rules
  • Standardize naming conventions
  • Regularly audit for duplicates or inconsistencies

Documentation

  • Include sheet instructions in first row (hide it)
  • Maintain README sheet with schema definitions
  • Document any custom formulas or validation rules

Migration to Database (Optional)

For large-scale deployments, consider migrating catalog data to Supabase:
1

Create Catalog Table

CREATE TABLE catalogo_productos (
  id BIGSERIAL PRIMARY KEY,
  codigo TEXT UNIQUE NOT NULL,
  nombre TEXT NOT NULL,
  familia TEXT NOT NULL,
  categoria TEXT NOT NULL,
  tipo TEXT NOT NULL,
  ficha_tecnica TEXT,
  hoja_seguridad TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);
2

Import Existing Data

Export CSV from Google Sheets and import:
COPY catalogo_productos(codigo, nombre, familia, categoria, tipo, ficha_tecnica, hoja_seguridad)
FROM '/path/to/export.csv'
DELIMITER ','
CSV HEADER;
3

Update Application

Replace CSV fetch with Supabase query:
const { data: products } = await supabase
  .from('catalogo_productos')
  .select('*')
  .order('nombre')
Keep Google Sheets for initial setup and small deployments. Migrate to database when catalog exceeds 5,000+ products or requires complex queries.

Next Steps

Environment Variables

Configure Google Sheets CSV URLs in your environment

Multi-Location

Learn about configuring production locations

Build docs developers (and LLMs) love