## Summary - move the Laravel application into `apps/platform` and keep the repository root for orchestration, docs, and tooling - update the local command model, Sail/Docker wiring, runtime paths, and ignore rules around the new platform location - add relocation quickstart/contracts plus focused smoke coverage for bootstrap, command model, routes, and runtime behavior ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/PlatformRelocation` - integrated browser smoke validated `/up`, `/`, `/admin`, `/admin/choose-workspace`, and tenant route semantics for `200`, `403`, and `404` ## Remaining Rollout Checks - validate Dokploy build context and working-directory assumptions against the new `apps/platform` layout - confirm web, queue, and scheduler processes all start from the expected working directory in staging/production - verify no legacy volume mounts or asset-publish paths still point at the old root-level `public/` or `storage/` locations Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #213
254 lines
24 KiB
Markdown
254 lines
24 KiB
Markdown
# Feature Specification: Platform Relocation to apps/platform
|
|
|
|
**Feature Branch**: `182-platform-relocation`
|
|
**Created**: 2026-04-07
|
|
**Status**: Proposed
|
|
**Input**: User description: "Spec 182 — Laravel Platform Relocation to apps/platform"
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: workspace
|
|
- **Primary Routes**:
|
|
- `/`
|
|
- `/admin`
|
|
- `/admin/t/{tenant}/...`
|
|
- `/system`
|
|
- `/livewire/*`
|
|
- existing public asset and build entrypoints served through the platform app `public/` directory
|
|
- **Data Ownership**:
|
|
- No workspace-owned or tenant-owned product tables change ownership in this spec.
|
|
- The repo root becomes the source of truth for repo-wide metadata, docs, specs, scripts, editor settings, and orchestration files.
|
|
- `apps/platform` becomes the source of truth for Laravel runtime, application code, tests, build inputs, and app-local environment files.
|
|
- Existing application data, snapshots, runs, findings, audits, and tenant-scoped artifacts remain owned by their current domains.
|
|
- **RBAC**:
|
|
- No new RBAC model, role semantics, capability registry entries, or authorization planes are introduced.
|
|
- Existing `/admin`, `/admin/t/{tenant}/...`, and `/system` authorization behavior must remain unchanged after the move.
|
|
- Non-members remain `404`, in-scope capability denials remain `403`, and the move must not widen route visibility or global search exposure.
|
|
|
|
For canonical-view specs, the spec MUST define:
|
|
|
|
- **Default filter behavior when tenant-context is active**: Not changed by this relocation. Existing tenant-context and canonical-view filters must behave identically before and after the move.
|
|
- **Explicit entitlement checks preventing cross-tenant leakage**: Relocated entrypoints must preserve the existing server-side workspace and tenant entitlement checks exactly; the move must not create alternate paths, stale route bindings, or asset-linked leaks that bypass current `404` and `403` behavior.
|
|
|
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
|
|
|
- **New source of truth?**: No
|
|
- **New persisted entity/table/artifact?**: No
|
|
- **New abstraction?**: No new platform abstraction layer, shared package, or workspace engine. The only new contract is an explicit file-placement and command-model decision for the existing app.
|
|
- **New enum/state/reason family?**: No
|
|
- **New cross-domain UI framework/taxonomy?**: No
|
|
- **Current operator problem**: The repo root currently conflates Laravel app root, repo root, tooling root, and documentation root, which makes future multi-app growth and current-day runtime ownership harder to reason about.
|
|
- **Existing structure is insufficient because**: Root-based Laravel assumes that every runtime, script, task, and doc lives in the same top-level namespace. That blocks a clean repo-level topology and makes future additional surfaces harder without first untangling ownership.
|
|
- **Narrowest correct implementation**: Move only the existing Laravel platform app into `apps/platform`, update runtime paths and repo tooling to match, and defer website apps, shared packages, workspace orchestrators, and CI/CD redesign.
|
|
- **Ownership cost**: The repo takes on one large path migration, documentation updates, task and agent config updates, smoke validation, and clearer rollback expectations for open branches.
|
|
- **Alternative intentionally rejected**: Introducing `apps/website`, shared `packages/`, pnpm or Turbo or Nx orchestration, or a CI/CD rebuild in the same slice was rejected as over-scoped and unnecessary for solving the current topology problem.
|
|
- **Release truth**: Current-release infrastructure truth with future-facing value. The move prepares later multi-app work without shipping new product behavior in this spec.
|
|
|
|
## Decision Summary
|
|
|
|
- **Official Command Model**: `apps/platform` is the canonical working directory for platform development. Composer, PHP, Artisan, Sail, Node, Vite, Pint, and test commands are documented and maintained from `apps/platform`. Root-level helpers are allowed only as explicit compatibility aids for tools that cannot set a nested working directory cleanly.
|
|
- **Root vs App Placement Matrix**: Repo-wide docs, specs, scripts, `.specify`, editor configs, agent configs, and `docker-compose.yml` stay at the repo root. Laravel app code, runtime files, tests, build inputs, and app env files live under `apps/platform`.
|
|
- **Environment Model**: `apps/platform/.env.example` and `apps/platform/.env` are the canonical Laravel environment files. If a root-level compose env file is required, it is compose-only and must not duplicate or redefine application config truth.
|
|
- **Drizzle and Adjacent Tooling**: App-specific database tooling such as `drizzle.config.ts` moves next to the platform app unless a documented repo-wide consumer proves that root placement is necessary.
|
|
- **Root Compatibility Helpers**: No second official workflow is allowed. Any retained root wrappers, tasks, or aliases must delegate transparently to `apps/platform`, be labeled non-canonical, and remain optional rather than foundational.
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Run the Platform From the New Location (Priority: P1)
|
|
|
|
As a platform developer, I want one official local command model after the move so that I can install dependencies, boot the stack, build assets, and run tests without guessing whether commands belong at the repo root or the app root.
|
|
|
|
**Why this priority**: If the command model remains ambiguous, the move fails even if the files are technically relocated.
|
|
|
|
**Independent Test**: Can be fully tested by starting from a clean checkout, following the documented local workflow, and reaching a running application plus a passing focused test run without ad-hoc path fixes.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a clean checkout after the move, **When** a developer follows the documented local setup, **Then** they can install dependencies, start the stack, and reach the platform app using only the official `apps/platform` workflow.
|
|
2. **Given** repo-maintained tasks, scripts, and agent instructions, **When** they invoke platform-local commands, **Then** they point to `apps/platform` or transparently delegate there without inventing a second primary workflow.
|
|
|
|
---
|
|
|
|
### User Story 2 - Keep Existing Runtime Surfaces Stable (Priority: P1)
|
|
|
|
As an operator or maintainer, I want the public entry, admin panels, tenant-scoped panels, system panel, assets, and queue-backed behavior to work the same way after the move so that the relocation does not create a hidden product outage.
|
|
|
|
**Why this priority**: Structural success is not meaningful if the relocated app no longer boots or serves the existing product safely.
|
|
|
|
**Independent Test**: Can be fully tested by running the smoke pack and confirming that web entrypoints, choose-workspace navigation, a representative tenant-scoped route, preserved `404` versus `403` behavior, Filament panels, assets, and a representative queue-backed flow behave correctly from the relocated app.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the relocated platform app is started through the official workflow, **When** an operator opens the public root, admin panel, tenant routes, and system panel, **Then** those surfaces load without asset or bootstrap regressions.
|
|
2. **Given** the relocated runtime is active, **When** a maintainer runs the build and test smoke steps, **Then** asset manifests, Tailwind scanning, and test bootstrap complete successfully from the new app location.
|
|
3. **Given** a queue worker is started under the relocated runtime, **When** a representative queued flow is executed, **Then** the worker resolves the app correctly and the flow completes without root-path assumptions.
|
|
|
|
---
|
|
|
|
### User Story 3 - Review and Roll Back the Move Safely (Priority: P2)
|
|
|
|
As a maintainer responsible for a high-churn repo, I want the move to ship with an explicit rollback plan, smoke evidence, and branch-impact guidance so that I can recover quickly if the relocation breaks local or staging workflows.
|
|
|
|
**Why this priority**: Large repository moves create merge pressure and hidden environment drift unless rollback and branch guidance are part of the slice.
|
|
|
|
**Independent Test**: Can be fully tested by reviewing the documented rollback steps, verifying that they cover local env and artifact cleanup, and confirming that open-branch communication is part of the release notes for the move.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the relocation is ready for review, **When** a maintainer reads the rollout notes, **Then** they can see the rollback path, required cleanup steps, and branch-impact guidance without reverse-engineering the diff.
|
|
2. **Given** external deployment behavior cannot be proven from the repo alone, **When** the move is prepared for rollout, **Then** the unknowns are documented explicitly instead of being silently assumed resolved.
|
|
|
|
---
|
|
|
|
### User Story 4 - Keep Repo Tooling Aligned With the New Topology (Priority: P3)
|
|
|
|
As a contributor using editor tasks, MCP helpers, and repository automation, I want repo tooling to understand the new app location so that path-sensitive helper flows do not lag behind the actual runtime layout.
|
|
|
|
**Why this priority**: Tooling drift is a common hidden failure after large topological changes and creates day-two friction even when the app boots.
|
|
|
|
**Independent Test**: Can be fully tested by running at least one representative VS Code task or agent or MCP flow and confirming that it resolves the relocated app paths correctly.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** repo-maintained tasks and agent configs exist, **When** one representative task or tool-assisted workflow is executed after the move, **Then** it resolves the relocated app structure without manual path correction.
|
|
|
|
### Edge Cases
|
|
|
|
- A hybrid state could leave authoritative Laravel directories both at root and under `apps/platform`; the final structure must not require developers to remember which copy is real.
|
|
- The move could accidentally split `.env` truth between repo root and app root; the spec must prevent two competing application environment locations.
|
|
- Docker or Sail could start successfully while still mounting the wrong working directory, causing queue workers or asset builds to fail later.
|
|
- Asset builds could succeed while `public/index.php`, Vite manifest lookup, or Filament asset resolution still points at stale root paths.
|
|
- Editor tasks, MCP helpers, or agent configs may continue to call root-relative `artisan`, `phpunit`, `vite`, or `vendor/bin/sail` paths after the move.
|
|
- Open feature branches may become expensive to merge if the move lands without explicit branch and rollback communication.
|
|
- Dokploy or production runtime assumptions may differ from local assumptions and must remain visible as unresolved operational follow-up until verified.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
**Constitution alignment (required):** This feature introduces no new Microsoft Graph calls, no new product mutations, and no new domain workflow. It changes repository topology and runtime pathing only. Existing contract-registry usage, safety gates, audit logging, tenant isolation, and queued execution flows must continue to work unchanged after the move.
|
|
|
|
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** This feature must remain strictly structural. It may add documentation and repo-local delegation helpers, but it must not introduce shared packages, cross-app abstractions, new persistence, new state families, or speculative monorepo infrastructure.
|
|
|
|
**Constitution alignment (OPS-UX):** Existing `OperationRun`-backed features remain subject to the current Ops-UX contract. The relocation must not change run creation rules, progress surfaces, terminal notification behavior, or service-owned status transitions. Smoke validation must include queue and run-adjacent runtime proof so path changes do not silently break operational observability.
|
|
|
|
**Constitution alignment (RBAC-UX):** No authorization behavior changes are allowed. Tenant admin routes, tenant-context routes, workspace-context canonical routes, and system-plane routes must preserve the current `404` versus `403` semantics, server-side enforcement, global-search safety, and destructive-action confirmation requirements.
|
|
|
|
**Constitution alignment (OPS-EX-AUTH-001):** Not applicable. This feature does not alter `/auth/*` handshake behavior.
|
|
|
|
**Constitution alignment (BADGE-001):** Not applicable as a feature change. Existing badge semantics must remain unchanged because no operator-facing status model is being redesigned.
|
|
|
|
**Constitution alignment (UI-FIL-001):** The feature may touch Filament bootstrap and asset paths, but it must not create new local UI primitives, page-local status markup, or alternate design language. Existing shared Filament usage remains authoritative.
|
|
|
|
**Constitution alignment (UI-NAMING-001):** Not applicable as a naming change. Existing operator-facing labels, notifications, and audit prose must remain behaviorally unchanged.
|
|
|
|
**Constitution alignment (UI-CONST-001 / UI-SURF-001 / UI-HARD-001 / UI-EX-001 / UI-REVIEW-001):** No new operator-facing surfaces are introduced or reclassified. Existing routes and panels must retain their current canonical nouns, inspect models, and destructive-action placement.
|
|
|
|
**Constitution alignment (OPSURF-001):** No operator-surface redesign is part of this spec. If any incidental screen fix is required to preserve runtime after the move, it must preserve the existing page contract rather than using the relocation as a surface redesign opportunity.
|
|
|
|
**Constitution alignment (UI-SEM-001 / LAYER-001 / TEST-TRUTH-001):** The relocation must not introduce new semantic presenter layers or interpretation frameworks. Validation focuses on observable consequences: commands work, routes boot, panels load, queues run, and docs reflect reality.
|
|
|
|
**Constitution alignment (Filament Action Surfaces):** No Action Surface Contract changes are introduced. Existing Filament resources, pages, relation managers, and destructive actions must behave exactly as before once the app runs from `apps/platform`.
|
|
|
|
**Constitution alignment (UX-001 — Layout & Information Architecture):** No screen or layout redesign is part of this spec. Existing layout, empty-state, and infolist or form behavior must remain intact after the move.
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-182-001**: The system MUST relocate the authoritative Laravel application from the repo root to `apps/platform`.
|
|
- **FR-182-002**: The system MUST not leave an intentional hybrid steady state where core Laravel directories are actively maintained both at the repo root and under `apps/platform`.
|
|
- **FR-182-003**: The system MUST publish an explicit file-placement contract that distinguishes what stays at the repo root, what moves into `apps/platform`, and which exceptions were reviewed deliberately.
|
|
- **FR-182-004**: The repo root MUST remain the home for repo-wide docs, specs, scripts, editor config, agent config, and orchestration files after the move.
|
|
- **FR-182-005**: `apps/platform` MUST become the home for application code, runtime bootstrap files, tests, build inputs, public entry files, and app-local environment files.
|
|
- **FR-182-006**: The official local command model MUST define `apps/platform` as the canonical working directory for platform development commands.
|
|
- **FR-182-007**: All repo-maintained documentation, tasks, scripts, and helper instructions that describe local platform commands MUST be updated to the canonical command model.
|
|
- **FR-182-008**: Any retained root-level wrapper, alias, or helper MUST delegate transparently to `apps/platform`, be documented as non-canonical, and avoid creating a second primary workflow.
|
|
- **FR-182-009**: `apps/platform/.env.example` and `apps/platform/.env` MUST be the canonical Laravel environment files after the move.
|
|
- **FR-182-010**: Any root-level environment file kept for compose or host orchestration MUST be limited to compose-level concerns and MUST NOT become a second source of application configuration truth.
|
|
- **FR-182-011**: App-specific adjacent tooling, including database and local dev helpers such as `drizzle.config.ts`, MUST live with the platform app unless a repo-wide consumer is documented explicitly.
|
|
- **FR-182-012**: The relocated bootstrap chain MUST continue to resolve correct base paths for `artisan`, `bootstrap/app.php`, `bootstrap/providers.php`, `public/index.php`, route registration, config loading, cache paths, and storage paths.
|
|
- **FR-182-013**: Composer install, autoload generation, and application class discovery MUST work from `apps/platform` without manual path patching by developers.
|
|
- **FR-182-014**: Vite dev, Vite build, manifest generation, Tailwind source scanning, and public asset resolution MUST work from the relocated app without changing user-facing route structure.
|
|
- **FR-182-015**: Filament admin, tenant, and system panels, including theme resolution and registered assets, MUST render correctly after the move.
|
|
- **FR-182-016**: PHPUnit, Pest, and defined focused or smoke test runs MUST bootstrap successfully from `apps/platform`.
|
|
- **FR-182-017**: Docker and Sail container mounts, working-directory assumptions, worker commands, and local node-module handling MUST align with the relocated app.
|
|
- **FR-182-018**: Queue workers and at least one representative queued flow MUST start and run correctly under the relocated topology.
|
|
- **FR-182-019**: Repo-level editor tasks, MCP configuration, and agent configuration MUST target `apps/platform` explicitly or delegate there safely.
|
|
- **FR-182-020**: The feature MUST include a documented smoke validation pack covering local boot, CLI, build, public entry, panels, auth redirects, workspace-selection navigation, tenant-route authorization semantics including preserved `404` versus `403` behavior, queue, tests, and tooling.
|
|
- **FR-182-021**: The feature MUST include a documented rollback path covering git rollback, environment recovery, dependency and build artifact cleanup, Docker state, and communication for open branches.
|
|
- **FR-182-022**: The feature MUST document external deployment unknowns as explicit follow-up questions rather than assuming Dokploy or production behavior from local repo evidence alone.
|
|
- **FR-182-023**: The relocation MUST NOT introduce `apps/website`, shared packages, pnpm or Turbo or Nx orchestration, CI/CD redesign, or product feature work in the same slice.
|
|
- **FR-182-024**: The relocation MUST preserve existing product behavior, route semantics, authorization behavior, and data ownership behavior.
|
|
- **FR-182-025**: Smoke validation and documentation updates are part of done for this spec and MUST NOT be deferred to follow-up implementation work.
|
|
|
|
### Non-Functional Requirements
|
|
|
|
- **NFR-182-001**: The move should remain a single-slice topology change rather than a repo-wide platform rewrite.
|
|
- **NFR-182-002**: The official command model should be understandable from one concise documentation path without mixed primary workflows.
|
|
- **NFR-182-003**: The smoke pack should be runnable on a clean local setup without unpublished shell aliases or private machine knowledge.
|
|
|
|
### Non-Goals
|
|
|
|
- Creating `apps/website`
|
|
- Introducing a workspace toolchain such as pnpm workspaces, Turbo, Nx, Lerna, or similar orchestration
|
|
- Adding shared packages or a new `packages/` layer
|
|
- Rebuilding CI/CD, build-matrix, or deployment architecture in the same slice
|
|
- Delivering product features, governance changes, or UI workflow changes unrelated to the move
|
|
- Shipping new customer-facing, docs-facing, or API-facing surfaces in this spec
|
|
|
|
### Assumptions
|
|
|
|
- The existing Laravel application remains the only shipped app in this slice.
|
|
- `docker-compose.yml` remains a repo-level orchestration file after the move.
|
|
- Future additional apps or surfaces will be addressed in follow-up specs rather than pre-built here.
|
|
- Some staging or production runtime details cannot be proven from the repository alone and therefore remain explicit rollout questions.
|
|
|
|
### Dependencies
|
|
|
|
- Current Docker and Sail setup
|
|
- Current Composer, PHP, Vite, Tailwind, and Filament runtime behavior
|
|
- Current PHPUnit and Pest bootstrap behavior
|
|
- Current repo docs, tasks, scripts, and agent or MCP configuration that reference app paths
|
|
|
|
### Risks
|
|
|
|
- Docker and Sail may appear to boot while still using stale root working-directory assumptions.
|
|
- Hidden root-relative paths in scripts, tasks, or config files may only fail after merge rather than during the first boot.
|
|
- Asset output or Filament theme lookup may drift even if the PHP runtime itself boots successfully.
|
|
- Open branches may experience high merge friction if the move lands without explicit branch guidance.
|
|
- External deployment behavior may differ from local assumptions and must be treated as rollout risk until verified.
|
|
|
|
### External Operational Unknowns
|
|
|
|
- Actual Dokploy build context after the repo-root or app-root split
|
|
- Actual production working-directory expectations for web, queue, and scheduler processes
|
|
- Actual storage-volume and persistence mapping expectations outside local Sail
|
|
- Any unpublished shell aliases, wrapper scripts, or environment bootstraps currently used by operators or maintainers
|
|
|
|
### Key Entities *(include if feature involves data)*
|
|
|
|
- **Repo Root**: The repo-wide metadata and orchestration layer that remains after the app is moved out of root.
|
|
- **Platform App**: The existing Laravel application relocated to `apps/platform`.
|
|
- **File Placement Contract**: The documented decision set that assigns each reviewed file or directory to either repo root or app root.
|
|
- **Official Command Model**: The single canonical local workflow for running, building, testing, and maintaining the relocated platform app.
|
|
- **Environment Model**: The explicit separation between application env files in `apps/platform` and any optional compose-only env inputs at the repo root.
|
|
- **Smoke Validation Pack**: The required cross-runtime checks proving that the relocated topology still boots and behaves correctly.
|
|
- **Rollback Plan**: The documented recovery path for returning local and branch workflows to the pre-move state if needed.
|
|
- **External Unknowns Register**: The explicit list of deployment assumptions that cannot be proven solely from the repository.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-182-001**: From a clean checkout, a maintainer can follow the documented local workflow and reach a running platform entry surface in 20 minutes or less without needing unpublished path corrections.
|
|
- **SC-182-002**: 100% of repo-documented local platform commands for install, boot, build, format, and test use the canonical `apps/platform` workflow or a clearly labeled delegating helper.
|
|
- **SC-182-003**: 100% of the required smoke checks pass on the relocated topology before rollout approval.
|
|
- **SC-182-004**: No authoritative Laravel source directory or app-local manifest remains duplicated between repo root and `apps/platform` after cutover.
|
|
- **SC-182-005**: The documented rollback steps let a maintainer restore pre-move local operability, including env and artifact cleanup, in 30 minutes or less on a typical developer machine.
|
|
- **SC-182-006**: 100% of repo-maintained README, handover, task, and agent instructions that reference local platform commands are updated or explicitly deprecated before merge.
|
|
- **SC-182-007**: All external deployment assumptions needed for staging or production rollout are listed explicitly as follow-up questions before rollout approval.
|
|
|
|
### Measurement Protocol
|
|
|
|
- **MP-182-001**: Time-based success criteria are measured from the first documented command in `specs/182-platform-relocation/quickstart.md` on a clean local checkout where `apps/platform/.env`, `apps/platform/vendor/`, `apps/platform/node_modules/`, and app build artifacts are absent before setup begins.
|
|
- **MP-182-002**: **SC-182-001** stops when the documented CLI smoke passes and `http://localhost/admin/choose-workspace` returns the expected pre-move auth or workspace-selection response.
|
|
- **MP-182-003**: **SC-182-005** starts at the first documented rollback command and stops when rollback cleanup is complete and the restored local workflow reaches the documented post-rollback sanity state.
|
|
- **MP-182-004**: Timing evidence must record operating system, container runtime, whether Docker images were already available locally, and any intentionally skipped optional smoke steps.
|