feat(reports): gate unbuilt Marketing report to 404 for beta
Sales/Operational/Financial are built + verified; Marketing is blocked on the website cutover (launch-readiness Init 1b), not on code. Rather than hide the whole reports surface behind a module toggle, keep it live for beta and 404 the one unbuilt kind so a hand-typed /reports/marketing URL can't reach the "in development" placeholder. The landing page already advertises only the three live reports + Custom. Remove the UNAVAILABLE_NEW_KINDS entry when the Marketing report ships. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,16 @@ Phases (status snapshot 2026-05-27):
|
|||||||
PDF; server-side PDF endpoint for branded output. _See gaps
|
PDF; server-side PDF endpoint for branded output. _See gaps
|
||||||
below._
|
below._
|
||||||
3. ❌ Marketing report — NOT BUILT. Pending Init 1b cutover.
|
3. ❌ Marketing report — NOT BUILT. Pending Init 1b cutover.
|
||||||
|
**Beta gate (2026-06-02):** the `marketing` kind in
|
||||||
|
`reports/[kind]/page.tsx` now returns `notFound()` (via
|
||||||
|
`UNAVAILABLE_NEW_KINDS`) instead of the "in development" placeholder,
|
||||||
|
so the beta reports surface reads as complete — the landing page only
|
||||||
|
advertises Sales / Operational / Financial / Custom, and the
|
||||||
|
hand-typed `/reports/marketing` URL 404s. **Remove the
|
||||||
|
`UNAVAILABLE_NEW_KINDS` entry when this report ships.** Decision: keep
|
||||||
|
the reports page live for beta rather than hiding it behind a module
|
||||||
|
toggle — 3 of 4 reports are fully built + verified (export, templates,
|
||||||
|
scheduling) and strictly beat the dashboard-only fallback.
|
||||||
4. ✅ Financial report — **SHIPPED in b690fb8d.** Built on the canonical
|
4. ✅ Financial report — **SHIPPED in b690fb8d.** Built on the canonical
|
||||||
payments + expenses tables (invoices module stays OFF); the
|
payments + expenses tables (invoices module stays OFF); the
|
||||||
invoice-centric spec was reframed onto the payments model
|
invoice-centric spec was reframed onto the payments model
|
||||||
|
|||||||
@@ -27,6 +27,18 @@ const NEW_KINDS = ['sales', 'financial', 'marketing', 'operational', 'custom'] a
|
|||||||
type LegacyKind = (typeof LEGACY_KINDS)[number];
|
type LegacyKind = (typeof LEGACY_KINDS)[number];
|
||||||
type NewKind = (typeof NEW_KINDS)[number];
|
type NewKind = (typeof NEW_KINDS)[number];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NEW_KINDS that have a card on the /reports landing page each own a
|
||||||
|
* dedicated route (reports/sales, reports/operational, reports/financial,
|
||||||
|
* reports/custom) which shadows this dynamic segment. The only NEW_KIND that
|
||||||
|
* still resolves here is `marketing`, whose builder is blocked on the website
|
||||||
|
* cutover (launch-readiness Initiative 1b) and currently renders only an "in
|
||||||
|
* development" placeholder. Gate it to a 404 for beta so it can't be reached
|
||||||
|
* via a hand-typed URL or a stale saved template. Remove the entry when the
|
||||||
|
* Marketing report ships.
|
||||||
|
*/
|
||||||
|
const UNAVAILABLE_NEW_KINDS: readonly NewKind[] = ['marketing'];
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: Promise<{ portSlug: string; kind: string }>;
|
params: Promise<{ portSlug: string; kind: string }>;
|
||||||
searchParams: Promise<{ from?: string; to?: string }>;
|
searchParams: Promise<{ from?: string; to?: string }>;
|
||||||
@@ -74,6 +86,11 @@ export default async function ReportBuilderPage({ params, searchParams }: PagePr
|
|||||||
const isNew = (NEW_KINDS as readonly string[]).includes(kind);
|
const isNew = (NEW_KINDS as readonly string[]).includes(kind);
|
||||||
if (!isLegacy && !isNew) notFound();
|
if (!isLegacy && !isNew) notFound();
|
||||||
|
|
||||||
|
// Unbuilt report kinds (currently just Marketing) 404 rather than show the
|
||||||
|
// "in development" placeholder — keeps the beta reports surface looking
|
||||||
|
// complete. See UNAVAILABLE_NEW_KINDS above.
|
||||||
|
if ((UNAVAILABLE_NEW_KINDS as readonly string[]).includes(kind)) notFound();
|
||||||
|
|
||||||
if (isLegacy) {
|
if (isLegacy) {
|
||||||
const typedKind = kind as LegacyKind;
|
const typedKind = kind as LegacyKind;
|
||||||
const labels = LEGACY_LABELS[typedKind];
|
const labels = LEGACY_LABELS[typedKind];
|
||||||
|
|||||||
Reference in New Issue
Block a user