# V1 Persona: solo_tech_blogger_bulk_ai_rewriter

> **Source of truth for all UX decisions in RankWizAI v1.**
> Every PR that adds team/seat/multi-site UI must justify against this
> persona or update this file first (see root CLAUDE.md).

---

## Who They Are

A solo tech blogger managing **100–2,000 WordPress posts** who has watched
organic traffic decline by **30–80%** over the past 6–18 months. They are
**time-poor** — blogging is not their full-time job. They have a day job, a
backlog of competing content obligations, and cannot spend hours triaging a
spreadsheet before deciding what to fix next.

They understand SEO conceptually but are not analysts. They do not want to
read decay-pattern theory or confidence-score percentages — they want a
system that surfaces **what to fix first** and then helps them fix it **in
bulk**.

---

## Primary Job

**Bulk AI rewriting of decayed posts** is the defining job-to-be-done.

The persona's workflow is a recovery cycle:

1. **Find** the posts that have lost the most traffic
2. **Prioritize** by rewrite effort vs. impact (not by hand — the tool should
   do this)
3. **Act on a cohort** (not one post at a time — they have hundreds of
   candidates)
4. **Track recovery** over the following 4–8 weeks

Every feature decision in RankWizAI v1 flows from this cycle. If a feature
does not accelerate one of these four steps for a solo blogger operating at
scale, it is out of scope for v1.

---

## Key Constraints

| Constraint | Implication |
|---|---|
| Solo operator — no team | No seat management, no sharing/collaboration UI, no role-based access |
| 100–2,000 posts | Bulk actions are mandatory; one-at-a-time flows are frustrating |
| Time-poor | CTAs must be immediately actionable from the list view; no multi-step wizards before first action |
| Traffic loss is the trigger | "Click delta" (prior − recent clicks) is the primary sort signal, not word count or Flesch grade |
| Recovery takes weeks | The persona checks progress daily or weekly; must be able to track which rewrites have improved |
| Single WordPress site (v1) | Multi-site UI is deferred |

---

## Bulk-First Principles

These are the concrete UX rules derived from this persona. All v1 interface
decisions must satisfy them:

1. **Surface the rewrite-priority signal where the persona reads it.**
   Click delta (click_loss) must be visible at ≥md breakpoint in the Content
   Inventory — not hidden behind a responsive lg gate. The persona uses a
   laptop, not a 4K desktop monitor.

2. **Every list view with more than one row must support bulk selection.**
   Content Inventory and Freshness Watchlist are the two entry points. Both
   must have a leading checkbox column and a sticky bottom action bar.

3. **"Select all N matching this filter" is required at scale.**
   A persona with 400 decaying posts cannot select them page by page.
   The system must resolve the full cohort server-side from the active filter
   querystring and confirm the scope (count + estimated cost) before
   dispatching.

4. **CTAs must be in the list view, not the detail page.**
   "Rewrite" and "Brief" links belong on each table row. Detail pages exist
   for inspection, not as the primary action entrypoint.

5. **Sync feedback must be honest.**
   A 2,000-post WordPress import takes longer than 4 seconds. The sync
   indicator must poll until the count advances, not guess a fixed timeout
   and tell the user to click again.

6. **Title clicks should navigate, not toggle a drawer.**
   The persona's expectation when clicking a post title is to open the
   post/editor. The metrics drawer is secondary and should use a dedicated
   chevron control.

---

## Out of Scope for V1

- Team seats or multi-user collaboration *(clarification: the agency pricing
  tier and white-label report capability are v1-active — see Feature Surface
  Decisions § Agency tier below. What remains out of scope for v1 is the
  team-COLLABORATION UI: seat invitation flows, role editors, multi-site
  portfolio dashboards. Those surfaces stay behind `FEATURE_TEAMS=false`.)*
- Multi-site comparisons or cross-site bulk actions
- White-label or agency reporting *(clarification: white-label report output as
  a feature of the Team tier IS a v1-active capability. What is out of scope is
  building a dedicated agency-management UI — client-portal branding, custom
  domain per client, role-based access editor. The existing Team tier's white-
  label report download is the v1 surface; a deeper agency-management shell is
  deferred.)*
- Any UI that requires understanding of statistical models (confidence scores,
  decay patterns) before taking action — these are filters, not blockers

---

## Feature Surface Decisions (F5DEBT-001)

> Decisions recorded here satisfy the CLAUDE.md gate requiring any team/seat/multi-site
> UI to justify against this persona.

### Team / Seat Surface
- `FEATURE_TEAMS=false` (default) — all team routes (Sites/Settings/Team), SiteMemberController, and
  SiteMembershipService are behind the `feature-gate:teams` and `feature-gate:site_members` middleware.
- `Site-navigation.ts` hides the Members sub-item when `features.teams` is false OR plan != team/enterprise.
- **Retained in code** for v2 agency persona. Tables (site_members, site_invitations), services, and
  observers stay intact. The feature flag is the v1 boundary.

#### R6ARCH-008 Decision (2026-06-11) — Keep-but-gate cold surface

