# AGENTS.md — PCDesigner / Web 2 Print Solution

This file is the primary memory for Codex (Code + Chat) when working on this repository. It is loaded automatically into every session. Keep it current.

> Mục đích: Cho phép Codex trả lời chính xác các câu hỏi về kiến trúc, phát triển tính năng, audit bảo mật/performance, hỗ trợ kỹ thuật, redesign UX/UI, lập roadmap, và phân tích mô hình kinh doanh / sản phẩm niche dựa trên codebase này.

---

## 1. Product Identity

- **Plugin name (header):** PCDesigner — Web 2 Print Solution
- **WordPress.org slug (deploy target):** `printcart-integration` — defined in `.github/workflows/deploy.yml` (`SLUG:` env). Registered 2022-06-18 by wp.org user `printcart`, currently on 2.5.3. **This is the slug all wp.org queries must use.**
- **Text domain (i18n only, DO NOT confuse with wp.org slug):** `web-to-print-online-designer` — kept as-is to avoid regenerating every `.po/.mo` and breaking existing translations. It happens to collide with an unrelated wp.org submission `web-to-print-online-designer` that `netbaseteam` closed 2019-09-08 for guideline violation; that closed listing has nothing to do with this codebase or its release channel.
- **Internal namespace prefix:** `nbdesigner` / `nbd_` / `Nbdesigner_*` (legacy “Netbase Designer”)
- **Vendor:** Printcart (Netbase Team)
- **Current version:** 2.5.3 (header + `NBDESIGNER_VERSION` + `NBDESIGNER_NUMBER_VERSION=253` + `readme.txt` Stable tag — all four aligned since the 2.5.3 security release)
- **License:** GPLv3
- **Stack:** PHP 5.6+ (target 7.4–8.2), WordPress 4.6+, WooCommerce 3.0+ (HPOS-compatible)
- **SaaS coupling:** `https://api.printcart.com/v1` + `https://dashboard.printcart.com`

Always assume the plugin is being installed inside a live WooCommerce store; never break checkout, cart, or order flows.

---

## 2. High-level Architecture

```
WordPress + WooCommerce
        |
   nbdesigner.php  (bootstrap, ~40 require_once)
        |
   includes/   ← all PHP logic (84 core files)
        |
   ├── class.nbdesigner.php          (7,535 LOC — main hub, AJAX, WC hooks)
   ├── class-api.php                 (REST: /nbd/v1/*)
   ├── class-printcart-*.php         (Printcart Cloud bridge + WC REST)
   ├── class-3d-preview.php          (Three.js GLTF preview)
   ├── class.product-builder.php     (admin canvas builder)
   ├── class.my.design.php           (My Account endpoint)
   ├── class.templates-global.php    (v2.4.6+ global templates)
   ├── class.template-mapping.php    (v2.4.8+ template ↔ product modal)
   ├── class.advanced.upload.php     (image/PDF upload pipeline)
   ├── class.design.guideline.php    (bleed / safe zone / DPI)
   ├── class.artwork.actions.php     (approve/reject + email)
   ├── class.request-quote.php       (quote workflow)
   ├── launcher/                     (designer marketplace)
   ├── background-processes/         (async PDF export)
   ├── oauth/                        (Instagram, Unsplash)
   ├── options/                      (admin + frontend settings)
   └── settings/                     (tab pages)
        |
   assets/      JS (Fabric 2.6, AngularJS 1.6, Three.js, Firebase, jQuery UI)
   lib/         TCPDF, FPDI, DOMPDF, TCPDI, JWT, eval-math
   vendor/      Composer: AWS SDK, Google Cloud Storage, Firebase JWT, Guzzle, Flysystem
   templates/   WC-overridable front-end templates
   views/       Admin + editor partials (3D, faq, product-builder, modern, vista)
   data/        ICC profiles (16), default fonts/cliparts/patterns, language JSON
```

Detailed map: `docs/ARCHITECTURE.md`.

---

## 3. Bootstrap & Constants

`nbdesigner.php` defines (do not change without migration plan):

