feat(forms): space-scoped public URL /f/[space]/[slug] (P6)
- migration 028: drop global UNIQUE(forms.slug), add
UNIQUE(space_id, slug); schema.sql mirrored. Form slugs are now
unique per space (fixes cross-tenant slug squatting)
- getPublicForm now takes { space, slug }: resolves the space by its
slug then the form by space_id + slug (maybeSingle)
- route moved app/f/[slug] -> app/f/[space]/[slug]; the public client
submits by formId (slug is no longer globally unambiguous) and the
sign-in link round-trips the full /f/space/slug path
- forms-guard returns the space slug; the builder + forms list show
the full /f/<space>/<slug> share URL; new/edit pass it through
- middleware /f allowlist already covers /f/<space>/<slug>
- getPublicFormSchema + tests updated (333 pass)
build verified (Compiled successfully, exit 0; new route present). No deploy.
This commit is contained in:
@@ -29,6 +29,7 @@ type Status = 'draft' | 'published' | 'closed'
|
||||
|
||||
export type BuilderForm = {
|
||||
id?: string
|
||||
spaceSlug: string
|
||||
slug: string
|
||||
title: string
|
||||
description: string
|
||||
@@ -171,8 +172,9 @@ export function FormBuilder({ initial }: { initial: BuilderForm }) {
|
||||
router.refresh()
|
||||
}
|
||||
|
||||
const publicPath = `/f/${initial.spaceSlug}/${initial.slug}`
|
||||
const publicUrl =
|
||||
typeof window !== 'undefined' ? `${window.location.origin}/f/${initial.slug}` : `/f/${initial.slug}`
|
||||
typeof window !== 'undefined' ? `${window.location.origin}${publicPath}` : publicPath
|
||||
|
||||
return (
|
||||
<div className="grid gap-6 lg:grid-cols-2">
|
||||
@@ -240,7 +242,7 @@ export function FormBuilder({ initial }: { initial: BuilderForm }) {
|
||||
{isEdit ? (
|
||||
<p className="text-xs text-muted-foreground">The slug cannot change after creation.</p>
|
||||
) : (
|
||||
<p className="text-xs text-muted-foreground">Public address: /f/{slug || '…'}</p>
|
||||
<p className="text-xs text-muted-foreground">Public address: /f/{initial.spaceSlug}/{slug || '…'}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
|
||||
Reference in New Issue
Block a user