diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..edcd322 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,8 @@ +# Instructions for Gemini + +This file serves as a guide for future sessions working on this codebase. + +1. **Read Memory First**: Always read `MEMORY.md` at the start of a session to understand the project context and our working agreements. +2. **Update Memory**: If we make significant architectural decisions or change our working patterns, update `MEMORY.md` to reflect this. +3. **Check Documentation**: `README.md`, `docs/ARCHITECTURE.md`, and `docs/SETUP.md` are the sources of truth for the system. Keep them updated as code changes. +4. **Task Tracking**: Use the `task.md` artifact to track progress on multi-step tasks. diff --git a/MEMORY.md b/MEMORY.md new file mode 100644 index 0000000..aa0ba3f --- /dev/null +++ b/MEMORY.md @@ -0,0 +1,25 @@ +# Project Memory + +## Project Context +This project (`product_inventory`) integrates Google Sheets with Shopify. It serves as a master inventory management tool where users edit product data in a Google Sheet, and scripts automatically sync those changes to Shopify. + +**Critical Components:** +- **Google Apps Script**: Runs the logic. +- **"vars" Sheet**: Holds all configuration and API keys. NEVER hardcode credentials. +- **Shopify Admin API**: Used for syncing. REST for Orders, GraphQL for Products. + +## Work Patterns & Agreements +1. **Documentation First**: Before implementing complex features, we update the plan and often the documentation (README/ARCHITECTURE). +2. **Safety First**: We use `SafeToAutoRun: false` for commands that deploy or modify external state until verified. +3. **Strict Typing**: We use TypeScript. No `any` unless absolutely necessary (and even then, we try to avoid it). +4. **Artifact Usage**: We use `task.md`, `implementation_plan.md`, and `walkthrough.md` to track state. + +## Key Technical Decisions +- **Queue System**: We implemented `onEditQueue.ts` to batch edits. This prevents hitting Shopify API rate limits and Google Apps Script execution limits during rapid manual edits. +- **Hybrid API**: We use REST for retrieving Orders (legacy/easier for flat data) and GraphQL for Products (more efficient/flexible). +- **Global Exports**: Functions in `src/global.ts` are explicitly exposed to be callable by Apps Script triggers. + +## User Preferences +- **OS**: Windows. +- **Shell**: PowerShell. +- **Node Manager**: `fnm`. diff --git a/README.md b/README.md new file mode 100644 index 0000000..328c99e --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# Product Inventory Management + +This project integrates Google Sheets with Shopify to manage product inventory, photos, and metadata. It uses Google Apps Script to synchronize data between a "master" Google Sheet and your Shopify store. + +## Overview + +The system allows you to: +- Manage product details (SKUs, titles, descriptions) in a Google Sheet. +- Automatically upload product photos from Google Drive to Shopify. +- specific triggers (`onEdit`, `onOpen`) to sync changes to Shopify in real-time or on-demand. +- Handle rate limiting and concurrency using a custom queue system. + +## Prerequisites + +- **Node.js**: managed via `fnm` (Fast Node Manager) +- **Google Clasp**: for pushing code to Apps Script +- **Google Cloud Project**: tied to the Apps Script container + +## Quick Start + +1. **Install Dependencies** + ```bash + npm install + ``` + +2. **Build Project** + ```bash + npm run build + ``` + +3. **Deploy to Apps Script** + ```bash + npm run deploy + ``` + +## Project Structure + +- `src/`: Source code (TypeScript) +- `src/config.ts`: Configuration loading from Sheets +- `src/global.ts`: Entry points for Apps Script +- `src/shopifyApi.ts`: Shopify Admin API wrapper +- `src/onEditQueue.ts`: Concurrency management + +For more details, see: +- [Architecture Guide](docs/ARCHITECTURE.md) +- [Setup Guide](docs/SETUP.md) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..fe8c48a --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,68 @@ +# Architecture Documentation + +## System Overview + +This project serves as a bridge between Google Sheets and Shopify. It enables a two-way sync (primarily Sheets to Shopify for products) and allows managing inventory directly from a spreadsheet. + +### Core Flows + +1. **Product Updates**: + - User edits a cell in the "product_inventory" sheet. + - `onEditQueue` trigger fires, capturing the SKU and timestamp. + - Edits are batched in `PropertiesService` (script properties). + - A time-based trigger runs `processBatchedEdits` every minute. + - The processing function locks the script, reads the queue, and pushes changes to Shopify via the Admin API. + +2. **Order Sync**: + - Users can run menu commands to fetch orders from Shopify. + - The `Shop` class fetches orders via the REST API, handling pagination. + - Data is populated into specific sheets (`_orders`, `_line_items`, `_customer`, etc.). + +## Key Components + +### 1. Queue System (`src/onEditQueue.ts`) + +To avoid hitting Shopify API rate limits and Google Apps Script execution time limits, edits are not processed immediately. + +- **`onEditQueue(e)`**: + - Triggered on every cell edit. + - Checks if the edit is valid (correct sheet, valid SKU). + - Acquires a `DocumentLock`. + - Updates a JSON list in `ScriptProperties` (`pendingEdits`). + - Debounces edits (updates timestamp if SKU is already pending). + +- **`processBatchedEdits()`**: + - Run via time-based trigger (every 1 minute). + - Acquires a `ScriptLock`. + - Reads `pendingEdits`. + - Filters for edits older than `BATCH_INTERVAL_MS` (30s) to allow for multiple quick edits to the same SKU. + - Iterates through valid edits and calls `Product.UpdateShopifyProduct`. + +### 2. Shopify Integration (`src/shopifyApi.ts`) + +The project uses a hybrid approach for the Shopify Admin API: + +- **REST API**: Used primarily for fetching Orders (legacy support). +- **GraphQL API**: Used for fetching and updating Products and Inventory. + +The `Shop` class handles authentication using credentials stored in the "vars" sheet. + +### 3. Configuration (`src/config.ts`) + +Configuration, including API keys, is stored in a dedicated Google Sheet named "vars". The `Config` class reads these values at runtime using a `vlookup` style helper. + +**Required "vars" columns:** +- `key`: The name of the configuration variable. +- `value`: The actual value. + +### 4. Global Entry Points (`src/global.ts`) + +Since Apps Script functions must be top-level to be triggered or attached to buttons, `src/global.ts` explicitly exposes necessary functions from the modules to the global scope. + +## Triggers + +Triggers are managed programmatically via `src/triggers.ts`. Running `reinstallTriggers` will wipe existing project triggers and set up the standard set: +- `onEdit` -> `newSkuHandler` +- `onEdit` -> `matchProductToShopifyOnEditHandler` +- `onEdit` -> `onEditQueue` +- `TimeBased (1 min)` -> `processBatchedEdits` diff --git a/docs/SETUP.md b/docs/SETUP.md new file mode 100644 index 0000000..325d297 --- /dev/null +++ b/docs/SETUP.md @@ -0,0 +1,57 @@ +# Setup Guide + +## Local Development Environment + +1. **Install Node.js** + This project uses `fnm` to manage Node versions. + ```powershell + # Install fnm (if not installed) + winget install Schniz.fnm + # Configure environment + fnm env --use-on-cd | Out-String | Invoke-Expression + # Install Node version + fnm use --install-if-missing 22 + ``` + +2. **Install Dependencies** + ```bash + npm install + npm install -g @google/clasp + ``` + +3. **Clasp Login** + Authenticate with Google to allow pushing code. + ```bash + clasp login + ``` + +## Google Sheets Configuration + +1. **Create a Google Sheet** (or use existing). +2. **"vars" Sheet**: + Create a tab named `vars` with the following columns: `key`, `value`. + Add the following rows: + - `productPhotosFolderId`: ID of the Drive folder for photos. + - `shopifyApiKey`: Your Shopify API Key. + - `shopifyApiSecretKey`: Your Shopify API Secret. + - `shopifyAdminApiAccessToken`: The Admin API access token. + - `shopifyApiURI`: e.g., `https://your-store.myshopify.com` + - `shopifyLocationId`: Location ID for inventory. + - `shopifyCountryCodeOfOrigin`: Two-letter country code (e.g., `US`). + - `shopifyProvinceCodeOfOrigin`: Two-letter province code (e.g., `NY`). + +## Deployment + +1. **Build** + ```bash + npm run build + ``` + +2. **Push to Apps Script** + ```bash + npm run deploy + ``` + +3. **Install Triggers** + Open the Apps Script editor (Extensions > Apps Script). + Run the `reinstallTriggers` function manually once to set up the automation.