Files
SkinbaseNova/docs/cli-reference.md
T
test 9c537e08d0 Wire new routes and environment keys for the recent modules.
Register AdSense, artwork review, comment captcha, lazy collections, and upload review props, and document the matching env vars and CLI commands.
2026-09-20 14:51:04 +02:00

321 lines
24 KiB
Markdown

# Skinbase26 CLI Reference
Last updated: 2026-05-19
This document lists the repository-specific command-line entry points in Skinbase26.
Scope:
- Custom Artisan commands from `app/Console/Commands`
- Maintained standalone scripts in the repo root and `scripts/`
- Ad hoc and temporary scripts that are still present in the workspace
Not included:
- Built-in Laravel Artisan commands such as `migrate`, `queue:work`, `cache:clear`, and similar framework defaults
- Raw SQL files such as `missing_users.sql` or `recover-users.sql`
Examples below are representative. For the full option list of any Artisan command, run `php artisan help <command>`.
## Main Entry Points
| Entry point | Why it is used | Example |
| --- | --- | --- |
| `php artisan` | Main Laravel CLI for all custom app commands listed below | `php artisan list --raw` |
| `deploy.cmd` / `deploy.bat` | Windows Command Prompt production deploy entrypoint; switches into WSL and runs `deploy.sh` | `deploy.cmd` |
| `bash deploy.sh` | Canonical bash production deploy entrypoint; stages versioned releases and switches `current` | `bash deploy.sh` |
| `bash sync.sh` | Legacy alias for `bash deploy.sh` | `bash sync.sh` |
| `bash sync_dev.sh` | Push the development environment to the configured remote dev host | `bash sync_dev.sh` |
## Maintained Standalone Scripts
| Script | Why it is used | Example |
| --- | --- | --- |
| `scripts/deploy-production.sh` | Safe production deployment wrapper that resolves to the retained-release deploy workflow with a server-side current-release switch | `bash scripts/deploy-production.sh --mode=normal` |
| `scripts/rollback-production.sh` | Switch the active production release to a previously retained server-side deployment | `bash scripts/rollback-production.sh --previous` |
| `scripts/push-db-to-prod.sh` | Push the local database to production with remote backup controls | `bash scripts/push-db-to-prod.sh --force` |
| `scripts/render-nova-card.cjs` | Render a Nova card screenshot through Playwright | `node scripts/render-nova-card.cjs --url=https://example.test/card --out=tmp/card.png` |
| `scripts/vision-smoke.ps1` | Smoke-test the configured Vision API from PowerShell | `powershell -ExecutionPolicy Bypass -File scripts/vision-smoke.ps1` |
## Custom Artisan Commands
### Analytics
| Command | Why it is used | Example |
| --- | --- | --- |
| `analytics:aggregate-discovery-feedback` | Aggregate discovery feedback events into daily metrics by algorithm and surface | `php artisan analytics:aggregate-discovery-feedback --date=2026-04-16` |
| `analytics:aggregate-feed` | Aggregate feed analytics into daily metrics by algorithm version and source | `php artisan analytics:aggregate-feed --date=2026-04-16` |
| `analytics:aggregate-similar-artworks` | Aggregate similar-artwork analytics into daily counts by algorithm version | `php artisan analytics:aggregate-similar-artworks --date=2026-04-16` |
| `analytics:aggregate-tag-interactions` | Aggregate tag-interaction analytics by surface, tag, source tag, and query | `php artisan analytics:aggregate-tag-interactions --date=2026-04-16` |
| `analytics:compare-feed-ab` | Compare baseline versus candidate feed algorithms over a date window | `php artisan analytics:compare-feed-ab baseline_v1 candidate_v2 --from=2026-04-01 --to=2026-04-16` |
| `analytics:evaluate-feed-weights` | Run offline feed-weight evaluation against stored daily metrics | `php artisan analytics:evaluate-feed-weights --algo=v2 --from=2026-04-01 --to=2026-04-16` |
| `analytics:seed-tag-interaction-demo` | Seed demo analytics data for local dashboards and ranking experiments | `php artisan analytics:seed-tag-interaction-demo --days=7 --per-day=100` |
| `adsense:sync` | Synchronize Google AdSense entities and daily reporting into the admin analytics tables | `php artisan adsense:sync --days=3` |
### AI Biography
| Command | Why it is used | Example |
| --- | --- | --- |
| `ai-biography:generate` | Generate missing AI biographies or refresh stale ones | `php artisan ai-biography:generate --stale --limit=50` |
| `ai-biography:inspect` | Inspect an AI biography record and its normalized prompt/input payload | `php artisan ai-biography:inspect 123` |
| `ai-biography:providers` | Check provider health and list available AI biography models | `php artisan ai-biography:providers --limit=10` |
| `ai-biography:review-queue` | List AI biography records that need manual review | `php artisan ai-biography:review-queue --needs-review --limit=25` |
| `ai-biography:validate` | Revalidate stored AI biographies against the current rules | `php artisan ai-biography:validate --limit=100 --dry-run` |
### Academy
| Command | Why it is used | Example |
| --- | --- | --- |
| `academy:analytics-health` | Inspect Academy analytics collection health, rollup freshness, and privacy safeguards | `php artisan academy:analytics-health --json` |
| `academy:billing-health` | Check Academy Stripe billing rollout readiness, including Stripe secrets, price IDs, Cashier routes, and billing tables | `php artisan academy:billing-health --strict` |
| `academy:courses:sync-foundations` | Create or update the default AI-Assisted Digital Art Foundations Academy course | `php artisan academy:courses:sync-foundations` |
### Artworks
| Command | Why it is used | Example |
| --- | --- | --- |
| `artworks:ai-suggest` | Generate studio AI suggestions for artworks, including suggested tags | `php artisan artworks:ai-suggest --after-id=1000 --limit=100 --queue` |
| `artworks:ai-tag` | Generate artwork tags through the local LM Studio vision model | `php artisan artworks:ai-tag --after-id=1000 --limit=50 --dry-run` |
| `artworks:audit-legacy-user-ids` | Compare `artworks.user_id` with legacy `wallz.user_id` using shared artwork IDs | `php artisan artworks:audit-legacy-user-ids --chunk=1000 --show=25 --json` |
| `artworks:audit-thumbnail-maturity` | Scan thumbnails for possible mature content without changing maturity fields | `php artisan artworks:audit-thumbnail-maturity --after-id=1 --limit=100 --dry-run` |
| `artworks:audit-thumbnails` | Audit object-storage thumbnails and flag artworks with missing variants | `php artisan artworks:audit-thumbnails --limit=1000 --dry-run` |
| `artworks:check-user-ids` | Verify that every `artworks.user_id` exists in `users` | `php artisan artworks:check-user-ids --show-missing=50` |
| `artworks:check-user-refs` | Full artwork-user reference audit with optional legacy-user recovery helpers | `php artisan artworks:check-user-refs --show-missing=50 --json` |
| `artworks:embeddings-backfill` | Queue resumable CLIP embedding backfill jobs for artworks | `php artisan artworks:embeddings-backfill --after-id=0 --batch=200` |
| `artworks:backfill-primary-category` | Report and backfill `artworks.primary_category_id` from unique pivot memberships | `php artisan artworks:backfill-primary-category --report --apply` |
| `artworks:generate-missing-sq-thumbs` | Generate missing smart square thumbnails | `php artisan artworks:generate-missing-sq-thumbs --limit=200 --dry-run` |
| `artworks:import-hashes` | Import artwork hash and extension metadata from a CSV file | `php artisan artworks:import-hashes artworks_hash_skinbase.csv --start=0 --limit=1000` |
| `artworks:normalize-slugs` | Normalize stored artwork slugs from titles without enforcing uniqueness | `php artisan artworks:normalize-slugs --only-mismatched --dry-run` |
| `artworks:publish-scheduled` | Publish artworks whose scheduled publish date has passed | `php artisan artworks:publish-scheduled --limit=100` |
| `artworks:search-rebuild` | Requeue all artworks for Meilisearch indexing in chunks | `php artisan artworks:search-rebuild --chunk=500` |
| `artworks:search-reindex-recent` | Reindex recent public artworks to recover missed search updates | `php artisan artworks:search-reindex-recent --hours=24 --limit=500` |
| `artworks:sync-created-at` | Copy `published_at` into `created_at` for published artworks | `php artisan artworks:sync-created-at --only-null --dry-run` |
| `artworks:vectors-index` | Send artwork image URLs to the vector gateway for indexing | `php artisan artworks:vectors-index --public-only --batch=200 --limit=1000` |
| `artworks:vectors-repair` | Repair vector gateway state for artworks that already have local embeddings | `php artisan artworks:vectors-repair --public-only --stale-hours=24` |
| `artworks:vectors-search` | Search for similar artworks through the vector gateway | `php artisan artworks:vectors-search 123 --limit=12` |
### Awards
| Command | Why it is used | Example |
| --- | --- | --- |
| `awards:import-legacy` | Import legacy `users_opinions` rows into `artwork_medals` | `php artisan awards:import-legacy --chunk=500 --dry-run` |
### Avatars
| Command | Why it is used | Example |
| --- | --- | --- |
| `avatars:bulk-update` | Bulk update `user_profiles.avatar_hash` from a CSV file | `php artisan avatars:bulk-update user_profiles_avatar.csv --dry-run` |
| `avatars:migrate` | Migrate legacy avatars and generate resized WebP variants | `php artisan avatars:migrate --dry-run --force` |
### Collections
| Command | Why it is used | Example |
| --- | --- | --- |
| `collections:dispatch-maintenance` | Dispatch maintenance jobs for collection health, recommendations, and duplicate handling | `php artisan collections:dispatch-maintenance --health --recommendations` |
| `collections:sync-lifecycle` | Expire pending invites and sync collection lifecycle state | `php artisan collections:sync-lifecycle` |
### Comments
| Command | Why it is used | Example |
| --- | --- | --- |
| `comments:import-legacy` | Import legacy `artworks_comments` into `artwork_comments` | `php artisan comments:import-legacy --chunk=500 --dry-run` |
### Creator Journey
| Command | Why it is used | Example |
| --- | --- | --- |
| `creator-journey:rebuild-eras` | Rebuild creator-era records from public artwork history | `php artisan creator-journey:rebuild-eras 123 --chunk=200` |
### Forum
| Command | Why it is used | Example |
| --- | --- | --- |
| `forum:convert-posts` | Convert migrated forum posts from legacy BBCode to HTML | `php artisan forum:convert-posts --chunk=500 --report` |
| `forum:migrate-old` | Migrate legacy forum data into the new forum tables | `php artisan forum:migrate-old --chunk=500 --report --dry-run` |
### Health
| Command | Why it is used | Example |
| --- | --- | --- |
| `health:check` | Run the application health check across critical services and dependencies | `php artisan health:check --json` |
| `health:tick` | Write the scheduler heartbeat used by `health:check` | `php artisan health:tick` |
### Homepage
| Command | Why it is used | Example |
| --- | --- | --- |
| `homepage:warm-guest-cache` | Warm the guest homepage cache payload | `php artisan homepage:warm-guest-cache` |
### Imports
| Command | Why it is used | Example |
| --- | --- | --- |
| `import:categories` | Import categories from the legacy CSV source file | `php artisan import:categories database/artworks_categories.csv` |
| `import:legacy-favourites` | Copy legacy favourites from another DB connection into `user_favorites` | `php artisan import:legacy-favourites --connection=legacy --chunk=500` |
| `import:wallz-categories` | Import artwork-category mappings from the legacy `wallz` table | `php artisan import:wallz-categories --connection=legacy --table=wallz --chunk=500` |
### Legacy Repair
| Command | Why it is used | Example |
| --- | --- | --- |
| `legacySB:repair-legacy-wallz-users` | Backfill legacy `wallz.user_id` values by matching usernames to current users | `php artisan legacySB:repair-legacy-wallz-users --chunk=500 --dry-run` |
### Meilisearch
| Command | Why it is used | Example |
| --- | --- | --- |
| `meilisearch:configure-index` | Push sortable/filterable settings to the Meilisearch artworks index | `php artisan meilisearch:configure-index --index=artworks` |
### Migrations
| Command | Why it is used | Example |
| --- | --- | --- |
| `migrate:featured-works` | Safely migrate legacy `featured_works` rows into `artwork_features` | `php artisan migrate:featured-works --chunk=500 --dry-run` |
### News
| Command | Why it is used | Example |
| --- | --- | --- |
| `news:import-legacy` | Import legacy news articles into `news_articles` | `php artisan news:import-legacy --start=0 --limit=500 --dry-run` |
| `news:publish-scheduled` | Publish scheduled news items whose publish time has passed | `php artisan news:publish-scheduled --limit=100` |
### Nova
| Command | Why it is used | Example |
| --- | --- | --- |
| `nova:metrics-snapshot-hourly` | Collect hourly metric snapshots used by rising/heat calculations | `php artisan nova:metrics-snapshot-hourly --days=1` |
| `nova:prune-metric-snapshots` | Delete old hourly metric snapshots past the retention window (batched) | `php artisan nova:prune-metric-snapshots --keep-days=30 --chunk=5000` |
| `nova:recalculate-heat` | Recalculate heat and momentum scores for the rising engine | `php artisan nova:recalculate-heat --days=30 --chunk=500` |
| `nova:recalculate-rankings` | Recalculate V2 ranking scores | `php artisan nova:recalculate-rankings --chunk=500 --sync-rank-scores` |
### Nova Cards
| Command | Why it is used | Example |
| --- | --- | --- |
| `nova-cards:publish-scheduled` | Publish scheduled Nova cards | `php artisan nova-cards:publish-scheduled --limit=100` |
### Posts
| Command | Why it is used | Example |
| --- | --- | --- |
| `posts:publish-scheduled` | Publish scheduled posts when their publish time arrives | `php artisan posts:publish-scheduled` |
| `posts:warm-trending` | Refresh the post-trending cache | `php artisan posts:warm-trending` |
### Schema
| Command | Why it is used | Example |
| --- | --- | --- |
| `schema:audit-migrations` | Compare the live schema with executed migration files | `php artisan schema:audit-migrations --json` |
### Skinbase Core
| Command | Why it is used | Example |
| --- | --- | --- |
| `skinbase:audit-orphaned-artworks` | Find artworks whose `user_id` no longer exists and optionally export repair data | `php artisan skinbase:audit-orphaned-artworks --chunk=1000 --output=orphaned.csv` |
| `skinbase:backfill-user-activities` | Backfill historical profile activity into `user_activities` | `php artisan skinbase:backfill-user-activities --chunk=500 --dry-run` |
| `skinbase:enforce-usernames` | Normalize and enforce the username policy on existing users | `php artisan skinbase:enforce-usernames --dry-run` |
| `skinbase:flag-legacy-users` | Flag legacy users for migration based on activity across legacy tables | `php artisan skinbase:flag-legacy-users --chunk=1000 --dry-run` |
| `skinbase:flush-redis-stats` | Drain Redis artwork stat deltas into MySQL | `php artisan skinbase:flush-redis-stats --max=1000` |
| `skinbase:import-legacy-artworks` | Import artworks from the legacy `wallz` table | `php artisan skinbase:import-legacy-artworks --chunk=200 --dry-run` |
| `skinbase:import-legacy-users` | Import legacy users into the current auth schema | `php artisan skinbase:import-legacy-users --chunk=200 --dry-run` |
| `skinbase:migrate-favourites` | Migrate legacy favourites into `artwork_favourites` | `php artisan skinbase:migrate-favourites --chunk=500 --dry-run` |
| `skinbase:migrate-follows` | Migrate legacy `friends_list` data into `user_followers` | `php artisan skinbase:migrate-follows --chunk=500 --dry-run` |
| `skinbase:migrate-messages` | Migrate legacy chat/messages into the conversation system | `php artisan skinbase:migrate-messages --chunk=500 --dry-run` |
| `skinbase:migrate-smileys` | Convert legacy `:smiley:` codes to Unicode emoji in content fields | `php artisan skinbase:migrate-smileys --chunk=500 --dry-run` |
| `skinbase:migrate-wallz-stats` | Import views/downloads from legacy `wallz` into `artwork_stats` | `php artisan skinbase:migrate-wallz-stats --chunk=500 --dry-run` |
| `skinbase:prune-view-events` | Delete old `artwork_view_events` rows | `php artisan skinbase:prune-view-events --days=90` |
| `skinbase:rebuild-creator-journey` | Rebuild persisted creator-journey milestones | `php artisan skinbase:rebuild-creator-journey --all --chunk=200` |
| `skinbase:recalculate-trending` | Recalculate artwork trending scores and sync them to search | `php artisan skinbase:recalculate-trending --period=30d --chunk=500` |
| `skinbase:recalculate-user-xp` | Rebuild stored XP, level, and rank from `user_xp_logs` | `php artisan skinbase:recalculate-user-xp --all --chunk=500` |
| `skinbase:recompute-user-stats` | Rebuild `user_statistics` counters from source tables | `php artisan skinbase:recompute-user-stats --all --chunk=500` |
| `skinbase:repair-temp-usernames` | Replace placeholder usernames such as `tmpu123` using user profile data | `php artisan skinbase:repair-temp-usernames --chunk=500 --dry-run` |
| `skinbase:repair-user-join-dates` | Backfill `users.created_at` from the legacy `joinDate` value | `php artisan skinbase:repair-user-join-dates --chunk=500 --only-null --dry-run` |
| `skinbase:rescan-content-moderation` | Reprocess stored moderation findings using the latest rules | `php artisan skinbase:rescan-content-moderation --limit=100 --force` |
| `skinbase:reset-all-passwords` | Reset every user password and force password reset on next login | `php artisan skinbase:reset-all-passwords --chunk=500 --yes` |
| `skinbase:reset-windowed-stats` | Reset windowed view/download counters in `artwork_stats` | `php artisan skinbase:reset-windowed-stats --period=30d` |
| `skinbase:sanitize-content` | Sanitize legacy HTML and populate sanitized columns | `php artisan skinbase:sanitize-content --chunk=500 --dry-run` |
| `skinbase:scan-content-moderation` | Scan comments and descriptions for suspicious or spam-like content | `php artisan skinbase:scan-content-moderation --limit=100 --dry-run` |
| `skinbase:sitemaps:build` | Build a versioned sitemap release artifact set | `php artisan skinbase:sitemaps:build --release=manual-20260417 --dry-run` |
| `skinbase:sitemaps:publish` | Build, validate, and atomically publish a sitemap release | `php artisan skinbase:sitemaps:publish --sync` |
| `skinbase:sitemaps:releases` | List recent sitemap releases and the active release | `php artisan skinbase:sitemaps:releases` |
| `skinbase:sitemaps:rollback` | Roll back sitemap delivery to a previous published release | `php artisan skinbase:sitemaps:rollback release-20260416-1` |
| `skinbase:sitemaps:validate` | Validate sitemap XML, shard integrity, and public URL safety | `php artisan skinbase:sitemaps:validate --active` |
| `skinbase:sync-countries` | Synchronize ISO 3166 country metadata into the local countries table | `php artisan skinbase:sync-countries --deactivate-missing` |
### Stories
| Command | Why it is used | Example |
| --- | --- | --- |
| `stories:migrate-legacy` | Import legacy interview/story records into the Nova Stories system | `php artisan stories:migrate-legacy --chunk=200 --dry-run` |
### Storage
| Command | Why it is used | Example |
| --- | --- | --- |
| `storage:test-upload` | Upload a probe file to object storage and verify persistence | `php artisan storage:test-upload --disk=s3 --keep` |
### Tags
| Command | Why it is used | Example |
| --- | --- | --- |
| `tags:fix-names` | Convert slug-style tag names into readable display names | `php artisan tags:fix-names --dry-run` |
### Translations
| Command | Why it is used | Example |
| --- | --- | --- |
| `translations:export-missing` | Export missing translations for one language file into CSV | `php artisan translations:export-missing admin --out=storage/app/missing-admin.csv` |
### Users
| Command | Why it is used | Example |
| --- | --- | --- |
| `users:audit-missing-migrated` | List legacy users marked for migration but still missing from the new users table | `php artisan users:audit-missing-migrated --chunk=1000` |
## Ad Hoc and Inspection Scripts
These are useful, but they read more like maintenance probes and one-off utilities than stable product commands.
### scripts/ Helpers
| Script | Why it is used | Example |
| --- | --- | --- |
| `scripts/check_col_charset.php` | Inspect charset/collation of artwork comment content columns | `php scripts/check_col_charset.php` |
| `scripts/check_fp_translations.php` | Inspect translation-file stats and active language rows | `php scripts/check_fp_translations.php admin` |
| `scripts/check_intervention.php` | Verify the available image-processing backend such as GD or Imagick | `php scripts/check_intervention.php` |
| `scripts/check_redis.php` | Ping Redis and inspect the artwork stat delta queue depth | `php scripts/check_redis.php` |
| `scripts/check_reply_tree.php` | Inspect the artwork-comment reply tree for a hardcoded test case | `php scripts/check_reply_tree.php` |
| `scripts/check_stats.php` | Inspect a specific artwork stats row and related counters | `php scripts/check_stats.php` |
| `scripts/check_stats2.php` | Alternate stats inspection helper for the same debugging area | `php scripts/check_stats2.php` |
| `scripts/fill_translations_csv.php` | Fill the `Value` column in a translations CSV from language files | `php scripts/fill_translations_csv.php` |
| `scripts/fix_artworks_updated_at.php` | Sync `artworks.updated_at` to `created_at` in bulk | `php scripts/fix_artworks_updated_at.php --dry-run` |
| `scripts/inspect_autotag_jobs.php` | Inspect queued and failed `AutoTagArtworkJob` jobs | `php scripts/inspect_autotag_jobs.php` |
| `scripts/inspect_legacy_users.php` | Inspect the legacy users table schema and a sample row | `php scripts/inspect_legacy_users.php` |
| `scripts/populate_sl_translations.php` | Translate missing strings to Slovenian using LibreTranslate | `php scripts/populate_sl_translations.php input.csv output.csv` |
| `scripts/repair_broken_artworks.php` | Repair artworks with missing or invalid metadata | `php scripts/repair_broken_artworks.php --limit=25 --publish` |
| `scripts/rerender_comments.php` | Re-render artwork comments through the content sanitizer | `php scripts/rerender_comments.php` |
| `scripts/verify_upload_publish.php` | Check that an artwork has the fields required for upload/publish | `php scripts/verify_upload_publish.php --id=123 --limit=5` |
### Temporary Root Scripts
| Script | Why it is used | Example |
| --- | --- | --- |
| `temp-ai-debug.php` | Temporary PHP debug probe for AI-related investigation | `php temp-ai-debug.php` |
| `temp-ai-title-debug.php` | Temporary PHP debug probe for AI title generation/debugging | `php temp-ai-title-debug.php` |
| `temp-check-collection-controllers.php` | Temporary PHP inspection script for collection controllers | `php temp-check-collection-controllers.php` |
| `temp-check-collection-services.php` | Temporary PHP inspection script for collection services | `php temp-check-collection-services.php` |
| `temp-check-user-id-cols.php` | Temporary PHP probe for user ID column inspection | `php temp-check-user-id-cols.php` |
| `temp-latest-playwright-owner.php` | Temporary PHP probe related to Playwright ownership/debug output | `php temp-latest-playwright-owner.php` |
| `temp-playwright-probe.cjs` | Temporary Node/CommonJS Playwright probe | `node temp-playwright-probe.cjs` |
| `temp-playwright-probe.js` | Temporary Node Playwright probe | `node temp-playwright-probe.js` |
| `temp-probe-ai-title.cjs` | Temporary Node/CommonJS AI title probe | `node temp-probe-ai-title.cjs` |
## Notes
- The deploy mirror under `.deploy/artwork-evolution-release` contains equivalent command classes for deployment packaging, but this reference is sourced from the main repository tree.
- For commands that mutate production data, prefer running a dry-run mode first when one exists.
- For one-off scripts, read the file before using it. Several are intentionally ad hoc and may contain hardcoded IDs, paths, or assumptions.
## Scheduler
- **Active scheduler file:** The application's active runtime schedule is consolidated in [routes/console.php](routes/console.php). Do not duplicate recurring entries in [app/Console/Kernel.php](app/Console/Kernel.php) — the app boots command routes from `bootstrap/app.php` and registering the same cron bodies in multiple places can lead to duplicate runs.
- **Validation:** After editing schedules run `php artisan schedule:list` to confirm Laravel parses the schedule and to view the resolved cron timings. This command also surfaces invalid frequency methods (for example `everyHour()` or `everyFiveMinute()`) which will break schedule introspection.
- **Best practice:** Stagger heavy jobs away from the same minute boundaries (avoid piling multiple CPU-heavy commands on `:00`, `:10`, `:15`, `:30`). Prefer cron offsets or `->cron()` expressions in `routes/console.php` and use `->withoutOverlapping()` and `->runInBackground()` where appropriate.