**Finding:** ~87 files of team/seat/portfolio code ship even when the feature flags are off. This
is intentional v2 scaffolding, not accidental surface area.

**Decision: Keep all code, enforce a single config-gate boundary.**
- All team/seat routes are behind `feature-gate:teams` + `feature-gate:site_members` (already true).
- `SiteMember`, `SiteMembershipService`, and related controllers are NOT deleted — they are the
  vetted v2 agency-persona implementation, retained for a clean flag-flip at launch.
- **Test isolation (R6ARCH-008):** all SiteMember test files are in the `teams-v2` Pest group
  (`tests/Pest.php`). When `FEATURE_TEAMS=false` the `beforeEach` hook auto-skips the entire group.
  `phpunit.xml` keeps `FEATURE_TEAMS=true` so CI still exercises the feature; the flag-off skip
  is a local/dev convenience guard to avoid exercising off-persona code during development. The two
  `Feature/Http/Requests/*SiteMember*` test files were added to the group in this decision to close
  the auto-skip gap that existed for those integration tests.
- **Scope:** `config/features.php` keys `teams`, `site_members`, and `portfolio` remain the
  single-flag boundary. No additional gate mechanism is introduced. FEATURE_TEAMS is the master
  switch; FEATURE_SITE_MEMBERS lets ops disable member-management independently.

### Portfolio Surface
- `FEATURE_PORTFOLIO=false` (default) — the cross-site portfolio dashboard view routes are behind `feature-gate:portfolio` + `ensure-multi-site`; the per-site mutation `portfolio.generate-report` is behind `can:edit,site` only (intentional — it is a per-site operation, not a cross-site portfolio feature).
- `navigation.ts` portfolio nav item requires `requiresMultiSite: true` (additional frontend gate).
- **Retained in code** for v2.

### Spend Page (single-site layout)
- `/spend` route is accessible (no portfolio flag needed — it is a personal AI budget tool, not a
  multi-site portfolio feature).
- F5UXA-017: the per-site "By site" table and "N SITES" eyebrow are hidden when `active_site_count === 1`
  so the v1 solo persona sees a focused spend view without agency framing.

### Use-case pages (agencies / ecommerce)
- F5SEO-003: `use-cases.agencies` and `use-cases.ecommerce` meta entries removed from MetaTagService and
  SeoController::staticContentDates(). Routes were already noindexed (F4SEO-002). The off-persona
  meta was residual dilution; removing it causes the service to fall back to the generic use-cases meta.

### Consolidated IA Decision (R6IA-002 Phase B)

**Effective 2026-06-10 — single source of truth is `resources/js/config/site-navigation.ts`.**

Primary sidebar destinations (5 hubs):

| Hub | Sidebar children | Rationale |
|-----|-----------------|-----------|
| Overview | Analyze · ROI | Pipeline and Traffic Alerts moved to Overview hub landing page; 2 primary children match the daily-return workflow |
| Opportunities | *(none — hub leaf)* | All 6 surfaces (Recommendations, Action Queue, Cannibalization, Freshness, Link Opportunities, Topic Clusters) accessible as cards on the hub page; collapsed from 6 sidebar entries to 1 hub click |
| Content | Content Inventory · Content Briefs · Batch AI · Calendar · Reports | Core bulk-rewriting workflow; all 5 children directly relevant to the persona |
| Performance | Geographic · Device | 2 analytical deep-dives; no further consolidation needed |
| Settings | Connections · Schedule · Alert Subscriptions · [Members] | Operational config; Members gated to team/enterprise |

**Orphan surface reconciliation:**

| Surface | Status | Access path |
|---------|--------|-------------|
| `The Hour Queue` (`hour-queue.show`) | User-level (cross-site) — intentionally not a hub child | Top-nav bar link in DashboardLayout when user has ≥1 site |
| `Spend` (`spend.index`) | User-level AI budget cockpit — not site-scoped | User menu / top-nav area in DashboardLayout; documented in § Spend Page |
| `Batch AI History` (`batch-ai.show/{id}`) | Detail page, not a standalone nav destination | Reachable from Batch AI (`batch-ai.index`, Content hub) and batch notification toasts |

**Route-label canonical map:** `CANONICAL_ROUTE_LABELS` in `config/site-navigation.ts` is the
authoritative label source. Nav items, page `<Head>` titles, and the command palette all derive
labels from this map. Label drift reconciled (R6IA-003): "Alert Subscriptions" in Settings
now correctly routes to `notification-settings.show` (not `alerts.index`).

---

### FAQ corpus — team/agency copy (R6SEO-003)
- `allFaqs` is the default FAQPage JSON-LD corpus (general + feature + pricing + technical).
- Off-persona items removed from `allFaqs`: agency client-site FAQ, Pro vs Team plan FAQ, multi-team-member FAQ. These are relocated to `teamFaqs` (a separate named export in `faqs.ts`).
- `teamFaqs` must only be merged into the FAQPage schema when `FEATURE_TEAMS=true` (i.e., `import.meta.env.VITE_FEATURE_TEAMS === 'true'`).
- The existing test in `faqs.test.ts` (`allFaqs — R6SEO-003 persona guard`) enforces this at CI.

