# Landlord Management (Main · User Portal)

**Portal:** Main · **Route:** `main.portal.landlord-management.index` (`GET /property/landlord-management`; `GET /property/renovation-management` redirects) · **Nav:** sidebar → **Landlord Management** · **Gated by:** `['auth','main','contact.verified','lock.analyze']`

## What it does
The **after-you-own-it** line: everything a member does with a property once it is theirs — renovate
it, let it, run the tenancy, keep the tax right, or hand any of that to the team. One destination,
five tabs: **Renovation · Rent · Tenant Management · Tax Planning · Concierge Service**.

It is also the **Control** stage of the member's DMAIC road (the course's 第6单元 买房 · 养房 · 再买房);
the Learning Hub's road links here after a member buys.

> **Renamed from "Renovation & Management" on 2026-08-27** (and before that a dead `Tenant Management
> · SOON` row). The old name listed two of the jobs; the new one names the **role**, so all five belong
> to it without the title enumerating them. The URL moved with it; the old one redirects because it was
> the sidebar entry until that day.

> ⚠️ **Four of the five tabs are still in build, and say so.** GUIDELINES §15: a product line with no
> surface yet still gets a **real route and a page that shows the plan**. Each in-build tab states what
> it will do, lists what a member can **use today** (a course, the free Rental Estimate, the official
> tax site) and captures demand through the feature waitlist. The fifth, **Concierge**, is live: it is
> the done-for-you version of the same jobs, so the member's own requests are listed on this page.

## How it works
- **The controller is the content.** `LandlordManagementController@index` ships four `sections`
  (`key`, `label`, `headline`, `body`, `points[]`, `links[]`) plus a `concierge` prop (`requests[]`,
  `services`, `statuses`) — no model of its own. When an in-build tab is actually built it stops
  being a tab body here and becomes its own page; the strip stays as the way between them.
- **The tab keys ARE the waitlist keys**, so the page and the signups can never drift apart. Tabs are
  hosted by the shared [`Components/ShowTabs.vue`](/resources/js/Components/ShowTabs.vue), which
  lazy-mounts the active tab and syncs it to `?tab=` — a refresh or a shared link lands on the same
  one (`?tab=concierge`, `?tab=rent`).
- **Demand capture** reuses `Components/Portal/FeatureWaitlistModal.vue` → `POST /waitlist` →
  `feature_waitlist_signups` (one row per member per feature). Read demand with
  `SELECT feature, COUNT(*) … GROUP BY feature`; there is deliberately no Manage UI.
- ⚠️ **`tenant-management` KEEPS ITS ORIGINAL WAITLIST KEY** through both renames.
  `Src\Portal\FeatureWaitlistSignup` states the rule: *append, never rename — a renamed key orphans
  every row already stored under it*. `renovation`, `tax-planning` (2026-08-26) and `rent`
  (2026-08-27) were appended beside it.
- **The Concierge tab reads the same rows as `/property-concierge`.** The owner-side card shape
  (`conciergeCard()`) lives in the shared `PresentsConciergeRequest` trait so the two lists can never
  disagree; creating and following a request still happens on the Concierge pages — this tab is the
  view from the landlord's shelf, with **New request** and **Open Property Concierge** beside it.

## Five-day trainees (2026-09-02)
`index()` renders `Main/Portal/Training/Locked` (`title / reason / day / cardHref / backHref`) for a
trainee whose C card is not complete yet (`TrainingAccess::verdict($user, 'landlord')`, Day 4);
everyone else gets the page as before.

## Related files

**Backend**
- [app/Http/Controllers/Main/Portal/LandlordManagementController.php](/app/Http/Controllers/Main/Portal/LandlordManagementController.php) — the four sections + the concierge list.
- [app/Http/Controllers/Concerns/PresentsConciergeRequest.php](/app/Http/Controllers/Concerns/PresentsConciergeRequest.php) — `conciergeCard()`, shared with `ConciergeController`.
- [src/Portal/FeatureWaitlistSignup.php](/src/Portal/FeatureWaitlistSignup.php) — `FEATURE_RENOVATION` / `FEATURE_RENT` / `FEATURE_TENANT_MANAGEMENT` / `FEATURE_TAX_PLANNING` (+ the append-never-rename rule).
- [app/Http/Controllers/Main/Portal/FeatureWaitlistController.php](/app/Http/Controllers/Main/Portal/FeatureWaitlistController.php) · [Waitlist/StoreRequest.php](/app/Http/Requests/Main/Portal/Waitlist/StoreRequest.php) — validates `feature` against the model's own constant, so a new key needs no validation change.

**Frontend (Vue)**
- [resources/js/Pages/Main/Portal/LandlordManagement/Index.vue](/resources/js/Pages/Main/Portal/LandlordManagement/Index.vue) — the four in-build tab bodies (pitch · use-today links · Notify me) + the Concierge tab.
- [resources/js/Pages/Main/Portal/Concierge/Partials/RequestCard.vue](/resources/js/Pages/Main/Portal/Concierge/Partials/RequestCard.vue) — reused for the Concierge tab's cards.
- [resources/js/Components/ShowTabs.vue](/resources/js/Components/ShowTabs.vue) (shared, `?tab=` sync) · [resources/js/Components/Portal/FeatureWaitlistModal.vue](/resources/js/Components/Portal/FeatureWaitlistModal.vue) (per-feature copy lives in its `FEATURES` map — `rent` added).
- Nav entry: [resources/js/Layouts/AppLayout.vue](/resources/js/Layouts/AppLayout.vue) (`prefixes` carries the old path so the entry stays lit through the redirect).

**Routes**
- [routes/main.php](/routes/main.php) — `GET property/landlord-management` + the `property/renovation-management` redirect (route name kept for anything still calling it).

**Tests**
- [tests/Feature/Main/Portal/LandlordManagementTest.php](/tests/Feature/Main/Portal/LandlordManagementTest.php) — the page, the five tabs' keys, the concierge list scoped to the lead, and the redirect.

**See also:** [Property Concierge](/docs/modules_handbook/main/property-concierge/readMe.md) — the
module behind the live tab · [Rental Estimate](/docs/modules_handbook/main/rental-estimate/readMe.md) —
the free tool the Rent tab points at · [Courses / LMS](/docs/modules_handbook/manage/lms/readMe.md) —
the three courses the tabs link to · [DMAIC 之路](/docs/modules_handbook/main/dmaic-road/readMe.md) —
the Learning Hub's road: this page is the **Control** stage's tool (the C card's hand-off), and the
terminal screen's "先把这一间养稳" button lands here.
