feat(db): mesh data model — meshes, members, invites, audit log
- pgSchema "mesh" with 4 tables isolating the peer mesh domain - Enums: visibility, transport, tier, role - audit_log is metadata-only (E2E encryption enforced at broker/client) - Cascade on mesh delete, soft-delete via archivedAt/revokedAt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: Legal pages
|
||||
description: Learn how to create and update legal pages
|
||||
url: /docs/web/marketing/legal
|
||||
---
|
||||
|
||||
# Legal pages
|
||||
|
||||
Legal pages are defined in the `apps/web/src/app/[locale]/(marketing)/legal` directory.
|
||||
|
||||
TurboStarter comes with the following legal pages:
|
||||
|
||||
* **Terms and Conditions**: to define the terms and conditions of your application
|
||||
* **Privacy Policy**: to define the privacy policy of your application
|
||||
* **Cookie Policy**: to define the cookie policy of your application
|
||||
|
||||
For obvious reasons, **these pages are empty and you need to fill in the content.**
|
||||
|
||||
## Content from CMS
|
||||
|
||||
Content for legal pages are stored as [MDX](https://mdxjs.com/) files in [content collection](/docs/web/cms/content-collections) in `packages/cms/src/content/collections/legal` directory.
|
||||
|
||||
Then it's parsed and rendered as a Next.js page under corresponding slug:
|
||||
|
||||
```tsx title="apps/web/src/app/[locale]/(marketing)/legal/[slug]/page.tsx"
|
||||
import {
|
||||
CollectionType,
|
||||
getContentItemBySlug,
|
||||
getContentItems,
|
||||
} from "@turbostarter/cms";
|
||||
|
||||
export default async function Page({ params }: PageParams) {
|
||||
const item = getContentItemBySlug({
|
||||
collection: CollectionType.LEGAL,
|
||||
slug: (await params).slug,
|
||||
locale: (await params).locale,
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
return <Mdx mdx={item.mdx} />;
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return getContentItems({ collection: CollectionType.LEGAL }).items.map(
|
||||
({ slug, locale }) => ({
|
||||
slug,
|
||||
locale,
|
||||
}),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
As it's fully typesafe it also allows us to generate metadata for each page based on the frontmatter that you define in the MDX file:
|
||||
|
||||
```tsx title="apps/web/src/app/[locale]/(marketing)/legal/[slug]/page.tsx"
|
||||
export async function generateMetadata({ params }: PageParams) {
|
||||
const item = getContentItemBySlug({
|
||||
collection: CollectionType.LEGAL,
|
||||
slug: (await params).slug,
|
||||
locale: (await params).locale,
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
return notFound();
|
||||
}
|
||||
|
||||
return getMetadata({
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
})({ params });
|
||||
}
|
||||
```
|
||||
|
||||
Read more about it in the [CMS section](/docs/web/cms/overview).
|
||||
|
||||
## ChatGPT prompts
|
||||
|
||||
Each `.mdx` file with legal content include a set of useful prompts that you can use to generate the content.
|
||||
|
||||
<Callout type="warn" title="Please, be aware of this!">
|
||||
Please, be aware that **ChatGPT is not a lawyer** and the content generated by it should be reviewed by one before publishing. Take your time and treat the generated content as a starting point not a final document.
|
||||
</Callout>
|
||||
|
||||
```mdx title="privacy-policy.mdx"
|
||||
---
|
||||
title: Privacy Policy
|
||||
description: Our privacy policy outlines how we collect, use, and protect your personal information.
|
||||
---
|
||||
|
||||
{/* 💡 You can use one of the following ChatGPT prompts to generate this 💡 */}
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
Feel free to add your own content or even additional pages to the `legal` collection.
|
||||
Reference in New Issue
Block a user