@extends('layouts.app') @section('content') {{-- Hero --}}
{{-- Left: text --}}
Add-On Plugin

Agency Pulse Invoice Archive & Backup

Extends the Agency Pulse Invoice ecosystem with automatic, incremental backup and restore capabilities for invoices. Integrates with an external secure & encrypted backup server console to provide incremental backups. The backup management console allows monitoring backup status, configuring settings, and sending restore and archive commands to the site.

Agency Pulse Invoice Archive & Backup Plugin
{{-- Feature Groups --}}
{{-- Automatic Backup Engine --}}

📤 Automatic Backup Engine

  • Trigger-Based Backup: Backups are enqueued automatically on three configurable triggers per invoice — post save, invoice status transition, and PDF generation — each independently enabled or disabled in settings.
  • Non-Blocking Architecture: Backup triggers never execute the HTTP send inline. Every trigger call enqueues the entity for processing by the queue cron job, ensuring backup activity never delays the admin or client-facing request that caused it.
  • Content Change Detection: Before every send, the plugin computes a SHA-256 hash of the serialised payload and compares it against the stored hash from the last successful send. Identical payloads are silently skipped — no redundant network requests.
  • Create vs. Update Routing: On the first successful push, the server returns a remote ID which is stored in post meta. All subsequent pushes for the same entity include the remote ID, allowing the server to route the request as an update rather than a new record.
  • Master Enable/Disable Switch: A global on/off toggle disables all backup triggering site-wide without requiring deactivation of the plugin or loss of any stored meta or configuration.
  • Manual Sync Request: A sync request can be triggered manually for any reason to ensure the external store is up to date after a period of disconnection.
{{-- Addon-Aware Payloads --}}

📦 Addon-Aware Payloads

  • Core Invoice Payload: Every invoice backup payload includes the post fields, all _invoice_* meta, line items, and the PDF version history array.
  • Portal Section: When Agency Pulse Portal is active, the payload includes a snapshot of the linked portal client’s record — email, all _client_* meta, and any invoice templates attached to the client.
  • Multi-Currency Section: When Agency Pulse Multi-Currency is active, the payload captures the invoice currency, base currency, locked exchange rate, and a snapshot of the site-wide currency configuration at backup time.
  • Enhancements Section: When Agency Pulse Invoice Enhancements is active, the payload includes the company assignment (name + index), external file map, external image references, and the hide-files-until-paid flag.
  • Products Section: When Agency Pulse Products is active, the payload includes a snapshot of any linked order meta and, for each line item referencing a product, a point-in-time snapshot of the product record.
  • Secure Sign Section: When Agency Pulse Secure Sign is active and the invoice has been signed, the payload includes the S3 path, PDF hash, signing timestamp, and client IP of the signed PDF.
  • Active Plugin Registry: Every payload includes a plugins_active array listing which addon slugs contributed sections, allowing the server and future restore handlers to interpret the payload structure correctly regardless of which addons are installed on the restore target.
{{-- Backup Queue and Retry --}}

