209 lines
14 KiB
Markdown
209 lines
14 KiB
Markdown
# TenantPilot Workspace
|
||
|
||
TenantPilot is an Intune management platform built around a stable Laravel application in
|
||
`apps/platform` and, starting with Spec 183, a standalone public Astro website in
|
||
`apps/website`. The repository root is now the official JavaScript workspace entry point and
|
||
orchestrates app-local commands without becoming a runtime itself.
|
||
|
||
## Multi-App Topology
|
||
|
||
- `apps/platform`: the Laravel 12 + Filament v5 + Livewire v4 product runtime
|
||
- `apps/website`: the Astro v6 public website runtime
|
||
- repo root: workspace manifests, documentation, scripts, editor tooling, and `docker-compose.yml`
|
||
- `./scripts/platform-sail`: platform-only compatibility helper for tooling that cannot set `cwd`
|
||
|
||
## Official Root Commands
|
||
|
||
- Install workspace-managed JavaScript dependencies: `corepack pnpm install`
|
||
- Start the platform stack: `corepack pnpm dev:platform`
|
||
- Start the website dev server: `corepack pnpm dev:website`
|
||
- Start platform + website together: `corepack pnpm dev`
|
||
- Build the website: `corepack pnpm build:website`
|
||
- Build platform frontend assets: `corepack pnpm build:platform`
|
||
|
||
## App-Local Commands
|
||
|
||
### Platform
|
||
|
||
- Install PHP dependencies: `cd apps/platform && composer install`
|
||
- Start Sail: `cd apps/platform && ./vendor/bin/sail up -d`
|
||
- Generate the app key: `cd apps/platform && ./vendor/bin/sail artisan key:generate`
|
||
- Run migrations and seeders: `cd apps/platform && ./vendor/bin/sail artisan migrate --seed`
|
||
- Run frontend watch/build inside Sail: `cd apps/platform && ./vendor/bin/sail pnpm dev` or `cd apps/platform && ./vendor/bin/sail pnpm build`
|
||
- Run tests: `cd apps/platform && ./vendor/bin/sail artisan test --compact`
|
||
|
||
### Website
|
||
|
||
- Start the dev server: `cd apps/website && pnpm dev`
|
||
- Build the static site: `cd apps/website && pnpm build`
|
||
|
||
## Test Suite Governance
|
||
|
||
### Canonical Lane Commands
|
||
|
||
- Preferred repo-root wrappers:
|
||
- `./scripts/platform-test-lane fast-feedback`
|
||
- `./scripts/platform-test-lane confidence`
|
||
- `./scripts/platform-test-lane heavy-governance`
|
||
- `./scripts/platform-test-lane browser`
|
||
- `./scripts/platform-test-lane profiling`
|
||
- `./scripts/platform-test-lane junit`
|
||
- Regenerate the latest report artifacts without re-running the lane:
|
||
- `./scripts/platform-test-report fast-feedback`
|
||
- `./scripts/platform-test-report confidence`
|
||
- `./scripts/platform-test-report heavy-governance`
|
||
- `./scripts/platform-test-report browser`
|
||
- `./scripts/platform-test-report profiling`
|
||
- `./scripts/platform-test-report junit`
|
||
- App-local equivalents remain available through Sail Composer scripts:
|
||
- `cd apps/platform && ./vendor/bin/sail composer run test`
|
||
- `cd apps/platform && ./vendor/bin/sail composer run test:confidence`
|
||
- `cd apps/platform && ./vendor/bin/sail composer run test:heavy`
|
||
- `cd apps/platform && ./vendor/bin/sail composer run test:browser`
|
||
- `cd apps/platform && ./vendor/bin/sail composer run test:profile`
|
||
- `cd apps/platform && ./vendor/bin/sail composer run test:junit`
|
||
- The root wrapper is the safer default for long lanes because it pins Composer to `--timeout=0`.
|
||
|
||
### Recorded Baselines
|
||
|
||
| Scope | Wall clock | Budget | Notes |
|
||
|-------|------------|--------|-------|
|
||
| Full suite baseline | `2624.60s` | reference only | Current broad-suite measurement used as the budget anchor |
|
||
| `fast-feedback` | `176.74s` | `200s` | More than 50% below the current full-suite baseline |
|
||
| `confidence` | `394.38s` | `450s` | Broader non-browser pre-merge lane |
|
||
| `heavy-governance` | `83.66s` | `120s` | Seed heavy family lane for architecture, deprecation, ops UX, and action-surface scans |
|
||
| `browser` | `128.87s` | `150s` | Dedicated browser smoke and workflow lane |
|
||
| `junit` | `380.14s` | `450s` | Parallel machine-readable report lane for the confidence scope |
|
||
| `profiling` | `2701.51s` | `3000s` | Serial slow-test drift lane with profile output |
|
||
|
||
Artifacts are written under `apps/platform/storage/logs/test-lanes` and kept out of git except for the checked-in skeleton `.gitignore`.
|
||
|
||
### Honest Taxonomy Rules
|
||
|
||
- `Unit`: isolated logic, helpers, and low-cost domain behavior.
|
||
- `Feature`: HTTP, Livewire, Filament, jobs, and non-browser integration slices.
|
||
- `Browser`: only end-to-end browser smoke and workflow coverage under `tests/Browser`.
|
||
- `heavy-governance`: intentionally expensive architecture, deprecation, ops UX, and wide contract scans. The first seeded batch is `tests/Architecture`, `tests/Deprecation`, `tests/Feature/078`, `tests/Feature/090`, `tests/Feature/144`, `tests/Feature/OpsUx`, `tests/Feature/Filament/Alerts/AlertsKpiHeaderTest.php`, `tests/Feature/Guards/ActionSurfaceContractTest.php`, `tests/Feature/Guards/OperationLifecycleOpsUxGuardTest.php`, and `tests/Feature/ProviderConnections/CredentialLeakGuardTest.php`.
|
||
|
||
### Fixture Cost Guidance
|
||
|
||
- `createUserWithTenant()` now defaults to the explicit cheap `minimal` profile.
|
||
- Use `createMinimalUserWithTenant()` in high-usage callers that only need tenant membership and workspace/session wiring.
|
||
- Use `fixtureProfile: 'provider-enabled'` when a test needs a default Microsoft provider connection.
|
||
- Use `fixtureProfile: 'credential-enabled'` when provider identity resolution, admin-consent URLs, or Graph option construction needs dedicated credentials.
|
||
- Use `fixtureProfile: 'ui-context'` when the helper should also seed current tenant UI context and clear capability caches.
|
||
- Use `fixtureProfile: 'heavy'` only when the full side-effect bundle is intentionally required.
|
||
|
||
### DB Reset and Seed Rules
|
||
|
||
- Default lanes use SQLite `:memory:` with `RefreshDatabase` as the reset strategy.
|
||
- The isolated PostgreSQL coverage remains the `Pgsql` suite and is reserved for schema or foreign-key assertions.
|
||
- Keep seeds out of default lanes. Opt into seeded fixtures only inside the test that needs business-truth seed data.
|
||
- Schema-baseline or dump-based acceleration remains a follow-up investigation, not a default requirement for the current lane model.
|
||
|
||
## Port Overrides
|
||
|
||
- Platform HTTP and Vite ports: set `APP_PORT` and or `VITE_PORT` before `corepack pnpm dev:platform` or `cd apps/platform && ./vendor/bin/sail up -d`
|
||
- Website dev server port: set `WEBSITE_PORT` before `corepack pnpm dev:website` or pass `--port <port>` to `cd apps/website && pnpm dev`
|
||
- Parallel local development keeps both apps isolated, even when one or both ports are overridden
|
||
|
||
## Platform Setup Notes
|
||
|
||
- Filament admin: `/admin` (seed user `test@example.com`, set password via factory or `artisan tinker`).
|
||
- Microsoft Graph (Intune) env vars:
|
||
- `GRAPH_TENANT_ID`
|
||
- `GRAPH_CLIENT_ID`
|
||
- `GRAPH_CLIENT_SECRET`
|
||
- `GRAPH_SCOPE` (default `https://graph.microsoft.com/.default`)
|
||
- Without these, the `NullGraphClient` runs in dry mode (no Graph calls).
|
||
- **Required API Permissions**: See [docs/PERMISSIONS.md](docs/PERMISSIONS.md) for complete list
|
||
- **Missing permissions?** Scope tags will show as "Unknown (ID: X)" - add `DeviceManagementRBAC.Read.All`
|
||
- Deployment (Dokploy, staging → production):
|
||
- Containerized deploy; ensure Postgres + Redis are provisioned (see `docker-compose.yml` for local baseline).
|
||
- Run application commands from `apps/platform`, including `php artisan filament:assets`.
|
||
- Run migrations on staging first, validate backup/restore flows, then promote to production.
|
||
- Ensure queue workers are running for jobs (e.g., policy sync) after deploy.
|
||
- Keep secrets/env in Dokploy, never in code.
|
||
|
||
## Platform relocation rollout notes
|
||
|
||
- Open branches that still touch legacy root app paths should merge `dev` first, then remap file moves from `app/`, `bootstrap/`, `config/`, `database/`, `lang/`, `public/`, `resources/`, `routes/`, `storage/`, and `tests/` into `apps/platform/...`.
|
||
- Keep using merge-based catch-up on shared feature branches; do not rebase long-lived shared branches just to absorb the relocation.
|
||
- VS Code tasks expose the official root workspace commands, while MCP launchers remain platform-only and delegate through `./scripts/platform-sail`.
|
||
|
||
## Bulk operations (Feature 005)
|
||
|
||
- Bulk actions are available in Filament resource tables (Policies, Policy Versions, Backup Sets, Restore Runs).
|
||
- Destructive operations require type-to-confirm at higher thresholds (e.g. `DELETE`).
|
||
- Long-running bulk ops are queued; the bottom-right progress widget polls for active runs.
|
||
|
||
### Troubleshooting
|
||
|
||
- **Progress stuck on “Queued…”** usually means the queue worker is not running (or not processing the queue you expect).
|
||
- Prefer using the Sail/Docker worker (see `docker-compose.yml`) rather than starting an additional local `php artisan queue:work`.
|
||
- Check worker status/logs: `cd apps/platform && ./vendor/bin/sail ps` and `cd apps/platform && ./vendor/bin/sail logs -f queue`.
|
||
- **Exit code 137** for `queue:work` typically means the process was killed (often OOM). Increase Docker memory/limits or run the worker inside the container.
|
||
- **Moved app but old commands still fail** usually means the command is still being run from repo root. Switch to `cd apps/platform && ...` or use `./scripts/platform-sail ...` only for tooling that cannot set `cwd`.
|
||
|
||
## Rollback checklist
|
||
|
||
1. Revert the relocation commit or merge on your feature branch instead of hard-resetting shared history.
|
||
2. Preserve any local app env overrides before switching commits: `cp apps/platform/.env /tmp/tenantatlas.platform.env.backup` if needed.
|
||
3. Stop local containers and clean generated artifacts: `cd apps/platform && ./vendor/bin/sail down -v`, then remove `apps/platform/vendor`, `apps/platform/node_modules`, `apps/platform/public/build`, and `apps/platform/public/hot` if they need a clean rebuild.
|
||
4. After rollback, restore the matching env file for the restored topology and rerun the documented setup flow for that commit.
|
||
5. Notify owners of open feature branches that the topology changed so they can remap outstanding work before the next merge from `dev`.
|
||
|
||
## Deployment unknowns
|
||
|
||
- Dokploy build context for a repo-root compose file plus an app-root Laravel runtime still needs staging confirmation.
|
||
- Production web, queue, and scheduler working directories must be verified explicitly after the move; do not assume repo root and app root behave interchangeably.
|
||
- Any Dokploy volume mounts or storage persistence paths that previously targeted repo-root `storage/` must be reviewed against `apps/platform/storage/`.
|
||
|
||
### Configuration
|
||
|
||
- `TENANTPILOT_BULK_CHUNK_SIZE` (default `10`): job refresh/progress chunk size.
|
||
- `TENANTPILOT_BULK_POLL_INTERVAL_SECONDS` (default `3`): Livewire polling interval for the progress widget (clamped to 1–10s).
|
||
|
||
## Intune RBAC Onboarding Wizard
|
||
|
||
- Entry point: Tenant detail in Filament (`Setup Intune RBAC` in the ⋯ ActionGroup). Visible only for active tenants with `app_client_id`.
|
||
- Flow (synchronous, delegated):
|
||
1) Configure Role (default Policy/Profile Manager), Scope (global or scope group), Group mode (create default `TenantPilot-Intune-RBAC` or pick existing security-enabled group). Review planned changes.
|
||
2) Delegated admin login (short-lived token, **not** stored in DB/cache).
|
||
3) Execute: resolve service principal, ensure/validate security group, ensure membership, ensure/create/patch Intune role assignment; persists IDs on tenant for idempotency; no queue.
|
||
4) Post-verify: forces fresh token, runs canary reads (deviceConfigurations/deviceCompliancePolicies; CA canary only if feature enabled), updates health and warnings (scope-limited, CA disabled, manual assignment required).
|
||
- Safety/notes: least-privilege default, idempotent reruns, “already exists” treated as success. If service principal missing, run Admin consent first. Scope-limited setups may yield partial inventory/restore; warnings are surfaced in UI and health panel.
|
||
|
||
## Graph Contract Registry & Drift Guard
|
||
|
||
- Registry: `config/graph_contracts.php` defines per-type contracts (resource paths, allowed `$select`/`$expand`, @odata.type family, create/update methods, id field, hydration).
|
||
- Client behavior:
|
||
- Sanitizes `$select`/`$expand` to allowed fields; logs warnings on trim.
|
||
- Derived @odata.type values within the family are accepted for preview/restore routing.
|
||
- Capability fallback: on 400s related to select/expand, retries without those clauses and surfaces warnings.
|
||
- Drift check: `cd apps/platform && php artisan graph:contract:check [--tenant=]` runs lightweight probes against contract endpoints to detect capability/shape issues; useful in staging/CI (prod optional).
|
||
- If Graph returns capability errors, TenantPilot downgrades safely, records warnings/audit entries, and avoids breaking preview/restore flows.
|
||
|
||
## Policy Settings Display
|
||
|
||
- Policy detail pages render normalized settings instead of raw JSON:
|
||
- OMA-URI/custom policies → path/value table
|
||
- Settings Catalog → flattened key/value entries
|
||
- Standard objects → labeled key/value view with metadata filtered
|
||
- Version detail pages show both pretty-printed JSON and normalized settings.
|
||
- Warnings surface malformed snapshots or @odata.type mismatches before restore.
|
||
|
||
## Policy JSON Viewer (Feature 002)
|
||
|
||
- **Location**: Policy View pages (`/admin/policies/{record}`)
|
||
- **Capability**: Pretty-printed JSON snapshot viewer with copy-to-clipboard
|
||
- **Settings Catalog Enhancement**: Dual-view tabs (Settings table + JSON viewer) for Settings Catalog policies
|
||
- **Features**:
|
||
- Copy JSON to clipboard with success message
|
||
- Large payload detection (>500 KB) with warning badge and auto-collapse
|
||
- Dark mode support integrated with Filament design system
|
||
- Browser native search (Cmd+F / Ctrl+F) for finding specific keys or values
|
||
- Scrollable container with max height to prevent page overflow
|
||
- **Usage**: See `specs/002-filament-json/quickstart.md` for detailed examples and configuration
|
||
- **Performance**: Optimized for payloads up to 1 MB; auto-collapse improves initial render for large snapshots
|