{"id":28522271,"url":"https://github.com/genaker/gogento","last_synced_at":"2025-07-04T09:31:21.139Z","repository":{"id":292116587,"uuid":"979871292","full_name":"Genaker/GoGento","owner":"Genaker","description":"Golang implementation for Magento and Adobe Commerce","archived":false,"fork":false,"pushed_at":"2025-05-23T22:59:07.000Z","size":2599,"stargazers_count":13,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-07T05:12:14.546Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Genaker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-08T07:44:30.000Z","updated_at":"2025-06-02T09:39:24.000Z","dependencies_parsed_at":"2025-05-09T04:17:47.854Z","dependency_job_id":null,"html_url":"https://github.com/Genaker/GoGento","commit_stats":null,"previous_names":["genaker/magento.go","genaker/gogento"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FGoGento","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FGoGento/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FGoGento/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FGoGento/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Genaker","download_url":"https://codeload.github.com/Genaker/GoGento/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Genaker%2FGoGento/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":258849008,"owners_count":22767546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-09T09:09:29.363Z","updated_at":"2025-07-04T09:31:21.129Z","avatar_url":"https://github.com/Genaker.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Magento Go API\n\nA fully functional REST API and HTTP server for Magento using Go, Echo, and GORM.\n\n## The world’s fastest framework for building e-Commerce MAGENTO websites!\n\n![image](https://github.com/user-attachments/assets/eaacc9e0-e497-4d3c-a4d9-faeadc7fd6e5)\n\n\n## Features\n- Echo web server with RESTful routing\n- Basic authentication for all endpoints\n- GORM ORM for MySQL\n- Modular structure for easy extension\n- **Concurrent-safe global product cache for fast flat product queries**\n- **Flexible product API: fetch all or specific products, with EAV attributes flattened**\n\n## Directory Structure\n```\nmagento.GO/\n  main.go\n  api/\n    product/\n      product_api.go\n    sales/\n      order_api.go\n  model/\n    entity/\n      product/\n        product.go\n        product_attribute.go\n        product_link.go\n      category/\n        category.go\n        category_product.go\n      sales/\n        order.go\n        order_grid.go\n    repository/\n      product/\n        product_repository.go\n      sales/\n        order_repository.go\n  service/\n    product/\n      product_service.go\n    sales/\n      order_service.go\n  config/\n    db.go\n    env.go\n  go.mod\n  go.sum\n  README.md\n```\n\n## Install Go (if not already installed)\nOn Ubuntu/Debian, you can install Go with:\n```\nsudo apt update\nsudo apt install golang-go\n```\nOr using snap:\n```\nsudo snap install go\n```\nAfter installation, check your Go version:\n```\ngo version\n```\n\n## Environment Variables\nSet these in a `.env` file or your environment:\n```\nMYSQL_USER=magento\nMYSQL_PASS=magento\nMYSQL_HOST=localhost\nMYSQL_PORT=3306\nMYSQL_DB=magento\nAPI_USER=admin\nAPI_PASS=secret\nREDIS_ADDR=\"\"\nREDIS_PASS=\"\"\nPORT=8080\n```\n\n## Install dependencies\n```\ncd GO\nexport GO111MODULE=on\ngo mod tidy\n```\n\n## Run the API\n```\ngo run magento.go\n```\n\n## Endpoints (all require Basic Auth)\n- `GET    /api/orders`         - List all orders\n- `GET    /api/orders/:id`     - Get order by ID\n- `POST   /api/orders`         - Create new order\n- `PUT    /api/orders/:id`     - Update order by ID\n- `DELETE /api/orders/:id`     - Delete order by ID\n- `GET    /api/products/flat`  - List all flat products (optionally for a store)\n- `GET    /api/products/flat/:ids` - List flat products for given comma-separated IDs (optionally for a store)\n\n### Product Flat API Usage\n- `GET /api/products/flat` returns all products, flattened (with EAV attributes as keys)\n- `GET /api/products/flat/1,2,3` returns only products with IDs 1, 2, 3\n- Both endpoints accept an optional store ID (see code for details)\n\n**Example:**\n```\nGET /api/products/flat/1,2,3\nResponse:\n{\n  \"products\": [\n    {\n      \"entity_id\": 1,\n      \"sku\": \"foo\",\n      ...,\n      \"stock_item\": {\n        \"item_id\": 123,\n        \"qty\": 10.0,\n        \"is_in_stock\": 1,\n        \"min_qty\": 0.0,\n        \"max_sale_qty\": 100.0,\n        \"manage_stock\": 1,\n        \"website_id\": 1\n      },\n      \"index_prices\": [\n        {\n          \"entity_id\": 1,\n          \"customer_group_id\": 0,\n          \"website_id\": 1,\n          \"tax_class_id\": 2,\n          \"price\": 99.99,\n          \"final_price\": 89.99,\n          \"min_price\": 89.99,\n          \"max_price\": 99.99,\n          \"tier_price\": 0.0\n        }\n      ]\n    },\n    ...\n  ],\n  \"count\": 3,\n  \"request_duration_ms\": 12\n}\n```\n\n## Authentication\nUse HTTP Basic Auth with `API_USER` and `API_PASS`.\n\n## Extending the App (.cursor documentation)\n\n### Add New Magento Table as an API Endpoint\n\n1. **Generate GORM Model**\n   - Use the database.mdc rules to generate a GORM model for your Magento table (see `.cursor` documentation or ask the AI: `@cursor please generate GORM model for Magento 2 table [table_name] with relationships and examples`).\n   - Place the model in `magento.GO/model/entity/`.\n\n2. **Create API Handler**\n   - Create a new file in `magento.GO/api/` (e.g., `product_api.go`).\n   - Follow the structure in `sales_order_grid_api.go` for CRUD endpoints.\n   - Use Echo's routing and middleware as described in the [Echo Routing Docs](https://echo.labstack.com/docs/routing).\n\n3. **Register Routes**\n   - In `magento.GO/main.go`, import your new API handler and register its routes with the Echo instance.\n\n4. **Test Your Endpoint**\n   - Use tools like curl or Postman to test your new API endpoint.\n   - All endpoints are protected by HTTP Basic Auth.\n\n### Echo Best Practices\n- Use Echo's `Group` feature to organize endpoints and apply middleware (see [Echo Routing](https://echo.labstack.com/docs/routing)).\n- Use context (`c echo.Context`) for request/response handling.\n- Add middleware for logging, recovery, CORS, etc., as needed.\n- See the [Echo Cookbook](https://echo.labstack.com/docs/cookbook) for advanced patterns (e.g., grouping, middleware, deployment).\n\n### GORM Model Generation (database.mdc)\n- Always include relationships and the `TableName()` method.\n- Place each model in its own file under `model/entity/`.\n- Include CRUD usage examples as comments in the model file.\n- Use the provided SQL query to get table structures for model generation.\n\n### References\n- [Echo Documentation](https://echo.labstack.com/docs)\n- [Echo Routing](https://echo.labstack.com/docs/routing)\n- [GORM Documentation](https://gorm.io/)\n- [database.mdc rules](see your .cursor documentation or ask the AI)\n\n## Repository and Service Layers\n\nThis project follows Go best practices by separating data access and business logic into repository and service layers:\n\n### Repository Layer (`model/repository/`)\n- Handles all database access (CRUD, queries) for each entity.\n- Example: `SalesOrderGridRepository` provides methods like `FindAll`, `FindByID`, `Create`, `Update`, `Delete`.\n- Keeps SQL/GORM logic out of your API and business logic.\n\n### Service Layer (`service/`)\n- Handles business logic and orchestration.\n- Calls repository methods to access data.\n- Example: `SalesOrderGridService` provides methods like `ListOrders`, `GetOrder`, `CreateOrder`, `UpdateOrder`, `DeleteOrder`.\n- Keeps business rules out of your API handlers.\n\n### Example Usage\n```go\nimport (\n    \"magento.GO/model/repository\"\n    \"magento.GO/service\"\n)\n\nrepo := repository.NewSalesOrderGridRepository(db)\nservice := service.NewSalesOrderGridService(repo)\norders, err := service.ListOrders()\n```\n\n### Summary Table\n| Layer       | Directory              | Responsibility                        |\n|-------------|-----------------------|----------------------------------------|\n| Entity      | model/entity/         | Structs, GORM tags                     |\n| Repository  | model/repository/     | DB access, queries, raw SQL            |\n| Service     | service/              | Business logic, orchestration          |\n| API/Handler | api/                  | HTTP, request/response, call services  |\n\nThis structure makes your codebase easier to maintain, test, and extend.\n\n## References\n- [Echo Routing](https://echo.labstack.com/docs/routing)\n- [GORM](https://gorm.io/)\n\n## Domain-Based Organization\n\nThis project organizes models, repositories, and services by domain (e.g., product, sales/order, category) for clarity and scalability.\n\n### Example Structure\n```\nmagento.GO/\n  model/\n    entity/\n      product/\n        product.go\n        product_attribute.go\n        product_link.go\n      category/\n        category.go\n        category_product.go\n      sales/\n        order.go\n        order_grid.go\n  model/\n    repository/\n      product/\n        product_repository.go\n      sales/\n        order_repository.go\n  service/\n    product/\n      product_service.go\n    sales/\n      order_service.go\n```\n\n### Importing with Aliases\nWhen two packages have the same name (e.g., `product` for both entity and repository), use import aliases to avoid conflicts:\n\n```go\nimport (\n    prodentity \"magento.GO/model/entity/product\"\n    productrepo \"magento.GO/model/repository/product\"\n)\n\n// Usage:\nvar p prodentity.Product\nrepo := productrepo.NewProductRepository(db)\n```\n\n### Benefits\n- **Scalability:** Add new domains without clutter.\n- **Clarity:** Quickly find all code related to a domain.\n- **Consistency:** Mirrors your API and business logic structure.\n\n## Handling Relationships: Products with Categories\n\nThis project demonstrates how to efficiently handle relationships (e.g., products with their categories) using GORM, following a clean repository-service pattern.\n\n### Model Structure\n\n**Product model references Category, StockItem, and ProductIndexPrices:**\n```go\nimport cat \"magento.GO/model/entity/category\"\n\ntype Product struct {\n    // ... other fields ...\n    Categories []cat.Category `gorm:\"many2many:catalog_category_product;joinForeignKey:ProductID;joinReferences:CategoryID\"`\n    StockItem StockItem `gorm:\"foreignKey:EntityID;references:ProductID\"`\n    ProductIndexPrices []ProductIndexPrice `gorm:\"foreignKey:EntityID;references:EntityID\"`\n}\n```\n\n### Repository Layer: Preloading Relationships\n\nThe repository is responsible for all data access, including loading related entities using GORM's `Preload`:\n\n```go\nfunc (r *ProductRepository) FindAll() ([]productEntity.Product, error) {\n    var products []productEntity.Product\n    err := r.db.Preload(\"Categories\").Find(\u0026products).Error\n    return products, err\n}\n\nfunc (r *ProductRepository) FindByID(id uint) (*productEntity.Product, error) {\n    var product productEntity.Product\n    err := r.db.Preload(\"Categories\").First(\u0026product, id).Error\n    if err != nil {\n        return nil, err\n    }\n    return \u0026product, nil\n}\n```\n\n### Service Layer: Orchestration Only\n\nThe service layer simply calls the repository and does not handle relationship logic:\n\n```go\nfunc (s *ProductService) ListProducts() ([]product.Product, error) {\n    return s.repo.FindAll()\n}\n```\n\n### API Handler: Returning Nested Data\n\nThe API handler returns products with their related categories included:\n\n```go\ng.GET(\"\", func(c echo.Context) error {\n    start := time.Now()\n    products, err := service.ListProducts()\n    duration := time.Since(start).Milliseconds()\n    if err != nil {\n        return c.JSON(http.StatusInternalServerError, echo.Map{\"error\": err.Error(), \"request_duration_ms\": duration})\n    }\n    c.Response().Header().Set(\"X-Request-Duration-ms\", strconv.FormatInt(duration, 10))\n    return c.JSON(http.StatusOK, echo.Map{\n        \"products\": products,\n        \"count\": len(products),\n        \"request_duration_ms\": duration,\n    })\n})\n```\n\n### Best Practices\n- **Repository Layer:** Handles all GORM queries and relationship loading (e.g., `Preload`).\n- **Service Layer:** Handles business logic and orchestration, not DB details.\n- **API Handler:** Returns the nested data as needed for the client.\n- **Model Layer:** Defines relationships using GORM tags.\n\n### References\n- [GORM Preload Documentation](https://gorm.io/docs/preload.html)\n- [Echo Grouping and Middleware](https://echo.labstack.com/docs/guide#grouping-routes)\n\n## Local Go Cache Database for Main Entities\n\nAll main entities (such as categories, products, attributes, etc.) must be stored in a local Go cache database. This cache acts as a persistent layer, ensuring that the application can continue to operate efficiently and reliably, even if the primary data source (such as a remote database or API) is temporarily unavailable.\n\n### Why Use a Local Cache?\n- **Performance:** Reduces latency by serving frequently accessed data from memory or local storage.\n- **Reliability:** Allows the application to function even during outages or slowdowns of the main data source.\n- **Persistence:** Ensures that critical data is not lost and can be quickly restored on restart.\n\n### Implementation Notes\n- The cache should be updated whenever entities are created, updated, or deleted.\n- On application startup, the cache should be loaded from persistent storage if available.\n- The cache can be implemented using Go's built-in data structures, with optional serialization to disk for persistence.\n\n\n## GORM SQL Query Logging\n\nYou can control GORM SQL query logging using the `GORM_LOG` environment variable:\n\n- To **enable** SQL logging (default):\n  - Omit `GORM_LOG` or set it to any value other than `off`.\n- To **disable** SQL logging:\n  ```\n  GORM_LOG=off\n  ```\n\nAll GORM logs are output to the console (stdout) using Go's standard logger. This is configured in `config/db.go`:\n\n```go\nimport (\n    \"log\"\n    \"os\"\n    \"gorm.io/gorm/logger\"\n    \"time\"\n)\n\nlogMode := logger.Info\nif os.Getenv(\"GORM_LOG\") == \"off\" {\n    logMode = logger.Silent\n}\n\ngormLogger := logger.New(\n    log.New(os.Stdout, \"\\r\\n\", log.LstdFlags),\n    logger.Config{\n        SlowThreshold: time.Second,\n        LogLevel:      logMode,\n        Colorful:      true,\n    },\n)\n```\n\n## Fetching and Flattening EAV Attributes\n\n- The repository supports fetching all product EAV attributes for a specific `store_id` (default is `0` for global).\n- Use `FetchWithAllAttributes(storeID ...uint16)` and `FetchWithAllAttributesFlat(storeID ...uint16)` to get products with all EAV attributes preloaded and flattened.\n- The flattening function can use attribute codes (from the `eav_attribute` table) as keys for a more readable API output.\n- **The flat product result also includes:**\n  - `stock_item`: Inventory/stock data for the product (qty, is_in_stock, min_qty, max_sale_qty, manage_stock, website_id, etc.)\n  - `index_prices`: Array of price index records for the product (entity_id, customer_group_id, website_id, tax_class_id, price, final_price, min_price, max_price, tier_price)\n\n\n\n## Performance Metrics (With Global Cache)\n\nThe following results were obtained using ApacheBench (ab) to benchmark the `/product/1` endpoint **with global cache enabled**:\n\n```\nab -c 100 -n 1000 http://magento.go:8080/product/1\n\nConcurrency Level:      100\nTime taken for tests:   3.363 seconds\nComplete requests:      1000\nFailed requests:        0\nRequests per second:    297.37 [#/sec] (mean)\nTime per request:       336.280 [ms] (mean)\nTime per request:       3.363 [ms] (mean, across all concurrent requests)\nTransfer rate:          1649.19 [Kbytes/sec] received\n\nPercentage of the requests served within a certain time (ms)\n  50%    284\n  66%    402\n  75%    425\n  80%    437\n  90%    575\n  95%    703\n  98%    843\n  99%    973\n 100%   1429 (longest request)\n```\n\n**Interpretation:**\n- With global cache enabled, the API handled 1000 requests at a concurrency level of 100 with no failed requests.\n- Average requests per second: **297.4** (vs. 79.6 without cache)\n- Median response time: **284 ms** (vs. 1231 ms without cache)\n- 99% of requests completed within **973 ms** (vs. 1693 ms without cache).\n\n\u003e _Enabling global cache resulted in a **~4x increase in throughput** and a **~4x reduction in median response time** for this endpoint._\n\n\u003e _Test environment: All benchmarks were run on a 2 vCPU AWS T4 instance._\n\n### Single Product Generation Time\n\nThe following results were obtained using ApacheBench (ab) to benchmark the `/product/1` endpoint with a concurrency level of 1 (single request at a time):\n\n```\nab -c 1 -n 10 http://magento.go:8080/product/1\n\nConcurrency Level:      1\nTime taken for tests:   0.011 seconds\nComplete requests:      10\nFailed requests:        0\nRequests per second:    912.83 [#/sec] (mean)\nTime per request:       1.095 [ms] (mean)\nTime per request:       1.095 [ms] (mean, across all concurrent requests)\nTransfer rate:          5062.44 [Kbytes/sec] received\n\nPercentage of the requests served within a certain time (ms)\n  50%      1\n  66%      1\n  75%      1\n  80%      1\n  90%      2\n  95%      2\n  98%      2\n  99%      2\n 100%      2 (longest request)\n```\n\n**Interpretation:**\n- With global cache enabled and a single request at a time, the API can serve a product page in about **1 ms** on average.\n- This demonstrates the extremely low latency possible for individual product requests when using the cache.\n\n## Technical Approach: Go Global Cache\n\nThe global cache in this API is designed to dramatically improve performance for frequently accessed product data, especially for flat product queries. Here's how it works:\n\n- **Concurrent-Safe In-Memory Map:**\n  - The cache is implemented as a Go `map[uint]Product` (or similar), where the key is the product ID and the value is the flattened product struct or map.\n  - This map is stored in a package-level variable, making it accessible throughout the application.\n\n- **Thread Safety with `sync.RWMutex`:**\n  - To ensure safe concurrent access (reads and writes) from multiple goroutines, the cache is protected by a `sync.RWMutex`.\n  - Read operations (`RLock`) can happen in parallel, while write operations (`Lock`) are exclusive.\n\n- **Cache Population:**\n  - On the first request (or on demand), the cache is populated by loading all relevant product data from the database and flattening EAV attributes.\n  - The cache can be refreshed or invalidated as needed (e.g., after product updates).\n\n- **Cache Usage:**\n  - When a flat product query is received, the handler first checks the cache.\n  - If the requested product(s) are present, they are returned directly from memory, bypassing the database and EAV flattening logic.\n  - This results in much faster response times and higher throughput, as shown in the performance metrics above.\n\n- **Benefits:**\n  - **Significant speedup** for repeated queries.\n  - **Reduced database load** and lower latency.\n  - **Safe for concurrent use** in a high-traffic API.\n\n- **Implementation Example:**\n  ```go\n  var (\n      flatProductCache = make(map[uint]map[string]interface{})\n      flatProductCacheMutex sync.RWMutex\n  )\n\n  func GetFlatProductFromCache(id uint) (map[string]interface{}, bool) {\n      flatProductCacheMutex.RLock()\n      defer flatProductCacheMutex.RUnlock()\n      prod, ok := flatProductCache[id]\n      return prod, ok\n  }\n  ```\n\n\u003e _This approach leverages Go's strengths in concurrency and memory management to provide a robust, high-performance caching layer for the API._\n\n## Tailwind CSS: Install \u0026 Compile Minimal Build\n\nTo use a minimal, production-ready Tailwind CSS build:\n\n1. **Install Tailwind CSS (v3):**\n   ```sh\n   npm install -D tailwindcss@3\n   ```\n\n2. **Create an input CSS file:**\n   Create a file named `input.css` in your project root with:\n   ```css\n   @tailwind base;\n   @tailwind components;\n   @tailwind utilities;\n   ```\n\n3. **Build your CSS for production:**\n   ```sh\n  npx tailwindcss -i ./input.css -o ./assets/tailwind.min.css --minify --content './html/**/*.html'\n   ```\n   - This will generate a minimal CSS file containing only the classes used in your HTML templates.\n\n4. **Reference the output in your HTML:**\n   ```html\n   \u003clink href=\"/static/tailwind.min.css\" rel=\"stylesheet\"\u003e\n   ```\n\nFor more details, see [Tailwind CSS documentation](https://tailwindcss.com/docs/installation) and [optimizing for production](https://tailwindcss.com/docs/optimizing-for-production).\n\n## Global Registry\n\nGoGento provides a thread-safe, application-wide global registry for sharing data across your application.\n\n**Usage:**\n```go\nimport \"magento.GO/core/registry\"\n\nvar GlobalRegistry = registry.NewRegistry()\n\n// Set a global value\nGlobalRegistry.SetGlobal(\"site_name\", \"MySite\")\n\n// Get a global value\nsite, ok := GlobalRegistry.GetGlobal(\"site_name\")\n\n// Delete a global value\nGlobalRegistry.DeleteGlobal(\"site_name\")\n```\n\n## Global Cache\n\nGoGento includes a thread-safe, application-wide global cache for storing frequently accessed data.\n\n**Usage:**\n```go\nimport \"magento.GO/core/cache\"\n\nvar GlobalCache = cache.GetInstance()\n\n// Set a value\nGlobalCache.Set(\"user_123_profile\", userProfile)\n\n// Get a value\nval, ok := GlobalCache.Get(\"user_123_profile\")\n\n// Delete a value\nGlobalCache.Delete(\"user_123_profile\")\n```\n\n## Request-Isolated Registry\n\nFor per-request data, use the request-isolated registry:\n\n```go\nreqReg := registry.NewRequestRegistry()\nreqReg.Set(\"user_id\", 123)\nuserID, ok := reqReg.Get(\"user_id\")\nreqReg.Delete(\"user_id\")\n```\n\n## Hello World Handler and Template Profiling\n\nGoGento includes a Hello World handler that demonstrates:\n- Using the request registry to track request start time\n- Passing execution time and template compilation time to the template\n\n\n## Singleton Pattern: Repository, Cache, and Registry\n\nGoGento uses the singleton pattern for its repositories, cache, and registry to ensure that only one instance exists and is shared across the application. This improves performance, ensures thread safety, and avoids redundant data loading.\n\n### Singleton Repository\n\nRepositories are created as singletons so that their in-memory caches (if any) are shared across all requests and handlers.\n\n**Example:**\n```go\nimport \"magento.GO/model/repository/product\"\n\n// Get the singleton instance\nrepo := product.GetProductRepository(db)\n```\n- The first call creates the repository; subsequent calls return the same instance.\n\n### Singleton Cache\n\nThe global cache is a singleton, ensuring all parts of the application use the same cache instance.\n\n**Example:**\n```go\nimport \"magento.GO/core/cache\"\n\ncache := cache.GetInstance()\ncache.Set(\"foo\", 123)\nval, ok := cache.Get(\"foo\")\n```\n\n### Singleton Registry\n\nThe global registry is also a singleton, so global data is always shared.\n\n**Example:**\n```go\nimport \"magento.GO/core/registry\"\n\nreg := registry.GetInstance() // if implemented, or use a global variable\nreg.SetGlobal(\"key\", \"value\")\n```\n\n## Shared (Global) vs. Isolated (Per-Request) Registry and Cache\n\n- **Shared (Global) Registry/Cache:**\n  - Accessible from anywhere in the application.\n  - Data persists for the application's lifetime.\n  - Use for configuration, global flags, or data that should be available to all requests.\n  - **Example:**\n    ```go\n    GlobalRegistry.SetGlobal(\"site_mode\", \"production\")\n    GlobalCache.Set(\"product_1\", productData)\n    ```\n\n- **Isolated (Per-Request) Registry/Cache:**\n  - Created fresh for each request (e.g., via middleware).\n  - Data is only visible within the current request and is discarded after the request ends.\n  - Use for request-specific data, such as timing, user context, or temporary values.\n  - **Example:**\n    ```go\n    reqReg := registry.NewRequestRegistry()\n    reqReg.Set(\"user_id\", 42)\n    userID, ok := reqReg.Get(\"user_id\")\n    ```\n\n### Summary Table\n| Type                | Lifetime         | Scope         | Thread Safe | Usage Example                  |\n|---------------------|-----------------|--------------|-------------|-------------------------------|\n| Global Registry     | Application     | All requests | Yes         | GlobalRegistry.SetGlobal(...)  |\n| Request Registry    | Per-request     | One request  | N/A         | reqReg.Set(...)                |\n| Global Cache        | Application     | All requests | Yes         | GlobalCache.Set(...)           |\n| Request Cache       | Per-request     | One request  | N/A         | reqCache.Set(...) (if needed)  |\n| Singleton Repo      | Application     | All requests | Yes         | product.GetProductRepository() |\n\n---\n\nThis pattern ensures high performance, data consistency, and safe concurrent access throughout your GoGento application.\n\n## Running as a Daemon / Background Process\n\n### 1. Run in Background with nohup\n\nYou can run the Go application in the background using `nohup` so it continues running after you log out:\n\n```sh\nnohup go run magento.go \u003e output.log 2\u003e\u00261 \u0026\n```\nOr, if you have built a binary:\n```sh\nnohup ./magento \u003e output.log 2\u003e\u00261 \u0026\n```\n- The process will keep running after you log out.\n- Output is written to `output.log`.\n\n### 2. Run as a systemd Service (Recommended for Production)\n\n1. **Build your binary:**\n   ```sh\n   go build -o magento\n   ```\n2. **Create a systemd service file** `/etc/systemd/system/magento.service`:\n   ```ini\n   [Unit]\n   Description=Magento Go API\n\n   [Service]\n   ExecStart=/var/www/html/react-luma/magento.go/magento\n   WorkingDirectory=/var/www/html/react-luma/magento.go\n   Restart=always\n   User=youruser\n   Environment=PORT=8080\n\n   [Install]\n   WantedBy=multi-user.target\n   ```\n   Replace `youruser` with the user you want to run the service as.\n\n3. **Enable and start the service:**\n   ```sh\n   sudo systemctl daemon-reload\n   sudo systemctl start magento\n   sudo systemctl enable magento\n   ```\n\n4. **Check status:**\n   ```sh\n   sudo systemctl status magento\n   ```\n\n---\n\n## Cron Jobs and CLI Usage\n\nThis project supports scheduled and on-demand background jobs using the [robfig/cron](https://github.com/robfig/cron) library and a modular CLI.\n\n### Directory Structure\n- `cron/jobs/` — Individual job implementations (e.g., `product_json.go`)\n- `cron/sheduler.go` — Cron scheduler setup and job registration\n- `cmd/cron.go` — CLI command for starting the scheduler or running jobs on demand\n\n### Running the Cron Scheduler\nTo start all scheduled cron jobs (as a foreground process):\n```bash\ngo run cli.go cron:start\n```\nOr as a background daemon:\n```bash\nnohup go run cli.go cron:start \u003e cron.log 2\u003e\u00261 \u0026\n```\n\n### Running a Single Job by Name\nYou can run a single job immediately by name:\n```bash\ngo run cli.go cron:start --job ProductJsonJob\n# or with parameters:\ngo run cli.go cron:start --job ProductJsonJob param1 param2\n```\n- The job name is case-insensitive.\n- All extra arguments are passed to the job function as parameters.\n\n### Adding New Jobs\n1. Create a new file in `cron/jobs/` and implement your job as `func(params ...string)`.\n2. Register the job in `cron/sheduler.go` for scheduled execution (wrap in a closure: `func() { jobs.YourJob() }`).\n3. Add a case for your job in `cmd/cron.go` to allow CLI execution by name.\n\n### Example Job Implementation\n```go\n// cron/jobs/product_json.go\nfunc ProductJsonJob(params ...string) {\n    fmt.Println(\"Running ProductJsonJob\", params)\n    // Your logic here\n}\n```\n\n### Example CLI Command\n```bash\ngo run cli.go cron:start --job ProductJsonJob 123 store2\n```\n\n### Production Daemon (systemd)\nFor production, create a systemd service to run the scheduler as a daemon. See the project documentation for a sample unit file.\n\n### Example: Adding and Using a CronJobs\n\n1. **Register the job in `config/cron.go`:**\n   ```go\n   var CronJobs = map[string]CronJob{\n       \"productjsonjob\": {Schedule: \"0 * * * *\", Job: jobs.ProductJsonJob},\n       \"testjob\":        {Schedule: \"@every 10s\", Job: jobs.TestJob},\n   }\n   ```\n   You can add more Jobs here \n\n2. **Run the test job manually:**\n   ```bash\n   go run cli.go cron:start --job TestJob\n   # or with parameters:\n   go run cli.go cron:start --job TestJob foo bar\n   ```\n\n3. **Scheduled run:**\n   - When the scheduler is started, `TestJob` will run every 10 seconds automatically.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgenaker%2Fgogento","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgenaker%2Fgogento","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgenaker%2Fgogento/lists"}