Backup Queue & Retry

  • Options-Based Queue: The backup queue is stored as a single WordPress option, requiring no custom database table. Items are serialised as a FIFO array; duplicate entries for the same entity are deduplicated on enqueue, keeping only the most recent trigger reason.
  • Queue Processor Cron: A WP-Cron job fires every minute, dequeues up to 10 items, builds each payload, and sends it. The one-minute interval ensures low latency between a save event and the backup reaching the server.
  • Configurable Retry Limit: The maximum number of retry attempts before a send is marked as permanently failed is configurable in settings (default: 3, range: 1–10). The attempt counter increments on each failure and resets to zero on success.
  • Permanent Failure Status: Once the retry limit is reached, the entity is marked failed_permanent. It is no longer automatically retried, preventing an unreachable server from consuming queue capacity indefinitely.
  • Archive Sends Bypass Queue: Archive operations (trash/delete events) are sent immediately rather than queued, because archive commands are time-sensitive and must reach the server before the local record is removed.
  • Configurable Catch-Up Schedule: A separate catch-up cron job runs on a configurable interval (hourly, daily, or weekly). It re-enqueues entities that missed a backup for any reason, acting as a safety net for edge cases the event-driven triggers cannot catch.
  • Failed and Stale Recovery: The catch-up query targets entities with failed status, entities stuck in in_progress for longer than 10 minutes (indicating a crashed send), and entities that have made at least one attempt but have no remote ID.
  • Drift Detection: A secondary query identifies posts whose post_modified timestamp is newer than the stored last-backup timestamp, catching content changes that occurred while the event-driven triggers were not active.
  • Multi-Entity Coverage: The catch-up runs across all three backed-up post types — invoices, portal clients, and products — in a single query pass.
  • Global Config Catch-Up: The catch-up run also checks the global configuration backup record. If the global config has never been successfully backed up, is in a failed state, or is stale in-progress, it is re-enqueued. The payload builder’s hash check prevents unnecessary sends if the config content has not changed.
{{-- Inbound Operations Endpoint --}}

🔒 Inbound Operations Endpoint

  • REST Endpoint: A WordPress REST API route at POST /wp-json/apab/v1/operation receives signed operation commands from the external backup server.
  • Dual Delivery Pattern Support: The endpoint handles two delivery patterns. Pattern A (direct POST) carries the payload in the request body with signature in HTTP headers. Pattern B (signed URL) carries the payload as a base64-encoded query parameter — used when triggering a restore from the management console.
  • Ed25519 Signature Verification: All inbound requests are verified against the Ed25519 public key managed by the Agency Pulse Pro Connector before any payload fields are read. Requests with invalid signatures, expired timestamps, or missing parameters are rejected with a 400 or 403 response before any data is written.
  • Payload Expiry Check: Every signed payload includes an expiry Unix timestamp. The endpoint rejects any payload whose expiry has passed, preventing replay of intercepted requests.
  • Result Callback: If the inbound payload includes a callback_url field, the endpoint posts the operation result back to the server using JWT Bearer authentication, enabling the management console to confirm completion synchronously.
{{-- Invoice Restore --}}

📄 Restore & Archive

  • Full Invoice Reconstruction: The restore handler recreates an invoice post from the backup payload, writing all post fields, _invoice_* meta, and line items to the database.
  • Conflict Resolution Modes: When a local invoice with the same invoice number already exists, the configurable conflict mode determines the outcome: skip leaves the existing record untouched (default), overwrite updates it in place, or duplicate creates a new post alongside the existing one.
  • PDF Version History Restore: The _invoice_pdf_versions array is written directly from the payload, preserving the full version history including S3-backed signed PDF references.
  • Portal Client Resolution: If the payload includes a portal section, the handler looks up the client by email. If found, the existing client is linked; if not found, a new client record is created (when the “Restore Client Record” setting is enabled) or data is written to denormalised meta only.
  • Company Index Mapping: When the enhancements section is present, the company name from the payload is matched against the local company list to resolve the correct local index. If no match is found, an admin notice is surfaced prompting review.
  • Addon Section Writes: Multi-currency, enhancements, products, and secure sign sections are each written to the restored invoice only when their respective plugin is active on the target site, preventing orphaned meta from inactive addons.
  • Archive on Local Delete/Trash: When a backed-up entity is trashed or permanently deleted locally, the plugin sends an archive request to the server immediately (bypassing the queue), notifying the server that the local record has been removed.
  • Inbound Archive Commands: The server can also send an archive operation to WordPress, triggering a local trash or hard-delete of the entity identified by its remote ID. The action is determined by the payload’s archive_mode field, falling back to the site-wide archive mode setting.
  • Archive Meta Persistence: Archived entities have _apab_archived = true and _apab_archived_at written to post meta. These flags persist through WordPress trash, ensuring the archive state survives a restore from trash.
{{-- Addon Entity Restore and Deduplication --}}