### AggregateOffer schema
- F5SEO-004: `highPrice` in WelcomeHead is now derived from `pricingTiers` array rather than a separate
  `teamPrice` prop. `offerCount` is dynamic. The team tier remains in the pricing section for now because
  it is a genuinely sold tier; if it is removed from the pricing page in future the schema will update
  automatically without a separate prop change.

### Privacy retention row
- F5SEO-004: retention row updated from "90 days (Starter) / 12 months (Pro, Agency, Enterprise)" to
  "90 days (Starter) / 12 months (Pro)". Agency/Enterprise tiers are not marketed v1 surfaces.

### Agency tier — v1-active buyer (synthesis, 2026-06-19)

> Decision recorded per operator synthesis on 2026-06-19 (pricing strategy review). Cross-reference:
> `PRICING_STRATEGY_2de9a02d-aacc-443f-8580-702be2dd3632.md` § SYNTHESIS DECISION + § Target buyer.
> Deferred re-anchor experiment preserved at `.v-prompt-packs/v-pricing-design-06-19/` (DO-NOT-RUN).

**Finding:** The operator confirmed that the Team/agency tier is a v1-ACTIVE buyer surface — not a v2-gated
afterthought — while keeping prices ($99/seat/mo) unchanged. The pricing page already surfaces the Team tier;
implementation pack `03-team-tier-visual-treatment.md` adds a contextual "for agencies — solo bloggers choose
Pro" label. `docs/PERSONA_V1.md` previously listed "White-label or agency reporting" as "Out of Scope for V1"
without this clarification, creating a conflict with the in-production pricing tier and the persona-guard tests
(which blocked the "for agencies" label in `allFaqs` as off-persona dilution).

**Decision: Admit the agency/studio buyer as a v1-active SECONDARY buyer. No price change.**

- **PRIMARY v1 persona stays `solo_tech_blogger_bulk_ai_rewriter` (unchanged).** All bulk-first principles,
  the 100–2,000 post scale assumption, and the "single WordPress site" default remain the canonical UX
  decision source. Any PR adding team-COLLABORATION UI (seat invitation flows, role editors, multi-site
  portfolio dashboards) must still justify against this primary persona.

- **SECONDARY v1-active buyer: the agency / studio managing multiple client WordPress sites.** Served by
  the existing Team tier (white-label reports, per-seat roles, audit trail). This is a genuinely sold tier
  on the public pricing page — not a placeholder. The operator's guidance: "support both #2 and #3" buyers
  in v1 (individual operator + agency).

- **The agency tier is surfaced on the public pricing page but DE-EMPHASIZED for solo visitors.** The
  "for agencies — solo bloggers choose Pro" label (pack `03`) directs the primary persona toward Pro;
  agency buyers can self-select Team. The tier is NOT hidden and NOT gated by `FEATURE_TEAMS` on the
  pricing page itself — it is a real, purchasable tier. Only the team-collaboration *routes* (SiteMember
  management, invitation flows) remain behind `FEATURE_TEAMS=false`.

- **This is a NO-PRICE-CHANGE decision.** The Agency $99→$149 re-anchor remains a deferred experiment;
  greenlight triggers are defined in `PRICING_STRATEGY_*.md` § Deferred experiment.

- **Scope of "agency out of scope" (clarified):** what remains out of scope for v1 is not the agency
  *pricing tier* or the *white-label report capability*, but the deeper agency-management shell:
  client-portal branding, custom domain per client, full role-based access editor (invite/remove members
  UI), and multi-site portfolio dashboards. These are behind `FEATURE_TEAMS=false` and `FEATURE_PORTFOLIO=false`.

- **Persona-guard test impact (R6SEO-003):** this decision does NOT move any FAQ between `allFaqs` and
  `teamFaqs`. The FAQ corpus guard remains: `allFaqs` must not contain agency/seat/white-label copy;
  `teamFaqs` (merged only when `VITE_FEATURE_TEAMS=true`) carries that copy. The agency label on the
  pricing page is marketing copy, not a FAQ answer — it falls outside the `faqs.ts` / `faqs.test.ts`
  scope. No test changes are required by this decision.

---

## Anti-Patterns to Avoid

- **Dead-end table rows**: a row that shows metrics but offers no action is
  waste for the persona. Every row in every table must have at least one
  forward CTA (Brief, Rewrite, or View with a clear next step).
- **Blind bulk actions**: any bulk dispatch that can cost money or trigger
  async jobs must show count + estimated cost/time before confirming.
- **Mobile-only responsive hiding of decision-critical columns**: Click delta
  is more important than word count or reading level — it must not be hidden
  at the viewport widths a laptop user actually uses.
- **One-shot timers for background operations**: any operation that runs
  asynchronously (sync, analysis, brief generation) must poll for completion,
  not guess a fixed timeout.
