# MyCode Control Global Visual System and Provider Archive Implementation Plan

> **For agentic workers:** Execute this plan with `executing-plans`, one task at a time, and keep the API and web commits independently deployable.

**Goal:** Apply the MyCode visual language to every MyCode Control surface and add a safe administrative provider archive flow that requires explicit confirmation and a reason while preserving relational history.

**Architecture:** The API owns archive authorization, validation, status transitions, audit events, and soft deletion. The web BFF only validates and forwards the supported admin operation. The admin JavaScript renders the confirmation experience and delegates business state to the API. The visual redesign is implemented through the existing split CSS modules so all current views inherit one light MyCode system without duplicating page-specific themes.

**Tech Stack:** Laravel, PHP 8, PostgreSQL, Blade, vanilla JavaScript modules, PHPUnit, Node test runner, Laravel Mix, CSS custom properties.

---

## Task 1: Add the administrative provider archive API contract

**Files:**

- Create: `/Users/tumac.cl/PhpstormProjects/api_mycode/tests/Feature/ServiceProviders/AdminServiceProviderArchiveApiTest.php`
- Create: `/Users/tumac.cl/PhpstormProjects/api_mycode/app/Http/Requests/ServiceProviders/ArchiveServiceProviderRequest.php`
- Modify: `/Users/tumac.cl/PhpstormProjects/api_mycode/app/Policies/ServiceProviderPolicy.php`
- Modify: `/Users/tumac.cl/PhpstormProjects/api_mycode/app/Services/ServiceProviders/ProviderStatusService.php`
- Modify: `/Users/tumac.cl/PhpstormProjects/api_mycode/app/Http/Controllers/Api/V1/AdminServiceProviderController.php`
- Modify: `/Users/tumac.cl/PhpstormProjects/api_mycode/routes/api/v1/service_providers.php`

### Step 1: Write the failing feature tests

Cover these observable behaviors:

```php
public function test_admin_archive_requires_suspend_permission(): void
{
    $response = $this->actingAs($admin)->postJson(
        "/api/v1/admin/service-providers/{$provider->id}/archive",
        ['reason' => 'Registro duplicado confirmado por soporte.'],
    );

    $response->assertForbidden();
    $this->assertNotSoftDeleted('service_providers', ['id' => $provider->id]);
}

public function test_admin_archive_requires_a_reason(): void
{
    $response = $this->actingAs($adminWithPermission)->postJson(
        "/api/v1/admin/service-providers/{$provider->id}/archive",
        [],
    );

    $response->assertUnprocessable()->assertJsonValidationErrors('reason');
}

public function test_admin_can_archive_provider_and_preserve_history(): void
{
    $response = $this->actingAs($adminWithPermission)->postJson(
        "/api/v1/admin/service-providers/{$provider->id}/archive",
        ['reason' => 'Registro duplicado confirmado por soporte.'],
    );

    $response->assertOk()->assertJsonPath('data.status', 'archived');
    $this->assertSoftDeleted('service_providers', ['id' => $provider->id]);
    $this->assertDatabaseHas('service_provider_status_events', [
        'service_provider_id' => $provider->id,
        'action' => 'archived',
        'reason' => 'Registro duplicado confirmado por soporte.',
        'actor_id' => $adminWithPermission->id,
    ]);
    $this->assertDatabaseHas('service_locations', ['service_provider_id' => $provider->id]);
    $this->assertDatabaseHas('service_provider_verifications', ['service_provider_id' => $provider->id]);
}
```

Use the factories and permission helpers already used by `AdminServiceProviderApiTest`.

### Step 2: Run the test and confirm the red state

Run:

```bash
php artisan test tests/Feature/ServiceProviders/AdminServiceProviderArchiveApiTest.php
```

Expected: failures because the admin archive route and request do not exist.

### Step 3: Implement request validation and authorization

Create `ArchiveServiceProviderRequest` with:

```php
public function rules(): array
{
    return [
        'reason' => ['required', 'string', 'max:1000'],
    ];
}
```

Add `ServiceProviderPolicy::archive()` using the existing `suspend_service_providers` permission. This deliberately reuses the established destructive moderation permission instead of creating an undeployed role permission.

