Files
takeone-youtube-clone/docs/audit-remediation-plan.md
T
ghassanandClaude Opus 4.7 56b6a83b34 docs: audit remediation plan (7 phases)
Checklist across security, performance/DOM, feeds/search/trending,
watch page, Shorts, channel/studio/live, and admin/a11y. Branch per
phase; backup tag backup/pre-audit-2026-10-21 at 5058eaf.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-10-21 00:33:10 +03:00

6.6 KiB
Raw Blame History

YouTube-parity audit remediation plan

Branch per phase. Feature tests per fix. STOP for approval between phases.

Safety tag: backup/pre-audit-2026-10-21 at commit 5058eaf on full-screen-data. Stashed WIP: stash@{0} — pre-audit WIP on full-screen-data (recover with git stash pop on that branch).


Phase 1 — Security & data integrity

Branch: fix/phase-1-security

  • Wrap sendEmailVerificationNotification + NewCommentNotification mail in try/catch; move to a queued notification channel; log failures. Document .env for Gmail app password + Mailgun/Postmark fallback.
  • php artisan app:resend-verification {--user=} command.
  • Reserved-name blocklist (admin, superadmin, takeone, support, root, …) via App\Rules\ReservedIdentifier wired into RegisteredUserController.
  • Harden login throttling to 5,1 with lockout message; log repeated failures and alert super admins.
  • Confirm email_verified_at is not mass-assignable; only the signed-URL verification route flips it.
  • Comment dedupe: raise 5s → 60s window, add client idempotency key header, server reject on duplicate. Disable submit button on first click.
  • php artisan comments:dedupe --dry-run cleanup command.
  • Owner-view exclusion in VideoController@trackProgress; dedupe by device_hash within 30 min.
  • Feature tests for each item.

Phase 2 — Performance & DOM

Branch: fix/phase-2-perf

  • One shared #globalEditModal + #globalCardMenu per page; populated via GET /videos/{id}/edit-payload. Owner-only items gated server-side.
  • Lazy-render reply/edit boxes (template clone on open).
  • Match highlights panel rendered once.
  • href="javascript:void(0)" → real <button> elements. Hide "Not interested" / "Don't recommend" / "Report" on own videos.
  • Cursor pagination (?cursor=) across Home, /videos filters, channel Videos, search, history, liked, comments.
  • IntersectionObserver infinite scroll + "Load more" fallback.
  • loading="lazy", explicit width/height, skeleton placeholders on thumbnails.

Branch: fix/phase-3-feeds

  • Music + filter feeds switch to latest().
  • Trending windows: 24 / 168 / 720 h; rank by in-window views.
  • Channel Popular: order by views, tiebreak by likes.
  • Duration badge on card thumbnail. Scoreboard thumb → <img> or aria-hidden. Strip CLUBLOGO / FLAG placeholders.
  • Filter tabs: fetch + pushState, sticky, aria-current.
  • Normalize naming (DB stays match, display label "Sports" everywhere).
  • "New to You" → "Recent" (or make personalized).
  • New SearchController with /search?q= matching title/description/tags/language/channel; include channels + playlists. /videos/search becomes 302 redirect. Keep query in input. Merge the two duplicate search forms.
  • /feed/subscriptions route backed by subscriptions table.

Phase 4 — Watch page

Branch: fix/phase-4-watch

  • Up Next: real <a href> cards. Recommender by type/tags/language, cross-channel. Tabs All / From this channel / Same type. Show more.
  • Unified player wrapper for match/music/generic: theater (t), mini (i), PiP, volume slider, captions=lyrics (c), 2x speed, end screen, autoplay countdown. Autoplay-ON forces Loop-OFF.
  • Like count visible, dislike button, Subscribe for guests, viewer ⋯ → Report. Channel row on match videos.
  • /videos/{id}/download/{format} signed route; enforce per-video Downloads setting (Off/Everyone/Members/Subscribers) server-side for MP4 and MP3.
  • Comments: ?lc= permalink with scroll + highlight. Heart + pin (creator). "Read more" clamp. @handle prefill on nested reply. Singular/plural counts. Top-level vs reply counts separate.
  • Markdown rendered (or stripped) in descriptions.
  • Dedupe audio Language menu.
  • Hide "Generating lyrics…" overlay unless job active.
  • Edit form prefilled with real values (fix "Generic" / "Loading…" defaults).
  • Streaming: HLS exists (GenerateHlsJob, /videos/{video}/hls/{file}). Switch player to hls.js when hls_path set. Verify -movflags +faststart on mp4 encode in CompressVideoJob. Add Cache-Control + Range on stream route.

Phase 5 — Shorts

Branch: fix/phase-5-shorts

  • Upload flag + auto-detect (vertical, ≤60s).
  • /shorts/{id} route + branded 404 at resources/views/errors/404.blade.php.
  • /shorts feed: 100dvh snap container, single reused <video> moved between slots, next 1–2 preloaded, URL via history.replaceState, wheel + arrows + swipe + ▲▼. Loop. Muted autoplay + "Tap to unmute"; unmuted state in localStorage.
  • Right action column (like/dislike/comments/share). Bottom overlay (avatar/@handle/Subscribe/title). Comments side panel desktop / bottom sheet mobile.
  • Home Shorts shelf. Channel Shorts tab (fix "My Shorts").

Phase 6 — Channel / Studio / Live

Branch: fix/phase-6-channel-studio-live

  • users.handle migration (unique, nullable → backfill → required). /@handle routes. Tabs /@handle/{videos,shorts,playlists,posts,about}. "Preview as visitor" toggle. Header shows description + links. Age/gender/horoscope private by default. Pluralize "1 video"; drop stray "· 0.0" on playlist cards.
  • /studio/*: content table + bulk edit, per-video analytics, two-step upload (Details → Visibility: tags + playlist + schedule), file-size + duration + processing-status surfaced.
  • Live: ended state → "Stream ended" + duration + recording (never "Waiting"). Live chat. Like / share / subscribe on viewer page. Channel name link. Private option on /live/new matching upload wording.

Phase 7 — Admin, a11y, consistency

Branch: fix/phase-7-admin-a11y

  • Rename "Live Videos" → "Ready". Storage counts NAS (via NasSyncService). Fix KPI WoW %. Strip HTML in description excerpts. Full titles with tooltip. Next/Last pagination on Audit Logs, Users, Videos. Error log viewer groups by stack trace in natural order.
  • A11y: aria-label on every icon button (menu, search, voice, avatar, ⋯, Like-active, comment menus, seek slider with value text). Skip-to-content link. One <h1> per page. label[for] on all inputs. Remove duplicate "Prefer not to say". Birth year 13+ cap.
  • Title helper {page} | Play. Brand: Play displayed; TAKEONE stays as config('app.name') per CLAUDE.md.
  • Cleanup commands (all --dry-run first): comments:dedupe, live:cleanup-test, tracks:dedupe.

Final deliverables

  • Checklist: done / partial / skipped (with reason).
  • .env keys the user must set.
  • Deploy steps: migrations, queue restart, cache clear, asset build.