| Constant | Path |
|---|---|
| `NBDESIGNER_DATA_DIR` | `wp-content/uploads/nbdesigner/` |
| `NBDESIGNER_FONT_DIR` | `…/fonts` |
| `NBDESIGNER_ART_DIR` | `…/cliparts` |
| `NBDESIGNER_DOWNLOAD_DIR` | `…/download` |
| `NBDESIGNER_CUSTOMER_DIR` | `…/designs` |
| `NBDESIGNER_PDF_DIR` | `…/pdfs` |
| `NBDESIGNER_TEMP_DIR` | `…/temp` |
| `NBDESIGNER_SUGGEST_DESIGN_DIR` | `…/suggest_designs` |
| `NBDESIGNER_TEMPLATES` | post type `nbdesigner_templates` |
| `NBDESIGNER_CATEGORY_TEMPLATES` | taxonomy |
| `NBDESIGNER_PAGE_STUDIO` | slug `design-studio` |
| `NBDESIGNER_PAGE_CREATE_YOUR_OWN` | slug `create-your-own` |
| `NBDESIGNER_ENABLE_NONCE` | toggle nonce checks (default TRUE) |
| `NBDESIGNER_MODE_DEV` / `_DEBUG` | both FALSE in production |

When introducing a new path, define it as a `pc_define()` constant in `nbdesigner.php` and create the directory in `class-install.php`.

---

## 4. Database

Custom tables (created in `class-install.php`):

- `{wp_prefix}nbdesigner_templates` — product templates (priority, hit, sales, vote, tags, colors)
- `{wp_prefix}nbdesigner_mydesigns` — saved customer designs (state: draft/saved)
- `{wp_prefix}nbdesigner_user_designs` — designer marketplace designs
- `{wp_prefix}nbdesigner_options` — product builder fields (JSON serialized)
- `{wp_prefix}pcs_brand_templates` — B2B store ↔ private template library entries sourced from global templates, local templates, or designer-created templates
- `{wp_prefix}pcs_brand_media` — B2B company-owned media such as logos, approved images, patterns, brand docs, and production references

Custom post types: `nbdesigner_templates`, `nbd_faq`, `nbc-macro`.
Taxonomy: `nbdesigner_category_templates`.

Critical post meta on WC products:

- `_nbdesigner_enable` — toggle designer on product
- `_designer_setting` — serialized array of canvas/sides/dimension/bleed
- `_nbes_settings` — 3D preview (`td_preview`, `td_folder_name`, `td_custom_mesh_name`)
- `_nbdg_files` — guideline files

Cart/order item meta:

- `nbd_item_key` — links cart/order item ↔ design folder under `NBDESIGNER_CUSTOMER_DIR`

When adding fields, prefer WooCommerce-native meta (cart, order item meta) over options to keep HPOS compatibility.

---

## 5. APIs

### Internal REST
- `GET /wp-json/nbd/v1/gallery/generate` — generate gallery images from base64-encoded request

### WooCommerce REST extension
- `GET /wp-json/wc/v3/printcart/pc-auth` — saves Printcart credentials (sid, secret, unauth_token)

### AJAX (action names — `wp-admin/admin-ajax.php`)
Editor: `nbd_save_customer_design`, `nbd_save_draft_design`, `nbd_convert_files`, `nbd_frontend_download_pdf`, `nbd_frontend_download_jpeg`, `nbd_crop_image`, `nbd_upload_pdf_as_bg_image`.
Product: `nbd_get_product_info`, `nbd_get_product_config`.
Resources: `nbdesigner_get_qrcode`, `nbdesigner_get_facebook_photo`, `nbd_get_freepik_data`, `nbd_get_pexels_data`, `nbd_get_instagram_token`.
Admin: `nbdesigner_save_design_to_pdf`, `nbdesigner_update_all_product`, `printcart_generate_key_api`, `printcart_check_connection_dashboard`.

### External
- Printcart Cloud (`api.printcart.com/v1`) — license, AI, sync, marketplace
- AWS S3 / Google Cloud Storage / Dropbox — design + PDF storage
- Firebase Realtime DB / JWT — live chat
- Google Fonts, Instagram OAuth, Unsplash, Pexels, Freepik

When adding a new endpoint, follow `class-api.php`’s pattern and **always** verify nonce + capability + sanitize.

---

## 6. WooCommerce Integration Points

Hooks already wired (see `class.nbdesigner.php`):