👥 Addon Entity Restore & Deduplication

  • Client Restore with Deduplication: The client restore handler matches incoming records by _client_email. If a matching client already exists locally, the handler compares modification timestamps and skips the update if the local record is newer, preventing accidental overwrites of more recent data.
  • Client Template Merge: Invoice templates attached to a client are merged by UUID — templates already present locally are not overwritten, while new templates from the backup are appended.
  • Product Restore with Deduplication: Products are matched by name and company index. If a match is found and prices differ, the discrepancy is logged and local values are preserved. New products are created when no match is found.
  • Global Config Restore: A dedicated handler overwrites the tracked WordPress options with values from the backup payload, enabling full site configuration recovery including currencies, companies, and invoice numbering config.
  • Batch Restore: The restore_batch operation processes an array of heterogeneous items in a single request, returning a per-item result array including local IDs, conflict flags, and any errors. Batch pages are limited to 25 items; the server controls pagination sequencing.
{{-- Admin UI and Settings --}}

Admin UI & Settings

  • Dedicated Settings Tab: A “Backup” tab is added to the Agency Pulse Invoice settings page, containing all backup configuration fields alongside a live Pro Connector status indicator and a direct link to the management console.
  • Backup Status Column: A “Backup” column in the invoice list table displays a status icon per row: grey dash (never backed up), grey clock (queued), spinner (in progress), green checkmark (complete, with timestamp on hover), orange warning (failed, with error on hover), or red X (failed permanently).
  • Manual Per-Invoice Backup: A “Backup Now” button in the invoice editor triggers an immediate synchronous backup for that invoice, bypassing the queue for instant feedback. The result is returned as JSON and displayed inline.
  • Backup All Button: A “Backup All” button in the settings tab enqueues all invoices, portal clients, products, and a global config item in a single AJAX action. The response includes a count of items queued.
  • Failure Notices: Admin notices are surfaced for entities with failed_permanent status, showing the entity title and last error message. Notices are dismissible and clear automatically once the backup succeeds.
  • Unresolved Company Notice: A persistent admin notice prompts review when any restored invoice has a company assignment that could not be resolved against the local company list.
{{-- Integration with Existing Plugins --}}

🔗 Integration with Existing Plugins

  • Pro Connector Dependency: All outbound backup sends use the Agency Pulse Pro Connector’s authenticated HTTP client and JWT token manager. If the Pro Connector is missing or has no valid token, the plugin stops triggering backups and surfaces a settings notice — it never throws errors or affects other plugins.
  • Inbound Signature Verification via Pro Connector: Inbound operation requests are verified using the same Ed25519 keypair managed by the Pro Connector, ensuring the backup server and WordPress share a single key management system.
  • Hook-Only Addon Interaction: The backup plugin never reads addon code directly. Addon data is collected via WordPress hook callbacks that fire conditionally when the relevant addon class is detected, keeping the backup plugin fully decoupled from addon internals.
  • Secure Sign Event Hook: A listener on the apss_invoice_signed action enqueues the invoice for backup immediately after signing completes, ensuring the signed PDF metadata and secure sign section reach the server with minimal delay.
  • Non-Gating Design: Backup status never blocks invoice issuance, PDF generation, or any other core workflow. A failed or missing backup is surfaced as an informational notice only.
  • Deactivation Safety: On deactivation, all scheduled cron events are cleared. No post meta, option data, or queued items are deleted — deactivation is not a data wipe, and reactivation resumes from the existing state.
{{-- Bottom CTA --}} @if($product ?? null)

Get {{ $product->name }}

Unlock all the features above for your agency.

${{ number_format($product->price, 2) }} / monthly ${{ number_format($product->price * 10, 2) }} / yearly
@csrf
@endif @endsection