### Step 4: Extend the status service without breaking owner archive

Change the signature compatibly:

```php
public function archive(
    ServiceProvider $provider,
    User $actor,
    ?string $reason = null,
): ServiceProvider
```

Pass `$reason` into the archived status event. Keep the existing asset cleanup and soft deletion behavior so locations, verification rows, and audit events remain in the database.

### Step 5: Add the controller operation and route

Add:

```php
public function archive(
    ArchiveServiceProviderRequest $request,
    ServiceProvider $provider,
    ProviderStatusService $statuses,
): ServiceProviderResource {
    $this->authorize('archive', $provider);

    return new ServiceProviderResource(
        $statuses->archive($provider, $request->user(), $request->string('reason')->toString()),
    );
}
```

Register:

```php
Route::post('admin/service-providers/{provider}/archive', [AdminServiceProviderController::class, 'archive'])
    ->middleware('permission:suspend_service_providers');
```

### Step 6: Run targeted and regression tests

Run:

```bash
php artisan test tests/Feature/ServiceProviders/AdminServiceProviderArchiveApiTest.php
php artisan test tests/Feature/ServiceProviders/AdminServiceProviderApiTest.php
php artisan test tests/Feature/ServiceProviders/ServiceProviderApiTest.php
```

Expected: all pass.

### Step 7: Commit the API change

```bash
git add app/Http/Requests/ServiceProviders/ArchiveServiceProviderRequest.php \
  app/Policies/ServiceProviderPolicy.php \
  app/Services/ServiceProviders/ProviderStatusService.php \
  app/Http/Controllers/Api/V1/AdminServiceProviderController.php \
  routes/api/v1/service_providers.php \
  tests/Feature/ServiceProviders/AdminServiceProviderArchiveApiTest.php
git commit -m "feat: archive providers from admin"
```

## Task 2: Add the web BFF archive bridge

**Files:**

- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/app/Application/Admin/Bridge/AdminProviderRouteRegistry.php`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/app/Application/Admin/Bridge/AdminProviderPayloadResolver.php`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/tests/Unit/Application/Bridge/AdminProviderRouteRegistryTest.php`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/tests/Unit/Application/Bridge/AdminProviderPayloadResolverTest.php`
- Create: `/Users/tumac.cl/PhpstormProjects/web_mycode/tests/Feature/AdminBridgeServiceProviderArchiveTest.php`

### Step 1: Write failing route and payload tests

Assert that:

```php
$route = $registry->resolve('POST', '/api/v1/admin/service-providers/'.$uuid.'/archive');

$this->assertSame(
    '/api/v1/admin/service-providers/'.$uuid.'/archive',
    $route->apiPath(),
);
$this->assertSame(
    ['reason' => 'Registro duplicado'],
    $resolver->resolve('archive', ['reason' => 'Registro duplicado', 'confirmation' => '1']),
);
```

The feature test must assert that the authenticated admin bridge forwards the exact route and reason, and never forwards the UI-only `confirmation` field.

### Step 2: Run the tests and confirm failure

Run:

```bash
php artisan test \
  tests/Unit/Application/Bridge/AdminProviderRouteRegistryTest.php \
  tests/Unit/Application/Bridge/AdminProviderPayloadResolverTest.php \
  tests/Feature/AdminBridgeServiceProviderArchiveTest.php
```

Expected: archive is not an allowed operation.

### Step 3: Add archive to the allow-list

Extend the registry action expression from:

```php
(approve|reject|suspend|restore|verify)
```

to:

```php
(approve|reject|suspend|restore|verify|archive)
```

Map `archive` to the same validated reason payload shape used by reject and suspend. Keep route construction centralized.

### Step 4: Run the tests

Run the command from Step 2.

Expected: all pass.

## Task 3: Implement the archive confirmation UI

**Files:**

- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/resources/js/admin/22-provider-detail-model.js`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/resources/js/admin/23-provider-detail-view.js`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/resources/js/admin/23-provider-moderation-dialog-view.js`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/resources/js/admin/24-provider-moderation-dialog.js`
- Modify or split: `/Users/tumac.cl/PhpstormProjects/web_mycode/resources/js/admin/24-provider-moderation-viewmodel.js`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/tests/js/admin-service-provider-detail.test.js`

### Step 1: Write failing JavaScript tests

Add assertions for:

- `archive` appears for every known non-archived provider status when `canSuspend` is true.
- Archived providers expose no moderation actions.
- `buildProviderModerationPayload('archive', ...)` requires a non-empty reason.
- Archive opens the dialog instead of sending immediately.
- The dialog contains an explicit confirmation checkbox and destructive explanatory copy.
- Submit remains disabled until both reason and confirmation are present.
- The request is sent once to `/api/v1/admin/service-providers/{uuid}/archive`.
- The provider detail is refreshed after success.

### Step 2: Confirm the tests fail

Run:

```bash
node --test tests/js/admin-service-provider-detail.test.js
```

Expected: archive is not modeled or rendered.

### Step 3: Implement archive as a first-class moderation action

Add the Spanish action label `Eliminar prestador`, use the danger treatment, and require the dialog. The dialog must explain that the profile stops appearing but its moderation history is retained.

The confirmation checkbox is a client safety control only. Build the API payload as:

```javascript
{ reason: reason.trim() }
```

Guard the submit path against repeated clicks with the existing busy state. If `24-provider-moderation-viewmodel.js` would exceed 150 lines, extract the submit logic into `24-provider-moderation-submit.js` and add it to `webpack.mix.js` immediately before the viewmodel.

### Step 4: Run the focused JavaScript suite

Run:

```bash
node --test tests/js/admin-service-provider-detail.test.js
```

Expected: all pass.

## Task 4: Establish the global visual contract

**Files:**

- Create: `/Users/tumac.cl/PhpstormProjects/web_mycode/tests/js/admin-global-visual.test.js`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/package.json`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/01.css`

### Step 1: Write a failing visual contract test

The test must load the admin CSS files and verify:

```javascript
assert.match(css, /--admin-bg:\s*var\(--paper-2\)/);
assert.match(css, /--admin-panel:\s*var\(--surface\)/);
assert.match(css, /--admin-primary:\s*var\(--mc-primary\)/);
assert.match(css, /color-scheme:\s*light/);
assert.match(css, /font-family:\s*var\(--font-body\)/);
assert.doesNotMatch(css, /#0d1117|#161b22|#0b0f14/i);
```

Also confirm every file in `public/css/admin-panel` remains at or under 150 lines.

Add:

```json
"test:admin-visual": "node --test tests/js/admin-global-visual.test.js"
```

### Step 2: Run and confirm failure

Run:

```bash
npm run test:admin-visual
```

Expected: the current dark aliases and color scheme violate the contract.

### Step 3: Replace the global aliases

Set the base aliases to the shared MyCode tokens:

```css
:root {
    --admin-bg: var(--paper-2);
    --admin-panel: var(--surface);
    --admin-panel-soft: var(--paper-1);
    --admin-sidebar-bg: var(--surface);
    --admin-line: var(--line);
    --admin-text: var(--ink-900);
    --admin-muted: var(--ink-500);
    --admin-primary: var(--mc-primary);
    --admin-primary-dark: var(--blue-700);
    --admin-primary-dim: var(--mc-primary-soft);
    --admin-accent: var(--mc-accent);
    --admin-danger: var(--mc-danger);
    color-scheme: light;
}
```

Apply `var(--font-body)` to the document and remove dark-only backgrounds from the global shell.

### Step 4: Run the contract test

Run:

```bash
npm run test:admin-visual
```

Expected: base contract passes before module-level restyling.

## Task 5: Redesign all shared admin primitives

**Files:**

- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/01.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/02.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/03.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/04.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/05.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/06.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/07.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/08.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/09.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/10.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/11.css`

### Step 1: Apply the approved system to the shared components

Implement:

- White login card with blue action and coral identity marker.
- White sidebar and topbar, soft-blue active navigation, coral active indicator.
- White cards with 18px radius, subtle border, and soft shadow.
- Pill buttons: blue primary, white ghost, coral/red destructive.
- Light form controls with 12px radius and blue focus rings.
- Light tables with readable headers, blue-soft hover, and responsive overflow.
- Semantic status pills using shared success, warning, danger, and primary tokens.
- Light modals, notices, empty states, pagination, JSON/code blocks, and error surfaces.
- No image inversion or dark-only `color-scheme`.

Preserve every selector used by the current Blade and JavaScript modules; this is a visual replacement, not a navigation rewrite.

### Step 2: Run the visual and DOM contract tests

Run:

```bash
npm run test:admin-visual
php artisan test tests/Feature/AdminPanelTest.php
```

Expected: all pass.

## Task 6: Redesign dashboard, charts, registrations, and remaining modules

**Files:**

- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/12.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/13.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/14.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/15.css`
- Modify: `/Users/tumac.cl/PhpstormProjects/web_mycode/public/css/admin-panel/16.css`

### Step 1: Bring page-specific modules into the same system

Restyle the dashboard visualization and registration map with light surfaces, blue data emphasis, coral highlights, and accessible labels. Ensure provider details, provider moderation, verification, catalog, user, and profile modules consume global aliases instead of their own dark theme.

Use coral selectively for:

- section markers,
- destructive actions,
- selected points or chart highlights,
- critical error states.

Do not make coral the primary call-to-action color.

### Step 2: Verify module coverage and responsive behavior

Run:

```bash
npm run test:admin-visual
node --test tests/js/admin-*.test.js
php artisan test tests/Feature/AdminPanelTest.php tests/Feature/AdminBridgeServiceProviderArchiveTest.php
```

Expected: all pass.

## Task 7: Build, audit, version, and verify both repositories

**Files:**

- Modify only if required by the version hook: `/Users/tumac.cl/PhpstormProjects/web_mycode/config/version.php`
- Modify only if required by the version hook: `/Users/tumac.cl/PhpstormProjects/web_mycode/package.json`
- Modify only if required by the version hook: `/Users/tumac.cl/PhpstormProjects/web_mycode/package-lock.json`

### Step 1: Run complete API verification

Run:

```bash
composer validate --no-check-publish
php artisan test
```

Expected: all API tests pass.

### Step 2: Run complete web verification

Run:

```bash
composer validate --no-check-publish
php artisan architecture:audit --strict
php artisan test
npm run test:admin
npm run test:admin-visual
npm run production
```

Expected: architecture audit, PHP tests, JavaScript tests, visual contract, and production build all pass.

### Step 3: Review the version dialog

This is a user-facing feature spanning all admin screens plus a new moderation capability. Select the minor version change from `1.5.0` to `1.6.0` when the web commit hook prompts.

### Step 4: Commit the web implementation

Stage only files named in this plan and the generated version files:

```bash
git add app/Application/Admin/Bridge/AdminProviderRouteRegistry.php \
  app/Application/Admin/Bridge/AdminProviderPayloadResolver.php \
  public/css/admin-panel \
  resources/js/admin \
  tests/Feature/AdminBridgeServiceProviderArchiveTest.php \
  tests/Unit/Application/Bridge/AdminProviderRouteRegistryTest.php \
  tests/Unit/Application/Bridge/AdminProviderPayloadResolverTest.php \
  tests/js/admin-service-provider-detail.test.js \
  tests/js/admin-global-visual.test.js \
  package.json package-lock.json config/version.php webpack.mix.js
git commit -m "feat: redesign admin and archive providers"
```

### Step 5: Inspect final diffs

Run in each repository:

```bash
git status --short
git diff HEAD^ --stat
git log -1 --oneline
```

Expected: only intentional files are committed; pre-existing unrelated files remain untouched in the original worktrees.

## Task 8: Integrate and prepare deployment

### Step 1: Merge each isolated branch into its repository master

Run from clean integration worktrees:

```bash
git merge --ff-only codex/provider-admin-archive
git merge --ff-only codex/admin-global-redesign
```

Resolve no unrelated files and do not reset user changes.

### Step 2: Push both masters

Run:

```bash
git push origin master
```

Expected: API and web remotes accept the new commits.

### Step 3: Provide separate droplet deployment commands

The API commands must target:

```text
/var/www/services/apimycode
```

The web commands must target:

```text
/var/www/html/webmycode
```

Each deploy sequence must verify the exact commit, install production dependencies, clear Laravel caches, rebuild web assets where appropriate, restore ownership, bring the application up, and run an HTTP health check.