- `woocommerce_before_single_product`, `woocommerce_before_add_to_cart_button`, `woocommerce_after_add_to_cart_button`
- `woocommerce_add_cart_item_data`, `woocommerce_get_cart_item_from_session`, `woocommerce_after_cart_item_name`
- `woocommerce_before_calculate_totals`, `woocommerce_order_again_cart_item_data`
- `woocommerce_checkout_create_order_line_item`, `woocommerce_checkout_order_processed`
- `woocommerce_admin_order_actions`, `woocommerce_hidden_order_itemmeta`
- `woocommerce_product_after_variable_attributes`, `woocommerce_save_product_variation`

HPOS declared in `nbdesigner.php` via `FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true)`. Never read order meta directly from `posts`/`postmeta` — always go through `wc_get_order()` / `$order->get_meta()`.

---

## 7. Front-end Stack

**Designer canvas:** Fabric.js 2.6.0 + custom plugins `fabric.curvedText.js`, `fabric.removeColor.js`.
**Admin UI:** AngularJS 1.6.9 (legacy — do not extend; new admin features should use vanilla JS or a lightweight isolated React island).
**3D preview:** `assets/js/3d/` — Three.js module + GLTFLoader + OrbitControls + worker.
**Other:** jQuery UI, Bootstrap, Lodash, Snap.svg, html2canvas, opentype.js, fontfaceobserver, Firebase JS SDK, Chart.js, moment.js, perfect-scrollbar.

Build tooling (`assets/package.json`) is gulp 3 + node-sass + webpack 4 (legacy). Migration plan in `docs/PERFORMANCE.md`.

---

## 8. Background Processing

- `includes/background-processes.php` + `includes/background-processes/export-pdf.php` use `WP_Background_Process` for PDF export.
- `launcher/class.generate.preview.process.php` handles marketplace preview generation.
- WP Cron jobs:
  - `nbdesigner_lincense_event` — daily license validation (note: typo `lincense` is intentional in code; do not rename without migration)
  - `nbd_w3_flush_cache` — flush W3 Total Cache when applicable

Never run heavy image / PDF work synchronously in an AJAX handler — push to a background process.

---

## 9. Security

Known historical CVEs (now patched, but stay vigilant):

- v2.4.0 (2025-06) — Arbitrary File Upload
- v2.4.1 (2025-07) — SQL Injection
- v2.4.8 (2026-03) — SiteGround false-positive (nulled), MIME inline check, font URL guard, robust template check

Mandatory checklist for any change touching `$_POST` / `$_GET` / `$_FILES`:

1. `check_ajax_referer()` or `wp_verify_nonce()` (respect `NBDESIGNER_ENABLE_NONCE`) — nonce is CSRF-only, NOT auth (`nbd_check_use_logged_in` leaks it to nopriv)
2. `current_user_can()` for capability gating on every state-changing action
3. For folder-name / file-key sinks: **use `nbd_sanitize_item_key()`** (defined in `includes/class-helper.php`) — never trust `wc_clean()` / `sanitize_text_field()` alone for filesystem paths
4. For URL fetch sinks: **use `nbd_validate_remote_url()`** then `wp_safe_remote_get()` — never `curl_exec()` on raw input, never `@copy()` (it honours `file://`)
5. `wp_check_filetype_and_ext()` + magic byte check for uploads; whitelist image extensions when saving
6. `$wpdb->prepare()` with `%d` / `%s` placeholders for any SQL; whitelist column names (`esc_sql` does NOT protect identifiers)
7. `esc_html()` / `esc_attr()` / `esc_url()` on output. For JS-string embed use `wp_json_encode()`, NOT `esc_js()` (esc_js mangles `&` in URLs)

Full audit playbook + practical 3-layer workflow (nopriv sweep → Semgrep → PCP): `.Codex/skills/pcd-security-audit/SKILL.md`.
Release playbook once fixes ready: `docs/RELEASE.md` and skill `pcd-release`.

---

## 10. Coding Conventions

