# etechflow/module-faq

> Help-Centre / FAQ module for Magento 2 with categories, slug-based detail pages, search, related articles, REST API, and admin management. Theme-agnostic — works on Hyvä, Luma, and any custom theme.

`composer require etechflow/module-faq`

Canonical URL: https://packagento.com/etechflow/module-faq

## At a glance

- **Vendor**: etechflow (https://packagento.com/etechflow.md)
- **Latest version**: 1.2.1 — released 2026-06-22
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/etechflow/module-faq and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require etechflow/module-faq:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Help-Centre / FAQ module for Magento 2 with categories, slug-based detail pages, search, related articles, REST API, and admin management. Theme-agnostic — works on Hyvä, Luma, and any custom theme.

## README


A self-contained FAQ / knowledge-base module with public detail pages,
admin management, REST API, and full theme/branding configurability.
Works on **Magento Open Source**, **Adobe Commerce**, with **Hyvä** or
**Luma** themes — no Tailwind, no Alpine, no PageBuilder dependencies.

```
┌─────────────────────────────────────────────────────────────┐
│   Help Centre & FAQs                                        │
│                                                             │
│   [Search articles...] [Search]                             │
│                                                             │
│   ┌──────────┐ ┌──────────┐ ┌──────────┐                    │
│   │ ORDERS   │ │ RETURNS  │ │ DELIVERY │   …                │
│   │ ▸ q1     │ │ ▸ q1     │ │ ▸ q1     │                    │
│   │ ▸ q2     │ │ ▸ q2     │ │ ▸ q2     │                    │
│   └──────────┘ └──────────┘ └──────────┘                    │
└─────────────────────────────────────────────────────────────┘

/faqs                            → listing of all categories
/faqs/orders/can-i-return-x      → detail page with related articles
/rest/V1/etechflow/faq          → REST: all categories with items
```

### Features

- **Categories** with display label, URL identifier, icon, sort order, active toggle.
- **Q&A items** with auto-generated slugs (unique per category), subtitle, rich answer body, SEO meta title + description.
- **Slug-based detail pages** at `/faqs/{category}/{slug}` — breadcrumb, left-rail category navigation, main content card, right-rail (search/helpful/contact), related articles grid.
- **Listing page** at `/faqs` — categories grid (desktop) + mobile accordion, in-page search filter, per-category modal showing all questions.
- **REST API** — three read-only public endpoints returning JSON, no auth required.
- **System Configuration** for branding (colours, font), hero (image + copy), contact details, and display toggles — no template hacking needed.
- **Theme-agnostic** — vanilla CSS scoped under `.kfaq-*`, vanilla JS (no framework). Renders identically on Hyvä and Luma.
- **Demo data** (opt-in) seeds 9 categories + 36 sample questions for a working out-of-the-box page.

### Requirements

| Requirement | Version |
|---|---|
| Magento | 2.4.4 → 2.4.8 (Open Source or Adobe Commerce) |
| PHP | 8.1, 8.2, or 8.3 |
| Frontend theme | Any (Hyvä, Luma, blank, custom) |

### Quick start

#### Manual install (no Composer)

```bash
cd <magento-root>
mkdir -p app/code/Etechflow/Faq
## unzip the package into the directory above (so registration.php sits at app/code/Etechflow/Faq/registration.php)
unzip Etechflow_Faq-v1.0.0.zip -d app/code/Etechflow/Faq

bin/magento module:enable Etechflow_Faq
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
```

#### Composer install (path repository)

```bash
## In <magento-root>/composer.json add:
##   "repositories": [{ "type": "path", "url": "../Etechflow_Faq" }]
composer require etechflow/module-faq:^1.0
bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush
```

#### Verify

- Admin → **Content → FAQs → Categories** — lists 0 rows (or 9 if demo data enabled).
- Admin → **Stores → Configuration → EtechFlow → FAQ** — defaults are populated.
- Storefront → `/faqs` — renders the listing page.

### Documentation

| File | What's inside |
|---|---|
| [INSTALL.md](INSTALL.md) | Manual + Composer install, troubleshooting, post-install cleanup, demo data toggle |
| [USAGE.md](USAGE.md) | Admin walkthrough, REST API, system-config reference, customising the look, layout extension points |
| [CHANGELOG.md](CHANGELOG.md) | Version history |
| [LICENSE](LICENSE) | MIT |

### Module structure

```
app/code/Etechflow/Faq/
├── Api/                                 service contracts
│   ├── Data/{Category,Item}Interface.php
│   └── FaqRepositoryInterface.php
├── Block/                               view blocks
│   ├── Config.php                       — reads Stores → Configuration values
│   ├── Listing.php                      — /faqs landing
│   └── View.php                         — /faqs/{cat}/{slug} detail
├── Controller/
│   ├── Adminhtml/{Category,Item}/*.php  — admin CRUD
│   ├── Index/Index.php                  — /faqs route
│   ├── Router.php                       — matches /faqs/{cat}/{slug}
│   └── View/Index.php                   — detail-page controller
├── Model/                               models, resource models, source models, repository
├── Setup/Patch/Data/
│   ├── BackfillUrlKeys.php              — populates slugs for legacy rows
│   └── InstallDemoData.php              — opt-in seed (9 cats + 36 items)
├── Ui/                                  admin form/listing data providers + action columns
├── etc/                                 module config (acl, di, db_schema, system.xml, etc.)
├── view/
│   ├── adminhtml/                       admin layouts + UI components
│   └── frontend/                        layouts + templates (listing.phtml, view.phtml)
├── composer.json
├── registration.php
└── *.md, LICENSE
```

### Support

Open an issue or reach t

_(README truncated for .md surface. Full README on https://packagento.com/etechflow/module-faq.)_

## Changelog


All notable changes to **Etechflow_Faq** will be documented in this file. The
format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### [1.1.0] — 2026-06-05 — Stripe portal licensing + admin gate + storefront/REST gating + Hero image upload

#### Added

- **Stripe portal subscription licensing.** Adds the SP-XXXX subscription-key flow — same pattern shipped on `ETechFlow_BackorderEtaDisplay` v1.3.0, `ETechFlow_NextDayEligibility` v1.8.0, and `ETechFlow_ShippingTableRates` v1.2.0. Three plan tiers (Starter $9/mo, Professional $19/mo, Enterprise $49/mo) with in-admin Stripe Checkout, automatic key activation, portal-validated server-IP enforcement, IP-block auto-restore, and 48-hour offline grace when the portal is unreachable. HMAC per-module + bundle keys (`LICENSING_PROTOCOL.md`) also accepted for offline / bundle activation.
- **`Model/LicenseValidator.php`** (greenfield) — 5-arg constructor with tri-state `validateViaPortal(): ?bool` per the enforcement contract. `MODULE_ID = 'faq'`, unique `SECRET_FRAGMENTS`, shared `BUNDLE_SECRET_FRAGMENTS`.
- **License gate page** under **Content → FAQs → License & Plans** with dark plan-cards UI and a Stripe Checkout button.
- **Module Status banner** at the top of Stores → Configuration → ETECHFLOW → FAQ / Help Centre. Always-expanded, 5-state (info / warning / success) — tells the merchant exactly why the module is locked (or that it's active).
- **Admin gating plugin** (`Plugin/Adminhtml/LicenseGatePlugin.php`) — every admin Item / Category / Pending / Categoryimage controller redirects to the license gate when not licensed.
- **Storefront gating plugin** (`Plugin/Controller/StorefrontGatePlugin.php`) — every `/faqs/*` request forwards to Magento's noroute (clean 404) when not licensed.
- **REST API gating plugin** (`Plugin/Api/FaqRepositoryGatePlugin.php`) — all 12 read methods on `FaqRepositoryInterface` return empty arrays / null when not licensed. No content leakage via API.
- **`<payment>` config group** for Stripe `sk_test`/`sk_live`/currency (Encrypted backend model on the secret key).
- **`<license>` config group** with `production_environment`, `license_key`, `bundle_license_key` (obscure + Encrypted), `portal_url`, and auto-managed `issued_key` + `issued_at` + `ip_blocked` fields.

#### Changed

- **Hero image path → image upload widget.** Replaced the plain text input with Magento's `type="image"` field + `backend_model="Image"`. Files now upload to `pub/media/etechflow_faq/hero/` directly through the admin UI. `Block\Config::getHeroImageUrl()` updated to resolve bare filenames, scope-prefixed paths (`default/foo.jpg`), and legacy plain paths — fully backward compatible.

#### Migration

```
composer update etechflow/module-faq
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
```

After upgrade, on a production host the module is **locked by default**. Go to **Stores → Configuration → ETECHFLOW → FAQ / Help Centre → License & Plans** and either paste an existing SP-XXXX / HMAC / bundle key, or click "Select Plan & Pay" to buy a subscription via Stripe.

Dev hosts (localhost, `*.test`, `*.local`, `staging.*`, `*.ngrok-free.dev`, etc.) auto-bypass licensing. Production hosts that aren't auto-detected can opt out with **Production Environment = No**.

#### Notes

- `License Portal URL` defaults to `https://license-service.etechflow.com/license/validate` (the eTechFlow portal). For production, change this when eTechFlow publishes the final portal URL.
- Portal IP-revoke + suspend lock the module within ~60 seconds (`CACHE_TTL_REJECT` = 60). Re-activating in the portal restores the module within the same window via `issued_key` auto-restore.

---

### [1.0.0] — 2026-05-16

#### Added
- Initial public release.
- Admin: Categories CRUD (label, identifier/

_(Changelog truncated for .md surface. Full history on https://packagento.com/etechflow/module-faq.)_

## Recent Versions

| Version | Released |
|---|---|
| 1.2.1 | 2026-06-22 |
| 1.2.0 | 2026-06-22 |
| 1.1.3 | 2026-06-16 |
| 1.1.2 | 2026-06-15 |
| 1.1.1 | 2026-06-15 |
| 1.1.0 | 2026-06-05 |
| 1.0.0 | 2026-06-05 |

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | >=103.0 |
| magento/module-backend | >=102.0 |
| magento/module-config | >=101.0 |
| magento/module-store | >=101.0 |
| magento/module-ui | >=101.0 |
| php | ~8.1.0\|\|~8.2.0\|\|~8.3.0\|\|~8.4.0 |

## Quality

Latest release (1.2.1) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | not tested |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 639 | 9 errors, 630 warnings (ruleset: Magento2) — 222 auto-fixable with phpcbf |
| PHPMD | Warning | 43 | 43 rule violations (UnusedFormalParameter:21, NPathComplexity:6, EmptyCatchBlock:5, CyclomaticComplexity:4, MissingImport:3) |
| Cpd | Pass | 0 |  |
| Composer validate | Info | 6 | valid; 6 advisory notes (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 39 | 39 | – | – |
| 2.4.8 | – | 39 | 39 | – |
| 2.4.9 | – | – | 39 | N/A |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["etechflow/module-faq"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

etechflow is a Magento 2 vendor on Packagento. See https://packagento.com/etechflow.md for their full catalogue.

