# Debugging Marketplace

Use this when Marketplace account linking, public domain verification, catalogue browsing, install authorization, heartbeat, diagnostics, or update notices fail.

## Flow Diagram

```mermaid
sequenceDiagram
    participant Admin
    participant CMS as Capell CMS
    participant App as Capell App
    participant Public as Public Host

    Admin->>CMS: Connect account
    CMS->>App: Create account connection session
    App-->>Admin: Approval URL
    Admin->>App: Approve site
    App->>CMS: Authenticated callback with code/state
    CMS->>App: Exchange code
    App-->>CMS: Instance ID and signing secret
    Admin->>CMS: Verify public domain
    CMS->>Public: Write challenge file
    CMS->>App: Request verification
    App->>Public: Fetch .well-known challenge
    App-->>CMS: Verified instance/domain
    CMS->>App: Heartbeat and install authorization requests
```

Account linking is the normal setup path. Public domain verification is a stronger production signal and requires a real public hostname.

## First Checks

```bash
php artisan config:show app.url
php artisan config:show capell-marketplace.marketplace.base_url
php artisan config:show capell-marketplace.marketplace.webhook_url
php artisan route:list --name=capell-marketplace
```

The default API URL is:

```ini
CAPELL_MARKETPLACE_URL=https://capell.app/api/v1
```

## Account Connection

```sql
select connection_session_id, claimed_domain, app_url, callback_url, status, expires_at, completed_at, last_error
from marketplace_account_connection_sessions
order by id desc
limit 5;
```

| Status       | Meaning                                             | Fix                                                  |
| ------------ | --------------------------------------------------- | ---------------------------------------------------- |
| `pending`    | Admin has not returned from Capell App yet          | Complete the current approval URL before it expires. |
| `completing` | Callback reserved the session while exchanging code | Wait briefly; if stuck, start a new connection.      |
| `failed`     | Remote request or validation failed                 | Read `last_error`, fix config/session, retry.        |
| `expired`    | 10-minute window passed                             | Start a fresh connection.                            |
| `completed`  | Instance should exist                               | Check `marketplace_instances`.                       |

Do not reuse old approval URLs after starting a newer account connection.

## Public Domain Verification

```sql
select domain, challenge_id, challenge_path, status, expires_at, last_error
from marketplace_registration_sessions
order by id desc
limit 5;
```

Fetch the exact public challenge URL:

```bash
curl -i https://your-domain/.well-known/capell/marketplace/chal_EXAMPLE
```

Expected result: `200 OK`, `Content-Type: text/plain`, and the stored challenge token body.

Common blockers:

- `www.example.com` was entered but `example.com` is being fetched, or the reverse.
- The challenge route is behind auth, maintenance mode, or a CDN rule.
- Static file handling bypasses Laravel/public files incorrectly.
- The session expired.
- The domain is local-only, such as `.test`, `.localhost`, `localhost`, `127.*`, or an IP address.

## Catalogue And Install Authorization

```sql
select instance_id, connection_mode, account_email, verified_domains, last_heartbeat_at
from marketplace_instances
order by last_heartbeat_at desc
limit 5;
```

Browsing the catalogue only proves the catalogue endpoint works. Installing also needs a connected instance, entitlement/licence state, domain policy, and local platform compatibility.

Check local package versions:

```bash
composer show capell-app/core filament/filament livewire/livewire laravel/framework
```

If the catalogue appears stale in local debugging:

```bash
php artisan cache:clear
```

Use targeted browser refresh controls in production rather than broad cache clears.

## Heartbeat And Update Notices

```sql
select instance_id, last_heartbeat_at
from marketplace_instances
order by last_heartbeat_at desc
limit 5;

select source, checked_at, capell_version, metadata
from marketplace_update_advisory_snapshots
order by checked_at desc
limit 5;
```

Heartbeat needs:

- Marketplace API base URL;
- public webhook/callback URL from `CAPELL_MARKETPLACE_WEBHOOK_URL` or `APP_URL`;
- known instance ID;
- outbound network access to the Marketplace API.

## Test Recipes

### Account Connection

```php
it('fails account connection when app url has no host', function (): void {
    config(['app.url' => '']);

    StartMarketplaceAccountConnectionAction::run();
})->throws(RuntimeException::class, 'APP_URL must include a valid host');
```

### Challenge Route

```php
it('serves only matching pending challenge domains', function (): void {
    MarketplaceRegistrationSession::factory()->create([
        'domain' => 'example.com',
        'challenge_id' => 'chal_TEST',
        'challenge_token' => 'secret-token',
    ]);

    $this->get('https://example.com/.well-known/capell/marketplace/chal_TEST')
        ->assertOk()
        ->assertSee('secret-token');
});
```

### Heartbeat

```php
it('does not phone home without a connected instance', function (): void {
    expect(PhoneHomeAction::run())->toBeFalse()
        ->and(PhoneHomeAction::lastFailureMessage())->toContain('not connected');
});
```

## Next

- [Marketplace package overview](../../packages/marketplace/docs/overview.md)
- [Operations troubleshooting](troubleshooting.md)
- [Extension troubleshooting](../packages/extension-troubleshooting.md)