- **Class naming is inconsistent**: `class-foo.php` and `class.foo.php` both exist. New files: prefer `class-foo.php` (WP-style).
- **Function/method prefixes:** `nbdesigner_` (legacy), `nbd_` (newer), `printcart_` (cloud bridge), `pc_` (helpers).
- **Indentation:** 4 spaces, no tabs.
- **PHP version target:** keep `PHP 7.4` syntax baseline (avoid 8.0-only features) until min version bump is announced.
- **Vietnamese / English:** code + comments are English. User-facing strings go through `__('...', 'web-to-print-online-designer')`.
- **Do not commit minified JS/CSS without source.**
- **No new AngularJS code.** New admin UI = vanilla JS or React island, mounted into a shadow root.

---

## 11. How to Run / Test Locally

There is no provided dev container. Recommended setup:

```bash
# Use wp-env or Local by Flywheel
wp-env start
wp plugin activate web-to-print-online-designer
```

Smoke checks before any PR:

1. Plugin activates without warning on a clean WP + WC.
2. Setup wizard (`/wp-admin/admin.php?page=nbd-setup`) finishes.
3. Enable “Online Design” on a product, frontend canvas loads.
4. Add to cart → checkout → order shows the design thumbnail.
5. PDF download from order detail works (sync + async).

For UI changes always boot a real browser and verify on mobile viewport.

---

## 12. Skills available to Codex

The `.Codex/skills/` directory holds task-specific skills. Trigger by purpose:

| Skill | When to use |
|---|---|
| `pcd-codebase-map` | Locate a feature / class / hook quickly |
| `pcd-feature-development` | Implement a new feature end-to-end |
| `pcd-bug-triage` | Reproduce, isolate, and fix a bug |
| `pcd-security-audit` | Review code touching input / SQL / uploads. Contains the practical 3-layer audit workflow (nopriv sweep → Semgrep → PCP) validated on the 2.5.3 security release. |
| `pcd-release` | Ship a new version to wordpress.org SVN — version-marker check, tag + push, verify SVN, troubleshoot E215004 / workflow-not-triggered / em-dash log message. |
| `pcd-performance-audit` | Find slow queries, large assets, blocking AJAX |
| `pcd-ux-redesign` | Refactor an editor / admin screen |
| `pcd-roadmap-planner` | Translate goals into a versioned roadmap |
| `pcd-tech-support` | Diagnose a customer issue from logs / settings |
| `pcd-business-analyst` | Analyse pricing, churn, monetisation |
| `pcd-niche-strategist` | Spin off a niche product from the core |

Each skill has its own `SKILL.md` with concrete steps, file paths, and acceptance criteria.

---

## 13. Working Agreement With Codex

When the user gives an open-ended request:

1. Restate the goal in 1 sentence.
2. Pick the matching skill (above) and load it with `Skill` tool when appropriate.
3. For multi-step work, call `TodoWrite` and keep exactly one task `in_progress`.
4. Read `docs/ARCHITECTURE.md` before changing more than one file in `includes/`.
5. Never delete files in `vendor/`, `lib/`, or `data/_icc/` without explicit request.
6. For UI work, prefer editing `views/` / `templates/`; do not introduce new top-level folders without asking.
7. Commits go to the branch the user specified; do not push to `main`.

---

## 14. Glossary

- **Studio** — main front-end editor (Fabric canvas + side panels)
- **Launcher** — internal name for the designer marketplace module
- **Vista** — single-column layout variant (legacy A/B)
- **Modern** — newest editor layout (`views/modern/`, `assets/js/app-modern.min.js`)
- **Side** — one face / page of a designable product (e.g. front + back)
- **Bleed / Safe zone** — print margins enforced by `class.design.guideline.php`
- **Output** — final PNG / JPEG / PDF generated for production printing
- **Tier** — Printcart Cloud subscription level gating premium features

---

## 15. Pointers

- Detailed architecture: `docs/ARCHITECTURE.md`
- Dev setup + conventions: `docs/DEVELOPMENT.md`
- Public roadmap: `docs/ROADMAP.md`
- Monetisation: `docs/BUSINESS-MODEL.md`
- Niche product playbook: `docs/NICHES.md`
- UX redesign principles: `docs/UX-UI-PRINCIPLES.md`
- Performance program: `docs/PERFORMANCE.md`
- Customer support runbook: `docs/SUPPORT-PLAYBOOK.md`
- WP.org release playbook: `docs/RELEASE.md`
- SVN deploy troubleshooting: `docs/SVN-DEPLOY-TROUBLESHOOTING.md`
- Store install stats (which system counts what — wp.org bracket vs Solution.printcart marketplace vs Printcart Cloud RDS): memory `reference-store-install-stats` + skill `printcart-store-lookup` (global). Use this before quoting any "active install" number.
- WP.org slug clarification (deploy slug `printcart-integration` vs collision with the closed 2019 listing that shares the text-domain string): memory `reference-wporg-slug`.

