# Foundation hardening implementation plan

## Current-state findings

- The legacy `role_assignments` table uses nullable organization/project scope columns. The two live rows are unambiguous, membership-backed, non-duplicated, and safe to migrate losslessly.
- Project access is enforced by `EnsureProjectMembership`, while `ProjectPolicy` is not invoked. No organization policy or access route exists.
- `WorkspaceContext` chooses the first project implicitly and accepts a supplied project without independently establishing a validated selection.
- `project_memberships` has no primary-role reference; primary state currently lives on role assignments.
- The local demo seeder is not environment-guarded, logout incorrectly requires verification, and shared Inertia props serialize models.
- The Vue permission test and default PHPUnit example do not test application behavior. Axios/bootstrap, the welcome view, and Sail appear unused.

## Controlled implementation sequence

1. **Lock behavior with failing tests**
    - Replace `tests/Feature/FoundationTest.php` with focused workspace, authorization, role-integrity, Inertia-payload, logout, and seeder tests.
    - Add focused test helpers/factories only where they reduce duplication.
    - Replace `resources/js/composables/usePermissions.test.ts` with a test that invokes application code.
    - Remove `tests/Unit/ExampleTest.php` after meaningful coverage exists.

2. **Separate scoped role assignments and preserve data**
    - Add a forward migration under `database/migrations` that creates `organization_role_assignments` and `project_role_assignments`, adds `primary_role_id` to `project_memberships`, migrates valid legacy rows, verifies counts/invariants, and only then removes `role_assignments`.
    - Use membership IDs in assignments so membership is structurally required. Use composite unique keys to reject duplicates.
    - Add composite membership/role keys needed for MariaDB foreign-key enforcement of primary-role ownership and scope.
    - Add `OrganizationMembership`, `ProjectMembership`, `OrganizationRoleAssignment`, and `ProjectRoleAssignment` models and complete relevant relationships in `User`, `Organization`, `Project`, `Role`, and `Permission`.

3. **Transactional role-management services**
    - Add focused classes under `app/Domain/Authorization` for assigning/removing scoped roles and changing the primary project role.
    - Validate role scope, use transactions and row locks, replace the primary deterministically when explicitly assigned, and clear it when its assignment is removed.

4. **Centralize authorization and workspace selection**
    - Add `OrganizationPolicy`; update `ProjectPolicy` to use membership relationships.
    - Replace the single-purpose middleware with workspace-selection middleware that validates route/session selections, clears stale values, enforces project/organization consistency, and falls back by stable ascending membership ID.
    - Keep policies authoritative in controllers. Add small `OrganizationController` and `ProjectController` show actions solely for the existing foundation pages and observable authorization boundaries.
    - Update `routes/web.php`, keeping logout in an authenticated-but-not-verified group.
    - Refactor `WorkspaceContext` into a read-only representation of selections already validated by the middleware/policies; permissions are the union of roles in the selected scope and the membership primary role controls presentation only.

5. **Minimize global Inertia data**
    - Update `HandleInertiaRequests` to construct explicit scalar arrays for the authenticated user, organization, project, roles, primary role, available workspace choices, and permission slugs.
    - Update `resources/js/types/index.ts`, `AppLayout.vue`, and any affected pages/composables.

6. **Protect development data and normalize configuration**
    - Split local demo records into `LocalDevelopmentSeeder`; keep `DatabaseSeeder` production-safe and environment-aware.
    - Clean duplicate/contradictory keys in `.env.example` without touching `.env`; default encrypted sessions and synchronous queues for the base install.

7. **Remove confirmed unused foundation artifacts**
    - Remove `resources/js/bootstrap.js`, `resources/views/welcome.blade.php`, Axios, and Sail only after reference checks.
    - Update `package.json`, `package-lock.json`, `composer.json`, and `composer.lock` using their package managers without adding dependencies.
    - Strengthen `eslint.config.js` to use recommended Vue rules and format affected templates.

8. **Documentation and verification**
    - Update `README.md` and `ARCHITECTURE.md` with the hardened schema, deterministic workspace fallback, seeding rules, and authorization boundaries.
    - Run focused tests red/green throughout.
    - Verify a clean SQLite migration and a forward MariaDB migration against the current schema without deleting legacy data.
    - Run `php artisan optimize:clear`, all backend/frontend tests, Pint, Larastan, Composer validation/audit, npm dependency validation/typecheck/lint/build, `git diff --check`, and final secret/artifact/status checks.

## Dependency decision

No new dependency is required. Existing Laravel transactions, policies, middleware, Eloquent, PHPUnit, Vitest, and MariaDB constraints cover this work.
