feat: Inertia profile settings page, Studio edit redesign, EGS, Nova UI components\n\n- Redesign /dashboard/profile as Inertia React page (Settings/ProfileEdit)\n with SettingsLayout sidebar, Nova UI components (TextInput, Textarea,\n Toggle, Select, RadioGroup, Modal, Button), avatar drag-and-drop,\n password change, and account deletion sections\n- Redesign Studio artwork edit page with two-column layout, Nova components,\n integrated TagPicker, and version history modal\n- Add shared MarkdownEditor component\n- Add Early-Stage Growth System (EGS): SpotlightEngine, FeedBlender,\n GridFiller, AdaptiveTimeWindow, ActivityLayer, admin panel\n- Fix upload category/tag persistence (V1+V2 paths)\n- Fix tag source enum, category tree display, binding resolution\n- Add settings.jsx Vite entry, settings.blade.php wrapper\n- Update ProfileController with JSON response support for API calls\n- Various route fixes (profile.edit, toolbar settings link)"

This commit is contained in:
2026-03-03 20:57:43 +01:00
parent dc51d65440
commit b9c2d8597d
114 changed files with 8760 additions and 693 deletions

78
config/early_growth.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
/**
* Early-Stage Growth System (EGS) Configuration
*
* Controls the Nova Early-Stage Growth System a reversible, non-deceptive
* layer that keeps the site feeling alive when organic traffic is low.
*
* TOGGLE:
* .env NOVA_EARLY_GROWTH_ENABLED=true
* .env NOVA_EARLY_GROWTH_MODE=light (off | light | aggressive)
*
* Set NOVA_EARLY_GROWTH_ENABLED=false (or NOVA_EARLY_GROWTH_MODE=off)
* to revert all behaviour to standard production logic instantly.
*/
return [
// ─── Master switch ────────────────────────────────────────────────────────
'enabled' => (bool) env('NOVA_EARLY_GROWTH_ENABLED', false),
// operating mode: off | light | aggressive
'mode' => env('NOVA_EARLY_GROWTH_MODE', 'off'),
// ─── Module toggles (each respects master 'enabled') ─────────────────────
'adaptive_time_window' => (bool) env('NOVA_EGS_ADAPTIVE_WINDOW', true),
'grid_filler' => (bool) env('NOVA_EGS_GRID_FILLER', true),
'spotlight' => (bool) env('NOVA_EGS_SPOTLIGHT', true),
'activity_layer' => (bool) env('NOVA_EGS_ACTIVITY_LAYER', false),
// ─── AdaptiveTimeWindow thresholds ───────────────────────────────────────
// uploads_per_day is the 7-day rolling average of published artworks/day.
'thresholds' => [
'uploads_per_day_narrow' => (int) env('NOVA_EGS_UPLOADS_PER_DAY_NARROW', 10),
'uploads_per_day_wide' => (int) env('NOVA_EGS_UPLOADS_PER_DAY_WIDE', 3),
// Days to look back for trending / rising queries
'window_narrow_days' => (int) env('NOVA_EGS_WINDOW_NARROW_DAYS', 7),
'window_medium_days' => (int) env('NOVA_EGS_WINDOW_MEDIUM_DAYS', 30),
'window_wide_days' => (int) env('NOVA_EGS_WINDOW_WIDE_DAYS', 90),
],
// ─── FeedBlender ratios per mode ─────────────────────────────────────────
// Values are proportions; they are normalised internally (sum need not equal 1).
'blend_ratios' => [
'light' => [
'fresh' => 0.60,
'curated' => 0.25,
'spotlight' => 0.15,
],
'aggressive' => [
'fresh' => 0.30,
'curated' => 0.50,
'spotlight' => 0.20,
],
],
// ─── GridFiller ──────────────────────────────────────────────────────────
// Minimum number of items to display per grid page.
'grid_min_results' => (int) env('NOVA_EGS_GRID_MIN_RESULTS', 12),
// ─── Auto-disable when site reaches organic scale ────────────────────────
'auto_disable' => [
'enabled' => (bool) env('NOVA_EGS_AUTO_DISABLE', false),
'uploads_per_day' => (int) env('NOVA_EGS_AUTO_DISABLE_UPLOADS', 50),
'active_users' => (int) env('NOVA_EGS_AUTO_DISABLE_USERS', 500),
],
// ─── Cache TTLs (seconds) ─────────────────────────────────────────────────
'cache_ttl' => [
'spotlight' => (int) env('NOVA_EGS_SPOTLIGHT_TTL', 3600), // 1 h rotated daily
'feed_blend' => (int) env('NOVA_EGS_BLEND_TTL', 300), // 5 min
'time_window' => (int) env('NOVA_EGS_WINDOW_TTL', 600), // 10 min
'activity' => (int) env('NOVA_EGS_ACTIVITY_TTL', 1800), // 30 min
],
];

View File

@@ -111,8 +111,8 @@ return [
*/
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
'address' => env('MAIL_FROM_ADDRESS', 'gregor@klevze.com'),
'name' => env('MAIL_FROM_NAME', 'Skinbase'),
],
];

View File

@@ -54,4 +54,13 @@ return [
'timeout' => (int) env('TURNSTILE_TIMEOUT', 5),
],
/*
* Google AdSense
* Set GOOGLE_ADSENSE_PUBLISHER_ID to your ca-pub-XXXXXXXXXXXXXXXX value.
* Ads are only loaded after the user accepts cookies via the consent banner.
*/
'google_adsense' => [
'publisher_id' => env('GOOGLE_ADSENSE_PUBLISHER_ID'),
],
];