# Architecture

How the Parcel2Go Shipping plugin and React app fit together.

## Bootstrap

1. **Plugin entry:** `parcel2go-shipping.php` runs on WordPress load. It defines `PARCEL2GO_SHIPPING_MAIN_PLUGIN_FILE`, loads Composer autoload (`vendor/autoload_packages.php`), and hooks `plugins_loaded` to `parcel2go_shipping_init`.
2. **Init:** After checking WooCommerce is active and loading the text domain, `parcel2go_shipping_init` calls `Parcel2GoShipping::instance()`, adds the "Settings" link on the Plugins screen, and registers REST routes for all API controllers (Orders, Quotes, Countries, Dropshop, Checkout, Payment, Settings, Shipments).
3. **Parcel2GoShipping:** The main class constructor only runs when `is_admin()`; it then instantiates `Parcel2GoShipping\Admin\Setup`.
4. **Setup:** Registers and enqueues the built script (`build/index.js`) and style (`build/index.css`) on WooCommerce Admin pages, and localizes `parcel2goShipping` (REST base URL, Sentry DSN/environment, asset URLs, etc.) for the frontend.

## Admin UI

- **Page registration:** Done in two places:
  - **PHP:** `includes/Admin/Setup.php` uses `wc_admin_register_page()` to register the WC Admin pages: landing (`/parcel2go-shipping`), shipments (`/parcel2go-shipping/shipments`), and settings (`/parcel2go-shipping/settings`).
  - **React:** `src/index.tsx` uses `addFilter('woocommerce_admin_pages_list', ...)` to provide the actual containers and breadcrumbs for those paths.
- **Script/style:** Enqueued only when `PageController::is_admin_or_embed_page()` is true, so the app loads only in the WC Admin context.
- **Localized config:** `parcel2goShipping` includes `apiUrl` (REST base), `dsn` / `environment` (Sentry), `flagsBaseUrl`, `couriersBaseUrl`, `editOrderUrlTemplate`, `storeAddressUrl`, and similar.

## Frontend

- **Entry:** Single React app in `src/index.tsx`. Sentry is initialized first; then the app registers with the `woocommerce_admin_pages_list` filter.
- **Routing:** The main component uses `useNavigation()` and `selectedOrderId`. If `selectedOrderId !== null`, it renders `OrderShipPage`; otherwise it renders `LandingPage`. Settings and Previous Shipments are lazy-loaded and rendered via the WC Admin page list (containers for `/parcel2go-shipping/settings` and `/parcel2go-shipping/shipments`).
- **Flow:** User starts on the landing page, picks an order to ship ("Ship now"), then goes through Order Ship (quotes, service selection, booking, payment). Settings and Shipments are separate flows from the sidebar/menu.

## High-level data flow

```mermaid
flowchart LR
	Landing[LandingPage]
	OrderShip[OrderShipPage]
	Quotes[Quotes]
	Booking[Booking]
	Payment[Payment]
	Complete[Complete]
	Settings[Settings]
	Shipments[Shipments]

	Landing -->|"Ship now"| OrderShip
	OrderShip --> Quotes
	Quotes --> Booking
	Booking --> Payment
	Payment --> Complete
	Settings --> Landing
	Shipments --> Landing
```

Landing shows orders; choosing one opens Order Ship. Order Ship fetches quotes, then checkout/validate, then payment (Braintree or prepay), then order completion. Settings and Previous Shipments are separate pages.

## Parcel2Go OAuth login

The plugin includes a first-party OAuth login flow so the WP admin can link their Parcel2Go account.
The WordPress plugin runs on each user's own domain.  There is no single fixed redirect URI that can be registered on the P2G OAuth client.

The accountlinking edge API acts as a stable, known OAuth redirect URI and encrypts the per-install WordPress site URL into the OAuth `state` parameter. When the user completes the P2G login, the edge decrypts the state and redirects the browser back to the WordPress site's REST API callback endpoint.

### Flow

```
WordPress Admin                         Accountlinking Edge               P2G Auth Server
       |                                           |                              |
       | POST /auth/authorise                      |                              |
       |   (generates PKCE verifier+challenge)     |                              |
       | ─────────────────────────────────────────>|                              |
       |   POST /{profile}/v1/nativeplugins/       |                              |
       |        nativeproxy/woocommerce/authorise  |                              |
       |   { codeChallenge, siteUrl, callbackUrl } |                              |
       |<─────────────────────────────────────────|                              |
       |   { authoriseUrl }                        |                              |
       |                                           |                              |
       | [browser redirects to authoriseUrl]       |                              |
       |                                           | ──────── user logs in ────>|
       |                                           |<── redirect with ?code= ─--|
       |                                           |                              |
       |<────── edge redirects to WP /auth/callback?code= ──────────────────────|
       |                                           |                              |
       | GET /auth/callback?code=                  |                              |
       |   (exchanges code + PKCE verifier)        |                              |
       | ────────────────────────────────── POST token ────────────────────────>|
       |<────────────────────────────────── { access_token, refresh_token } ──--|
       |   stores tokens in wp_options             |                              |
       |   redirects browser to plugin admin page  |                              |
```

### PHP
- `includes/Api/AuthController.php` — five REST endpoints: `authorise`, `callback`, `status`, `user`, and `logout`.
- Tokens are stored in `wp_options` (not autoloaded): `parcel2go_access_token`, `parcel2go_refresh_token`.
- PKCE code_verifier is stored as a short-lived transient (`parcel2go_pkce_code_verifier`, 10 min TTL) and deleted immediately after use.

### React
- `src/shared/context/AuthContext.tsx` — global auth context providing `useParcel2goAuth` hook for OAuth login, logout, and connection status. Checks server-rendered `window.parcel2goShipping.authLinked` and fetches `/auth/status` on mount.
- `src/features/orders/welcome-card.tsx` — renders a "Login to Parcel2Go" / "Connected ✓" button. When clicked, the button redirects the user to the P2G auth flow.
- `window.parcel2goShipping.authLinked` (bool) — set by PHP at page load; avoids an extra fetch on initial render.


| Path | Purpose |
|------|--------|
| `includes/` | PHP backend: `Api/` (REST controllers), `Helpers/` (OrderCompletionService, OrderFormatter, P2GApiClient, etc.), `Constants/P2GApi.php`, `Admin/Setup.php` |
| `src/` | React app: `index.tsx` (entry), `pages/` (LandingPage, OrderShipPage, SettingsPage, PreviousShipmentsPage), `features/` (order-ship, settings, shipments, orders), `shared/` (components, hooks, utils, sentry), `types/`, `constants/`, `public/couriers/` (and flags) |
| `build/` | Output of `npm run build`: `index.js`, `index.asset.php`, `index.css` |
| `vendor/` | Composer autoload; plugin requires `vendor/autoload_packages.php` |
