Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Roadmap

MOTIR-4221Blocked

(motir-core) The Public address pane, part 1 — the rail entry and its doors, the pane shell, and the workspace subdomain card: claim, rename with the retained-alias warning, copy and open; en + zh

Opened by Zhu Yue ·

The first half of the settings surface a customer configures their address from: the rail entry, both doors into it, the pane's shell, and the workspace-subdomain card — built to the design panels 0, 1, 2, 8 and 9, over the subdomain service. The custom-domain list renders INSIDE this pane and is part 2; this card ships the room it renders in. The pane is split in two on purpose: one card for both would exceed the estimation gate, and the design's allocation gives each card its own panels.

What ships

  • The rail entrylib/settings/projectSettingsNav.ts gains { id: 'public-address', group: 'access', href: '/settings/project/public-address', icon: Globe, labelKey: 'nav.publicAddress', permission: 'project:manage_access' } between members and roles (the design's panel 0), with the VERIFIED-permission comment the file's other entries carry; the registry totality test and the destination guard (guardSettingsPage('public-address', ctx)) cover it by construction. Cloud-only: the entry is absent and the page notFound()s when isCloud() is false — the BuildInPublicPromoCard pattern (app/(authed)/settings/project/page.tsx).
  • The second door — the share-link row in ProjectMembersSettings.tsx (design/public-projects Panel 6, rendered only while the project is public) gains the Set up your own address → link to the pane, exactly as panel 0 draws it. A small edit to a shipped component: read its access gate before adding the link.
  • The pageapp/(authed)/settings/project/public-address/page.tsx in the shape of the members page: session → active project → guardSettingsPage → the pane's reads (the workspace subdomain DTO, and the addresses list part 2 will render) behind Suspense with SettingsPaneFrame.
  • The subdomain card_components/PublicSubdomainCard.tsx: panel 1 (unclaimed: the Input with the live helperText preview <label>.<base>, grammar hint, inline reserved / taken / invalid errors mapped from the route's codes), panel 2 (claimed: the address row with copy + open ↗, Rename with the retained-alias warning and renamesLeft, the rename confirm Modal), panel 8 (non-admin read-only — a workspace member sees the address and no controls, using the same canManage-style gate the members pane uses but for the WORKSPACE role, which is what the service asserts). Optimistic writes through PUT /api/workspaces/{id}/public-subdomain with the members pane's toast + rollback pattern.
  • A slot for part 2 — the page composes <CustomDomainsSection /> from a file part 2 creates; this card ships it as a typed stub that renders nothing, so part 2 is an addition, not an edit.
  • Copy and i18n — every string under settings.publicAddress.* in messages/en.json AND messages/zh.json (the repository ships both; a key present in one and not the other fails the i18n parity test — run it).
  • Tests: the registry entry (totality, permission, group order); the page's cloud gate and destination guard; the card's four states rendered from fixtures; the rename confirm; the error mapping for each route code; i18n parity.

Boundary

No custom-domain UI (part 2), no service or route change (the subdomain service's are complete), no design change — a deviation from the asset is recorded ON the asset, not left in code. Nothing outside motir-core.

Acceptance criteria

  • Public address appears in the settings rail in the access group between Members & access and Roles for a user holding project:manage_access on a cloud build, and is absent — with the route answering 404 — when MOTIR_CLOUD is unset; the registry totality test and the destination-guard test both cover the new entry without an exemption.
  • The share-link row on the members pane links to the new pane while the project is public, and not otherwise.
  • The subdomain card renders the unclaimed, claimed and read-only states as the design's panels 1, 2 and 8 draw them; claiming a reserved label shows the inline error from the route's code without a page reload; renaming shows the retained-alias warning and the remaining count, and the old address appears under the card as an alias after confirm.
  • Every string is in en.json and zh.json; the parity test is green.
  • pnpm test covers the card at the repository's ≥90% per-file floor; no file outside motir-core is touched.

Context refs

  • the design — panels 0, 1, 2, 8, 9 and the access-path table; motir-core/design/projects/public-address.mock.html
  • the subdomain service — the DTO and route this card calls; part 2 — what renders in the slot
  • motir-core/lib/settings/projectSettingsNav.ts · app/(authed)/settings/project/_guard.tsx · app/(authed)/settings/project/members/page.tsx + _components/ProjectMembersSettings.tsx — the pane grammar, the gate, the share-link row
  • motir-core/app/(authed)/settings/project/page.tsxisCloud() gating a settings affordance (BuildInPublicPromoCard)
  • motir-core/messages/en.json · messages/zh.json — the two catalogues
  • motir-core/components/ui/*Card, Input, Button, Modal, Pill, Tooltip; motir-core/CLAUDE.md — component + token reuse

Discussion

No comments yet.

Adding to this discussion signs you in on app.motir.co and brings you back to this request.

Add a comment