|
| 1 | +# CLI Commands |
| 2 | + |
| 3 | +Complete reference for all Neev Artisan commands. Commands adapt to your [identity strategy](./architecture.md) — in **shared** mode they operate on teams, in **isolated** mode they operate on tenants. |
| 4 | + |
| 5 | +> Run `php artisan list neev` to see all available commands. |
| 6 | +
|
| 7 | +--- |
| 8 | + |
| 9 | +## Setup & Maintenance |
| 10 | + |
| 11 | +These commands handle initial setup and scheduled maintenance. |
| 12 | + |
| 13 | +### `neev:install` |
| 14 | + |
| 15 | +Interactive setup wizard for new installations. |
| 16 | + |
| 17 | +```bash |
| 18 | +php artisan neev:install |
| 19 | +``` |
| 20 | + |
| 21 | +Prompts for: team support, email verification, domain federation, tenant isolation. Publishes config and migrations. |
| 22 | + |
| 23 | +### `neev:download-geoip` |
| 24 | + |
| 25 | +Download the MaxMind GeoLite2 database for IP geolocation. |
| 26 | + |
| 27 | +```bash |
| 28 | +php artisan neev:download-geoip |
| 29 | +``` |
| 30 | + |
| 31 | +Requires `MAXMIND_LICENSE_KEY` in your `.env`. |
| 32 | + |
| 33 | +### `neev:clean-login-attempts` |
| 34 | + |
| 35 | +Remove login attempt records older than the configured retention period. |
| 36 | + |
| 37 | +```bash |
| 38 | +php artisan neev:clean-login-attempts |
| 39 | +``` |
| 40 | + |
| 41 | +Retention is controlled by `config('neev.last_login_attempts_in_days')`. |
| 42 | + |
| 43 | +### `neev:clean-passwords` |
| 44 | + |
| 45 | +Remove expired password history records. |
| 46 | + |
| 47 | +```bash |
| 48 | +php artisan neev:clean-passwords |
| 49 | +``` |
| 50 | + |
| 51 | +--- |
| 52 | + |
| 53 | +## Tenant / Team Provisioning |
| 54 | + |
| 55 | +These commands create and inspect tenants (isolated mode) or teams (shared mode). |
| 56 | + |
| 57 | +### `neev:tenant:create` |
| 58 | + |
| 59 | +Create a new tenant or team. |
| 60 | + |
| 61 | +```bash |
| 62 | +# Shared mode — creates a team |
| 63 | +php artisan neev:tenant:create "Acme Corp" --owner=admin@acme.com --activate |
| 64 | + |
| 65 | +# Isolated mode — creates a tenant with platform team |
| 66 | +php artisan neev:tenant:create "Acme Corp" --owner=admin@acme.com --domain=acme.yourapp.com |
| 67 | + |
| 68 | +# With custom slug and parent tenant (isolated) |
| 69 | +php artisan neev:tenant:create "Sub Tenant" --slug=sub-tenant --managed-by=acme-corp |
| 70 | +``` |
| 71 | + |
| 72 | +| Argument / Option | Description | |
| 73 | +|-------------------|-------------| |
| 74 | +| `name` | Name of the tenant or team (prompted if omitted) | |
| 75 | +| `--slug=` | Custom slug (auto-generated from name if omitted) | |
| 76 | +| `--owner=` | Owner by user ID or email address | |
| 77 | +| `--domain=` | Attach a domain (auto-verifies subdomains, shows DNS instructions for custom) | |
| 78 | +| `--activate` | Activate the team immediately | |
| 79 | +| `--managed-by=` | Parent tenant ID or slug (isolated mode only) | |
| 80 | + |
| 81 | +**Shared mode**: Creates a `Team` with the given owner. If `--activate` is passed, sets `activated_at`. |
| 82 | + |
| 83 | +**Isolated mode**: Creates a `Tenant`. If `--owner` is provided, also creates a platform team with the owner attached. If `--domain` is provided, attaches it to the tenant. |
| 84 | + |
| 85 | +### `neev:tenant:list` |
| 86 | + |
| 87 | +List all tenants or teams. |
| 88 | + |
| 89 | +```bash |
| 90 | +# Default table output |
| 91 | +php artisan neev:tenant:list |
| 92 | + |
| 93 | +# Filter and format |
| 94 | +php artisan neev:tenant:list --search=acme --limit=10 |
| 95 | +php artisan neev:tenant:list --inactive --json |
| 96 | +``` |
| 97 | + |
| 98 | +| Option | Description | |
| 99 | +|--------|-------------| |
| 100 | +| `--search=` | Filter by name or slug | |
| 101 | +| `--inactive` | Show only inactive entries (shared mode) | |
| 102 | +| `--json` | Output as JSON | |
| 103 | +| `--limit=25` | Maximum number of results | |
| 104 | + |
| 105 | +**Shared mode columns**: ID, Name, Slug, Members, Status, Created. |
| 106 | +**Isolated mode columns**: ID, Name, Slug, Teams, Created. |
| 107 | + |
| 108 | +### `neev:tenant:show` |
| 109 | + |
| 110 | +Show details for a tenant or team. Resolves by ID, slug, or domain. |
| 111 | + |
| 112 | +```bash |
| 113 | +php artisan neev:tenant:show acme-corp |
| 114 | +php artisan neev:tenant:show 42 |
| 115 | +php artisan neev:tenant:show app.acme.com |
| 116 | +php artisan neev:tenant:show acme-corp --json |
| 117 | +``` |
| 118 | + |
| 119 | +| Argument / Option | Description | |
| 120 | +|-------------------|-------------| |
| 121 | +| `identifier` | ID, slug, or domain (prompted if omitted) | |
| 122 | +| `--json` | Output as JSON | |
| 123 | + |
| 124 | +Displays: name, ID, slug, status, owner, member/team count, domains, auth config summary. |
| 125 | + |
| 126 | +--- |
| 127 | + |
| 128 | +## Domain Management |
| 129 | + |
| 130 | +Manage domains attached to tenants or teams. |
| 131 | + |
| 132 | +### `neev:domain:add` |
| 133 | + |
| 134 | +Add a domain to a tenant or team. |
| 135 | + |
| 136 | +```bash |
| 137 | +# Add subdomain (auto-verified if it matches your subdomain suffix) |
| 138 | +php artisan neev:domain:add acme.yourapp.com --team=acme-corp --primary |
| 139 | + |
| 140 | +# Add custom domain (requires DNS verification) |
| 141 | +php artisan neev:domain:add app.acme.com --tenant=acme-corp |
| 142 | + |
| 143 | +# Skip verification (local dev) |
| 144 | +php artisan neev:domain:add custom.local --team=1 --skip-verification |
| 145 | +``` |
| 146 | + |
| 147 | +| Argument / Option | Description | |
| 148 | +|-------------------|-------------| |
| 149 | +| `domain` | The domain to add (prompted if omitted) | |
| 150 | +| `--tenant=` | Tenant ID or slug | |
| 151 | +| `--team=` | Team ID or slug | |
| 152 | +| `--primary` | Set as primary domain | |
| 153 | +| `--enforce` | Enforce domain-based federation | |
| 154 | +| `--skip-verification` | Mark as verified immediately | |
| 155 | + |
| 156 | +Subdomains matching `config('neev.tenant_isolation_options.subdomain_suffix')` are automatically verified. Custom domains display DNS TXT record instructions. |
| 157 | + |
| 158 | +### `neev:domain:verify` |
| 159 | + |
| 160 | +Verify a domain via DNS TXT record lookup. |
| 161 | + |
| 162 | +```bash |
| 163 | +# Check DNS and verify |
| 164 | +php artisan neev:domain:verify app.acme.com |
| 165 | + |
| 166 | +# Force-verify without DNS check (local dev) |
| 167 | +php artisan neev:domain:verify app.acme.com --force |
| 168 | +``` |
| 169 | + |
| 170 | +| Argument / Option | Description | |
| 171 | +|-------------------|-------------| |
| 172 | +| `domain` | The domain to verify (prompted if omitted) | |
| 173 | +| `--force` | Mark verified without DNS check | |
| 174 | + |
| 175 | +Performs a `dns_get_record()` lookup on `_neev-verification.{domain}` and matches the TXT value against the stored verification token. |
| 176 | + |
| 177 | +### `neev:domain:list` |
| 178 | + |
| 179 | +List domains with optional filters. |
| 180 | + |
| 181 | +```bash |
| 182 | +php artisan neev:domain:list |
| 183 | +php artisan neev:domain:list --tenant=acme-corp --unverified |
| 184 | +php artisan neev:domain:list --team=1 --json |
| 185 | +``` |
| 186 | + |
| 187 | +| Option | Description | |
| 188 | +|--------|-------------| |
| 189 | +| `--tenant=` | Filter by tenant ID or slug | |
| 190 | +| `--team=` | Filter by team ID or slug | |
| 191 | +| `--unverified` | Show only unverified domains | |
| 192 | +| `--json` | Output as JSON | |
| 193 | + |
| 194 | +Columns: ID, Domain, Team ID, Tenant ID, Primary, Enforce, Status. |
| 195 | + |
| 196 | +--- |
| 197 | + |
| 198 | +## Member Management |
| 199 | + |
| 200 | +Add, remove, and list team members. These commands operate on the team membership pivot table directly, bypassing the invitation flow. |
| 201 | + |
| 202 | +### `neev:member:add` |
| 203 | + |
| 204 | +Add a user to a team directly. |
| 205 | + |
| 206 | +```bash |
| 207 | +# Add by team |
| 208 | +php artisan neev:member:add user@example.com --team=acme-corp --role=editor |
| 209 | + |
| 210 | +# Add to tenant's platform team |
| 211 | +php artisan neev:member:add user@example.com --tenant=acme-corp --role=member |
| 212 | +``` |
| 213 | + |
| 214 | +| Argument / Option | Description | |
| 215 | +|-------------------|-------------| |
| 216 | +| `email` | Email of the user to add (prompted if omitted) | |
| 217 | +| `--team=` | Team ID or slug | |
| 218 | +| `--tenant=` | Tenant ID or slug (adds to platform team) | |
| 219 | +| `--role=` | Role to assign | |
| 220 | + |
| 221 | +Looks up the user via the `emails` table and attaches them with `joined=true`. |
| 222 | + |
| 223 | +### `neev:member:remove` |
| 224 | + |
| 225 | +Remove a user from a team. |
| 226 | + |
| 227 | +```bash |
| 228 | +php artisan neev:member:remove user@example.com --team=acme-corp |
| 229 | +php artisan neev:member:remove user@example.com --team=acme-corp --force |
| 230 | +``` |
| 231 | + |
| 232 | +| Argument / Option | Description | |
| 233 | +|-------------------|-------------| |
| 234 | +| `email` | Email of the user to remove (prompted if omitted) | |
| 235 | +| `--team=` | Team ID or slug (required) | |
| 236 | +| `--force` | Skip confirmation prompt | |
| 237 | + |
| 238 | +Refuses to remove the team owner. |
| 239 | + |
| 240 | +### `neev:member:list` |
| 241 | + |
| 242 | +List members of a team or tenant. |
| 243 | + |
| 244 | +```bash |
| 245 | +php artisan neev:member:list --team=acme-corp |
| 246 | +php artisan neev:member:list --tenant=acme-corp --json |
| 247 | +``` |
| 248 | + |
| 249 | +| Option | Description | |
| 250 | +|--------|-------------| |
| 251 | +| `--team=` | Team ID or slug | |
| 252 | +| `--tenant=` | Tenant ID or slug (lists platform team members) | |
| 253 | +| `--json` | Output as JSON | |
| 254 | + |
| 255 | +Columns: ID, Name, Email, Role, Joined, Since. |
| 256 | + |
| 257 | +--- |
| 258 | + |
| 259 | +## Auth / SSO Configuration |
| 260 | + |
| 261 | +Configure per-tenant or per-team authentication methods. |
| 262 | + |
| 263 | +### `neev:auth:configure` |
| 264 | + |
| 265 | +Configure the authentication method for a tenant or team. Interactive when options are omitted. |
| 266 | + |
| 267 | +```bash |
| 268 | +# Set password auth |
| 269 | +php artisan neev:auth:configure --team=acme-corp --method=password |
| 270 | + |
| 271 | +# Configure SSO interactively |
| 272 | +php artisan neev:auth:configure --tenant=acme-corp --method=sso |
| 273 | + |
| 274 | +# Full non-interactive SSO setup |
| 275 | +php artisan neev:auth:configure --tenant=acme-corp \ |
| 276 | + --method=sso \ |
| 277 | + --sso-provider=entra \ |
| 278 | + --sso-client-id=your-client-id \ |
| 279 | + --sso-client-secret=your-secret \ |
| 280 | + --sso-tenant-id=your-azure-tenant-id \ |
| 281 | + --auto-provision \ |
| 282 | + --auto-provision-role=member |
| 283 | +``` |
| 284 | + |
| 285 | +| Option | Description | |
| 286 | +|--------|-------------| |
| 287 | +| `--tenant=` | Tenant ID or slug | |
| 288 | +| `--team=` | Team ID or slug | |
| 289 | +| `--method=` | Auth method: `password` or `sso` | |
| 290 | +| `--sso-provider=` | SSO provider: `entra`, `google`, or `okta` | |
| 291 | +| `--sso-client-id=` | SSO client ID | |
| 292 | +| `--sso-client-secret=` | SSO client secret | |
| 293 | +| `--sso-tenant-id=` | SSO tenant/directory ID (required for Entra) | |
| 294 | +| `--auto-provision` | Enable auto-provisioning of SSO users | |
| 295 | +| `--auto-provision-role=` | Role for auto-provisioned users | |
| 296 | + |
| 297 | +Creates or updates `TenantAuthSettings` (isolated) or `TeamAuthSettings` (shared). Validates the provider against `config('neev.tenant_auth_options.sso_providers')`. |
| 298 | + |
| 299 | +### `neev:auth:show` |
| 300 | + |
| 301 | +Display the authentication configuration. |
| 302 | + |
| 303 | +```bash |
| 304 | +php artisan neev:auth:show --tenant=acme-corp |
| 305 | +php artisan neev:auth:show --team=1 --reveal |
| 306 | +php artisan neev:auth:show --team=1 --json |
| 307 | +``` |
| 308 | + |
| 309 | +| Option | Description | |
| 310 | +|--------|-------------| |
| 311 | +| `--tenant=` | Tenant ID or slug | |
| 312 | +| `--team=` | Team ID or slug | |
| 313 | +| `--reveal` | Show client ID (client secret is **never** shown) | |
| 314 | +| `--json` | Output as JSON | |
| 315 | + |
| 316 | +--- |
| 317 | + |
| 318 | +## Team Lifecycle |
| 319 | + |
| 320 | +### `neev:team:activate` |
| 321 | + |
| 322 | +Activate or deactivate a team. |
| 323 | + |
| 324 | +```bash |
| 325 | +# Activate |
| 326 | +php artisan neev:team:activate acme-corp |
| 327 | + |
| 328 | +# Deactivate with reason |
| 329 | +php artisan neev:team:activate acme-corp --deactivate --reason="Non-payment" |
| 330 | +``` |
| 331 | + |
| 332 | +| Argument / Option | Description | |
| 333 | +|-------------------|-------------| |
| 334 | +| `team` | Team ID or slug (prompted if omitted) | |
| 335 | +| `--deactivate` | Deactivate instead of activate | |
| 336 | +| `--reason=` | Reason for deactivation | |
| 337 | + |
| 338 | +Calls the existing `$team->activate()` / `$team->deactivate($reason)` methods. |
| 339 | + |
| 340 | +--- |
| 341 | + |
| 342 | +## Scripting & Automation |
| 343 | + |
| 344 | +All list and show commands support `--json` for machine-readable output: |
| 345 | + |
| 346 | +```bash |
| 347 | +# Pipe to jq |
| 348 | +php artisan neev:tenant:list --json | jq '.[].slug' |
| 349 | + |
| 350 | +# Use in shell scripts |
| 351 | +TENANT_ID=$(php artisan neev:tenant:show acme-corp --json | jq -r '.id') |
| 352 | +``` |
| 353 | + |
| 354 | +All commands that accept required arguments implement `PromptsForMissingInput` — they work interactively when arguments are omitted and non-interactively when all arguments are supplied. |
0 commit comments