mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-27 21:33:41 +02:00
* feat(web): add use-cases content pipeline with welcome page (MUL-2349) Wire fumadocs-mdx into apps/web with an independent collection rooted at content/use-cases/. Add the first page at /use-cases/welcome (header + H1 + prose + screenshot + footer) using the about-page visual shell. - source.config.ts + lib/use-cases-source.ts (separate from apps/docs) - features/landing/components/mdx/screenshot.tsx wraps next/image - public/use-cases/welcome/screenshot-1.png placeholder (55KB) - next.config.ts wraps NextConfig with createMDX() - .gitignore + eslint ignore .source/ Co-authored-by: multica-agent <github@multica.ai> * feat(web): bilingual db-boy use case with cookie locale (MUL-2349) Extends the use-cases pipeline into the first real article. - ZH + EN MDX (auto-data-analysis.{zh,en}.mdx) sharing three real screenshots; sensitive fields on db-boy-profile.png (RDS host, DB name, password) are blurred in-place. - Cookie-based locale: /use-cases/<slug> reads multica-locale server-side via lib/use-cases-i18n.ts (mirrors LandingLayout's cookie + Accept-Language fallback). Same URL serves either language; no [lang] segment so all other landing routes stay unchanged. - Frontmatter schema (source.config.ts): z.looseObject with declared hero_image / updated_at (required) / category (optional); a preprocess converts YAML-auto-parsed Date back to a YYYY-MM-DD string. - MDX components factory createMdxComponents(locale) routes the secondary CTA to /docs/zh (ZH) or /docs (EN); internal MDX links use <Link> for SPA nav; full-width and half-width colons both trigger [CTA: ...] / [占位图: ...] markers; 副 and Secondary both work as the secondary CTA prefix. - Index page localizes hero / subtitle / card CTA / metadata; sort fallback uses an epoch placeholder so undefined-order disappears. - Landing header + footer surface use-cases entry in both locales. - Detail route: sticky header, right-rail TOC with anchor jumps, scroll-mt-[100px] on H2/H3 so anchor jumps don't slip under the sticky header. - Drop welcome demo page. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(web): resolve code review blockers on use-cases PR - Add `use-cases` to reserved_slugs.json + regenerate TS (P1: prevent future workspace slug collision) - Fix dead links in both MDX files: /features/* → /docs/* (P2) - Remove duplicate brand suffix in page title metadata (nit) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(web): align usecases locale routing * chore: refresh web mdx lockfile * fix(web): type mdx next config adapter * fix(web): wrap settings route page --------- Co-authored-by: multica-agent <github@multica.ai> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
155 lines
4.0 KiB
TypeScript
155 lines
4.0 KiB
TypeScript
// AUTO-GENERATED by scripts/generate-reserved-slugs.mjs.
|
|
// Do not edit by hand — edit server/internal/handler/reserved_slugs.json
|
|
// and run `pnpm generate:reserved-slugs`.
|
|
|
|
/**
|
|
* Slugs reserved because they collide with frontend top-level routes,
|
|
* platform features, or web standards.
|
|
*
|
|
* Single source of truth: `server/internal/handler/reserved_slugs.json`.
|
|
* The Go backend embeds that JSON; this file is regenerated from it.
|
|
*
|
|
* Convention for new global routes (CLAUDE.md): use a single word
|
|
* (`/login`, `/inbox`) or `/{noun}/{verb}` (`/workspaces/new`). Hyphenated
|
|
* root-level word groups (`/new-workspace`, `/create-team`) collide with
|
|
* common user workspace names — see PR for full discussion.
|
|
*/
|
|
export const RESERVED_SLUGS: ReadonlySet<string> = new Set([
|
|
// Auth flow
|
|
// `onboarding` is historical, kept reserved post-removal of the route.
|
|
"login",
|
|
"logout",
|
|
"signin",
|
|
"signout",
|
|
"signup",
|
|
"auth",
|
|
"oauth",
|
|
"callback",
|
|
"invite",
|
|
"invitations",
|
|
"verify",
|
|
"reset",
|
|
"password",
|
|
"onboarding",
|
|
|
|
// Platform / marketing routes (current + likely-future)
|
|
// `multica` is reserved as the brand name to block impersonation workspaces.
|
|
// `www`, `new`, `home`, `homepage`, `dashboard` are confusables or
|
|
// likely-future global landing/entry routes; `homepage` matches the existing
|
|
// `/homepage` landing variant in apps/web.
|
|
"api",
|
|
"admin",
|
|
"multica",
|
|
"www",
|
|
"new",
|
|
"home",
|
|
"homepage",
|
|
"dashboard",
|
|
"help",
|
|
"about",
|
|
"pricing",
|
|
"changelog",
|
|
"docs",
|
|
"support",
|
|
"status",
|
|
"legal",
|
|
"privacy",
|
|
"terms",
|
|
"security",
|
|
"contact",
|
|
"contact-sales",
|
|
"blog",
|
|
"careers",
|
|
"press",
|
|
"download",
|
|
"usecases",
|
|
|
|
// Account / billing (likely-future global routes in the avatar menu)
|
|
"profile",
|
|
"account",
|
|
"billing",
|
|
"notifications",
|
|
"search",
|
|
"members",
|
|
|
|
// Workspace route segments
|
|
// Reserving each segment name prevents `/{slug}/{view}` from being visually
|
|
// ambiguous (e.g. a workspace named `issues` would make `/issues/abc` mean two
|
|
// things). `workspaces` covers the global `/workspaces/new` workspace-creation
|
|
// page; `teams` is reserved for future team management.
|
|
"issues",
|
|
"projects",
|
|
"autopilots",
|
|
"agents",
|
|
"squads",
|
|
"inbox",
|
|
"my-issues",
|
|
"usage",
|
|
"runtimes",
|
|
"skills",
|
|
"settings",
|
|
"workspaces",
|
|
"teams",
|
|
|
|
// API / integration prefixes
|
|
// `api` above already covers `/api/*`; these guard against future top-level
|
|
// API alias routes (e.g. `/v1`, `/graphql`) and against accidental workspace
|
|
// slugs that read like API identifiers.
|
|
"v1",
|
|
"v2",
|
|
"graphql",
|
|
"webhooks",
|
|
"sdk",
|
|
"tokens",
|
|
"cli",
|
|
|
|
// Backend ops / observability
|
|
// `/health`, `/readyz`, `/healthz`, and `/ws` exist on the backend host;
|
|
// reserving them on the workspace slug space prevents naming confusion if/when
|
|
// these paths are ever proxied through the web origin.
|
|
"health",
|
|
"readyz",
|
|
"healthz",
|
|
"ws",
|
|
"metrics",
|
|
"ping",
|
|
|
|
// RFC 2142 — privileged email mailboxes
|
|
// Allowing user workspaces with these slugs would let attackers spoof system
|
|
// messaging.
|
|
"postmaster",
|
|
"abuse",
|
|
"noreply",
|
|
"webmaster",
|
|
"hostmaster",
|
|
|
|
// Hostname / subdomain confusables
|
|
// Even on path-based routing these names attract phishing and
|
|
// subdomain-takeover attempts.
|
|
"mail",
|
|
"ftp",
|
|
"static",
|
|
"cdn",
|
|
"assets",
|
|
"public",
|
|
"files",
|
|
"uploads",
|
|
|
|
// Next.js / web standards
|
|
// These entries contain characters (dots, underscores) that today's slug regex
|
|
// `^[a-z0-9]+(?:-[a-z0-9]+)*$` already rejects at the format-validation step —
|
|
// so `isReservedSlug` never actually matches them. They are kept as
|
|
// defense-in-depth so that if the slug regex is ever relaxed (e.g. to support
|
|
// dotted corporate slugs like `acme.io`), these system paths stay protected.
|
|
"_next",
|
|
"favicon.ico",
|
|
"robots.txt",
|
|
"sitemap.xml",
|
|
"manifest.json",
|
|
".well-known",
|
|
]);
|
|
|
|
export function isReservedSlug(slug: string): boolean {
|
|
return RESERVED_SLUGS.has(slug);
|
|
}
|