Getting Started
Enable the Movements module, let its migration build the tables and seed the mobility policy, grant the right people access, and (optionally) load demo data — then record your first movement and post your first internal opening.
Prerequisites
- PHP 8.2+ and a current ERPat core — the module runs through ERPat's HMVC compatibility layer, so no extra runtime is needed.
- Admin access to Settings → Manage Modules and to the Roles editor.
- Active staff users must exist. Movements and applications both attach to staff users. Departments (ERPat "teams") and, ideally, the Job Positions catalog should be set up so movements can name a "to" department and position.
- A ticking cron runtime if you want automatic movement capture and the daily close-expired-openings sweep — see Switch on the crons.
Activation — three steps
-
Run the module migration
From the project root. The migration is idempotent and reversible, creates all six tables, and seeds the mobility settings defaults. It is tracked in its own
migrations_movementstable and runs against the primary and every tenant database.php erpat migrate:modules # (or) php erpat migrate:latest -
Turn the module on
Go to Settings → Manage Modules and enable Movements (listed under the Human Resource category — this sets
module_movements = 1). An HR Operations group appears in the left sidebar for every user who also holds the matching permission. -
Grant permissions (for non-admins)
In Roles, assign the Human Resource: Mobility permission categories to the roles that need them. Administrators see everything by default. See Granting access below and the full matrix on Administration & Controls.
What the migration creates
One initial-schema migration builds the whole data model — every statement is guarded, so re-running it is safe:
| Area | Tables created |
|---|---|
| Employee Movement | employee_movements (the immutable audit trail),
employee_movement_snapshots (per-employee state for auto-capture) |
| Internal Hiring | internal_openings, internal_applications,
internal_application_stages (stage history),
mobility_overrides (audited policy exceptions) |
Full column-by-column detail is in the Data & Screen Reference. The migration also seeds the mobility settings below (insert-only — it never overrides values a tenant has already changed).
Seeded mobility policy defaults (12 settings)
Out of the box, the policy is "3 internal applications per rolling 6 months," salary is HR-only, and automatic capture is on:
| Setting | Default | What it controls |
|---|---|---|
movements_max_actions | 3 | Allowed mobility actions in the rolling window. |
movements_window_months | 6 | Length of the rolling window, in months. |
movements_count_withdrawn | 1 (on) | Withdrawn applications still count toward the limit. |
movements_withdrawal_grace_hours | 0 (off) | A withdrawal within this many hours of submitting releases the count. |
movements_min_tenure_months | 0 (off) | Minimum tenure before an employee may apply. |
movements_block_disciplinary | 1 (on) | Block employees with an active disciplinary case. |
movements_allow_override | 1 (on) | Allow audited policy exception requests. |
movements_auto_post_announcement | 1 (on) | Publishing an opening may post to Announcements. |
movements_auto_post_timeline | 0 (off) | Publishing an opening may post to the Timeline. |
movements_auto_capture | 1 (on) | The daily job captures Employee Master changes. |
movements_self_movement_tab | 1 (on) | Show "My Movement History" on employee profiles. |
movements_salary_visibility | hr_only | Who may see salary changes (HR only, or the employee + HR). |
You change these under HR Operations → Mobility Settings (or the Mobility Settings tab in core Settings). Each key is explained in Administration → Settings.
Granting access in Roles
While the module is enabled, the Human Resource: Mobility permission category appears in the
Roles editor with 10 keys. The base movements permit (labelled
"Employee Movements") unlocks the movement audit table; each other surface has its own
base key plus create/update/delete children.
| Surface | Base permission | Extra keys |
|---|---|---|
| Employee Movement | movements | movements_create, movements_update (reverse), movements_delete, movements_view_salary |
| Internal Hiring | internal_hiring | internal_hiring_publish, internal_hiring_select, mobility_override |
| Internal Job Portal | — none — | Self-service: any active staff member (gated only by the module toggle). |
| Mobility Settings | movements_settings | — |
movements_view_salary is a cross-cutting gate. It reveals the salary columns
on the movement table, lets HR set salary values on a manual movement or a candidate selection,
and reveals the salary range on an opening.
Grant it only to people who should see pay.
A tour of the HR Operations menu
With the module enabled and the matching permissions granted, the sidebar gains an HR Operations group with up to four items:
| # | Menu item | URL | Opens |
|---|---|---|---|
| 1 | Employee Movement | movements | The movement audit table — record, view, reverse, delete. |
| 2 | Internal Hiring | internal-hiring | Openings, candidate pipeline and mobility overrides (tabs). |
| 3 | Internal Job Portal | internal-jobs | Staff self-service — browse, check eligibility, apply. |
| 4 | Mobility Settings | movements-settings | The 12 policy / automation / privacy settings. |
Each staff member also gets self-service tabs on their own profile: "My Movement History" and "My Internal Applications" (and HR sees "Employee Movement" on any profile). See Administration → Profile tabs.
Switch on the crons
The module ships two scheduled jobs on ERPat's Advanced Cron runtime. They run only if your server is ticking the runtime (or you tick it manually), and each self-gates on the module being enabled:
php erpat cron:list # confirm the two Movements jobs are registered
php erpat cron:tick # run whatever is due right now
php erpat cron:run movements_capture_employee_movements # force a single job| Job (slug) | Schedule | What it does |
|---|---|---|
movements_capture_employee_movements |
Daily, 02:20 | Diffs each employee's department / position / salary against the last snapshot and
records movement rows for real changes. First run seeds baselines only. Respects the
movements_auto_capture setting. |
movements_close_expired_openings |
Daily, 01:10 | Moves published internal openings past their closing date to closed, so the portal never accepts applications for expired openings. |
Load demo data (optional)
To explore every screen with realistic sample data, run the demo seeder. It attaches sample rows to the first active staff users already on the database — it fabricates nothing if no users exist, and it is fully idempotent and reversible.
php erpat db:seed MovementsDemo # seed sample data
php erpat db:seed MovementsDemo --dry-run # preview without writing
php erpat db:seed MovementsDemo --remove # soft-delete the demo rowsIt seeds two internal openings (one published, one draft), one submitted application with stage history, two employee movements, and a pending mobility override. You can also load it from the Bulk Database Seeder modal in the Tenants console.
First-run checklist
Who: an administrator (or a role holding the Mobility permissions).
Preconditions: migration run, module enabled, at least one active staff user and department.
-
Enable and verify
Run
php erpat migrate:modules, enable Movements in Manage Modules, and confirm the HR Operations group appears in your sidebar. -
Grant roles
In Roles, give your HR roles the Mobility permissions they need. Decide who gets
movements_view_salary. Employees need nothing extra to use the job portal. -
Review the mobility settings
Open HR Operations → Mobility Settings and confirm the defaults suit your policy — the limit, the window, whether withdrawals count, minimum tenure, and salary visibility.
-
Record your first movement
Open Employee Movement → Record movement, pick an employee (the current department, position and salary auto-fill), choose a type, and save. It appears immediately on the audit table and the employee's profile.
-
Publish your first opening
Open Internal Hiring → Create opening, fill the title and target, save as a draft, then submit it for approval and Publish. Sign in as a staff member and confirm it appears on the Internal Job Portal.
-
Switch on the crons
Make sure your server ticks the cron runtime so auto-capture and the expiry sweep run daily.