---

## 16. Printcart Connect / License Architecture (v2.5.4) — ADDED 2026-07-22

> Captures the connect/license flow, the dashboard-URL migration, and a critical two-surface finding. Details in `docs/ARCHITECTURE.md` §13. Verified in the v2.5.4 session.

### 16.1 Connect / license flow

- **Store credentials:** Sid (`pcsia_` + 64 hex), Secret (`pcsup_` + 64 hex), Unauth Token.
- **Validation:** `GET /v1/stores/store-details` with **HTTP Basic `base64(sid:secret)`**. The response `data.unauth_token` (or `unauth_access_token` / `api_key`) must match the stored token. Requests send `?include=credentials`.
- **Option keys:** `nbdesigner_printcart_api_sid` | `_secret` | `_unauth_token` | `_access_token`, plus new `nbdesigner_printcart_store_id`.
- **v2.5.4 hardening** (`includes/class-printcart-api.php`, `class-printcart-general.php`): NEVER delete saved credentials on `WP_Error` / timeout / non-2xx. The old `delete_option` on a failed check caused mass disconnects — root cause of the "update Printcart API keys" + missing-order-designs incidents. Access token is cleared only on a definitive **401/403**. Self-heal: if sid+secret present but unauth token missing, re-fetch via Basic auth and restore. Reconnect maps to the EXISTING store by matching `shop_url` (never creates a duplicate).
- **Backend dependency:** relies on backend commit `ab0d8bf6` (StoreResource `isLegacyBasicStoreDetailsRequest`), which returns credentials for Basic-auth store-details callers.

### 16.2 Dashboard URL (retire `dashboard.printcart.com`)

- `NBD_Printcart_API::get_dashboard_url($path='')` — filterable (`nbd_printcart_dashboard_url`, or PHP const `NBD_PRINTCART_DASHBOARD_URL`), default `https://www.printcart.com`. API base also filterable via const `NBD_PRINTCART_API_URL` (default `https://api.printcart.com/v1`) — useful for local testing.
- **Route map:** Connect / copy creds → `/en/integration/wordpress`; API & Keys → `/en/settings` (NOT `/settings/api-keys`); login/register → `/en/login` · `/en/register`; upgrade/billing → `/en/payment`; help → `https://docs.printcart.com/integrations/woocommerce`. AVOID `/en/integration` (404, no index) and `/settings/api-keys` (does not exist).

### 16.3 ⚠️ Surface architecture — TWO connect UIs, only ONE renders

- **REAL surface (what merchants see):** the AngularJS card in `views/printcart-general.php` ("Connect the Printcart Dashboard to your site" — Account/Store sections, Sid/Secret/Unauth, "Connect to Dashboard" + "Change API key" buttons), driven by `assets/js/printcart-general.js`. Shown on `admin.php?page=nbdesigner` and reused as the first-run **setup wizard** connect step (`includes/class-setup-wizard.php`).
- **LEGACY / NON-RENDERED:** the WP-Settings block in `includes/class-printcart-settings.php` (hooked via the `nbdesigner_general_settings` filter, `printcart_settings_blocks`). Despite `init()` running, this block does NOT appear on `page=nbdesigner` or `page=nbdesigner_settings` in the pc-designer build — confirmed by full-HTML dumps (`nbdesigner_printcart_api_sid` input and `pcd-*` markers absent from the rendered pages).
- **RULE:** any redesign or change to the connect/credential UX MUST target `views/printcart-general.php` + `printcart-general.js` (+ the wizard), NOT `class-printcart-settings.php`. Editing `class-printcart-settings.php` has no visible effect.

### 16.4 Status

Plugin **v2.5.4 committed LOCAL** (`4662fe1`), NOT pushed / NOT deployed to wp.org. The credential-UX visual redesign currently sits (ineffectively) in `class-printcart-settings.php` and still needs to be applied to the real Angular surface (§16.3).
