# Feature: WordPress / Flamingo

## Purpose

Per-team WordPress connection so Flamingo (Contact Form 7) inbound messages are pulled into ServDiary as customers.

## Boundaries

- **Owns:** `wordpress_connections`, `flamingo_submissions`; connect/disconnect/sync; webhook `POST /webhooks/wordpress/{secret}`; artisan `wordpress:sync-flamingo`; queued `SyncFlamingoLeadsJob`; Inertia `Pages/WordPress/Settings.vue`; companion plugin under `wordpress-plugin/servdiary-flamingo/`
- **Does not own:** Customers CRM UI, marketplace catalogue, Bark
- **Depends on (platform only):** User / Team / auth; Laravel HTTP client; queue; scheduler
- **Depends on (other domains):** none required — optional `class_exists` consumption of Customers `CreateCustomer` / `Customer`. Soft `customer_id` (no FK). If Customers is removed, sync records an error and creates no customers.
- **Platform UI touchpoint:** Optional card on Customers index when this domain is present. Marketplace WordPress card links here. Revert the Customers card if WordPress is removed.

## Models

| Model | Table | Notes |
|-------|-------|-------|
| `WordPressConnection` | `wordpress_connections` | One row per team. Encrypted Application Password. `connected_at` null means disconnected; submission mappings are kept. `webhook_secret` for inbound plugin posts. |
| `FlamingoSubmission` | `flamingo_submissions` | Soft `customer_id`. Unique `external_id` per connection — pull/webhook idempotency. |

Schema is normalised (3NF). Tokens use Laravel `encrypted` casts. Soft customer ids are intentional cross-domain references without FK. Migration: `2026_09_16_140000_create_wordpress_tables.php`.

## Behaviour

- **Connect:** Owner/admin enters site URL, WP username, Application Password. ServDiary calls companion plugin `GET /wp-json/servdiary/v1/health` (requires Flamingo).
- **Pull:** Every 15 minutes (`wordpress:sync-flamingo`) and on **Sync now**. Lists `GET …/flamingo-leads`.
- **Import:** Soft-create Customer (`residential` default; `commercial` if form field `customer-type` / `type` says so). Name from Flamingo from_name / fields; email/phone from payload; notes include subject + fields JSON.
- **Re-sync:** Same `external_id` does not create a second customer.
- **Webhook:** Companion plugin may `POST` the same payload shape to `/webhooks/wordpress/{webhook_secret}` (CSRF exempt).
- **Queue:** Set `WORDPRESS_QUEUE_SYNC=true` on sandbox without a worker so pulls run immediately.

## Companion plugin

Path: [`wordpress-plugin/servdiary-flamingo/`](../../wordpress-plugin/servdiary-flamingo/). Install on the WordPress site with Flamingo active. Uses Application Passwords (`manage_options`). Optional webhook URL in Settings → ServDiary Flamingo.

## Routes

### Web

| Method | URI | Name | Controller |
|--------|-----|------|------------|
| GET | `/wordpress` | `wordpress.settings` | Web\WordPressSettingsController@edit |
| POST | `/wordpress` | `wordpress.connect` | Web\WordPressSettingsController@store |
| POST | `/wordpress/disconnect` | `wordpress.disconnect` | Web\WordPressSettingsController@destroy |
| POST | `/wordpress/sync` | `wordpress.sync` | Web\WordPressSettingsController@sync |
| POST | `/webhooks/wordpress/{secret}` | `wordpress.webhook` | Web\WordPressWebhookController |

### API

N/A

## Permissions

- View settings: non-restricted team roles with `read`
- Connect / disconnect / sync: owner, admin, or super admin

## Tests

- Path: `laravel/tests/Feature/Domains/WordPress/`
- Cover: connect (HTTP fake), sync creates customer once, disconnect, webhook import, authz

## Add / remove checklist

### Add

- [x] Domain folder + `DomainServiceProvider`
- [x] Provider registered
- [x] This wiki page linked from `docs/README.md`
- [ ] Feature tests passing

### Remove

- [ ] Provider unregistered
- [ ] Domain folder deleted
- [ ] Customers index card reverted
- [ ] This page and index link removed
- [ ] Feature tests deleted
- [ ] Remaining suite still green
