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:
Alejandro Gutiérrez
2026-04-04 21:19:32 +01:00
commit d3163a5bff
1384 changed files with 314925 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
---
title: Configuration
description: Learn how to configure internationalization in TurboStarter.
url: /docs/web/internationalization/configuration
---
# Configuration
The default global configuration is defined in the `@turbostarter/i18n` package and shared across all applications. You can override it in each app to customize the internationalization setup for that specific app.
The configuration is defined in the `packages/i18n/src/config.ts` file:
```ts title="packages/i18n/src/config.ts"
export const config = {
locales: ["en", "es"],
defaultLocale: "en",
namespaces: [
"common",
"admin",
"organization",
"dashboard",
"auth",
"billing",
"marketing",
"validation",
],
cookie: "locale",
} as const;
```
Let's break down the configuration options:
* `locales`: An array of all supported locales.
* `defaultLocale`: The default locale to use if no other locale is detected.
* `namespaces`: An array of all namespaces used in the application.
* `cookie`: The name of the cookie to store the detected locale (acts as a cache).
## Translation files
The core of the whole internationalization setup is the translation files. They are stored in the `packages/i18n/src/translations` directory and are used to store the translations for each locale and namespace.
Each directory represents a locale and contains a set of files, each corresponding to a specific namespace (e.g. `en/common.json`). Inside we define the keys and values for the translations.
```ts title="packages/i18n/src/translations/en/common.json"
{
"hello": "Hello, world!"
}
```
That way we can ensure that we have a single source of truth for the translations and we can use them consistently in all the applications.
## Locales
The `locales` array in the configuration defines the list of supported languages in your application. Each locale is represented by a string that uniquely identifies the language.
To add a new locale, you need to:
1. Add the new locale to the `locales` array in the configuration.
2. Create a new directory in the `packages/i18n/src/translations` directory.
3. Create a new file in the new directory for each namespace and add the translations for the new locale.
For example, if you want to add the `fr` locale, you need to:
1. Add `fr` to the `locales` array in the configuration.
2. Create a new directory in the `packages/i18n/src/translations` directory.
3. Create a new file for each namespace in the created directory and add the translations for the new locale.
### Fallback locale
The `defaultLocale` option in the configuration defines the fallback locale. If a translation is not found for a specific locale, the fallback locale will be used.
We can also override this setting in each [app configuration](/docs/web/configuration/app) by configuring the `locale` property.
## Namespaces
`namespaces` are used to group translations by feature or module. This helps in organizing the translations and makes it easier to maintain them.
### Why not one big namespace?
Using multiple namespaces instead of one large namespace helps with:
1. **Performance:** load translations on-demand instead of all at once, reducing the initial bundle size.
2. **Organization:** group translations by feature (e.g., `auth`, `common`, `dashboard`).
3. **Maintenance:** easier to update and manage smaller translation files.
4. **Development:** better TypeScript support and team collaboration.
For example, you might structure your namespaces like this:
<Tabs items={["Common", "Auth", "Billing"]}>
<Tab value="Common">
```ts title="packages/i18n/src/translations/en/common.json"
{
"hello": "Hello, world!"
}
```
</Tab>
<Tab value="Auth">
```ts title="packages/i18n/src/translations/en/auth.json"
{
"login": "Login",
"register": "Register"
}
```
</Tab>
<Tab value="Billing">
```ts title="packages/i18n/src/translations/en/billing.json"
{
"invoice": "Invoice",
"payment": "Payment",
"subscription": "Subscription"
}
```
</Tab>
</Tabs>
Remember that while you can create as many namespaces as needed, it's important to maintain a balance - too many namespaces can lead to unnecessary complexity, while too few might defeat the purpose of separation.
## Routing
TurboStarter implements locale-based routing by placing pages under the `[locale]` folder. However, the default locale (usually `en`) is not prefixed in the URL for better SEO and user experience.
For example, with English as the default locale and Polish as an additional language:
* `/dashboard` → English version (default locale)
* `/pl/dashboard` → Polish version
The app also automatically detects the user's preferred language through cookies, HTML `lang` attribute, and browser's `Accept-Language` header.
This ensures a seamless experience where users get content in their preferred language while maintaining clean URLs for the default locale.
<Callout>
You can override the locale by manually setting the cookie or by navigating to
a URL with a different locale prefix.
</Callout>

View File

@@ -0,0 +1,40 @@
---
title: Overview
description: Get started with internationalization in TurboStarter.
url: /docs/web/internationalization/overview
---
# Overview
TurboStarter uses [i18next](https://www.i18next.com/) for internationalization, which is one of the most popular and mature (over 10 years of development!) i18n frameworks for JavaScript.
<Callout title="Why i18next?">
With i18next, you can easily translate your application into multiple
languages, handle complex pluralization rules, format dates and numbers
according to locale, and much more. The framework is highly extensible through
plugins and provides excellent TypeScript support out of the box.
</Callout>
You can read more about `i18next` package in the [official documentation](https://www.i18next.com/overview/getting-started).
![i18next logo](/images/docs/i18next.jpg)
## Getting started
TurboStarter comes with `i18next` pre-configured and abstracted behind the `@turbostarter/i18n` package. This abstraction layer ensures that any future changes to the underlying translation library won't impact your application code. The internationalization setup is ready to use out of the box and includes:
* Multiple language support out of the box
* Type-safe translations with generated types
* Automatic language detection
* Easy-to-use React hooks for translations
* Built-in number and date formatting
* Support for nested translation keys
* Pluralization handling
To start using internationalization in your app, you'll need to:
1. Configure your supported languages
2. Add translation files
3. Use translation hooks in your components
Check out the following sections to learn more about each step:

View File

@@ -0,0 +1,147 @@
---
title: Translating app
description: Learn how to translate your application to multiple languages.
url: /docs/web/internationalization/translations
---
# Translating app
TurboStarter provides a flexible and powerful translation system that works seamlessly across your entire application. Whether you're working with React Server Components (RSC), client-side components, or server-side rendering, you can easily integrate translations to create a fully internationalized experience.
The translation system supports:
* **Server components (RSC)** for efficient server-side translations
* **Client components** for dynamic language switching
* **Server-side rendering** for SEO-friendly translated content
## Server components (RSC)
To get the translations in a server component, you can use the `getTranslation` method:
```tsx
import { getTranslation } from "@turbostarter/i18n";
export default async function MyComponent() {
const { t } = await getTranslation();
return <div>{t("common:hello")}</div>;
}
```
There is also a possibility to use the [Trans](https://react.i18next.com/latest/trans-component) component, which could be useful e.g. for interpolating variables:
```tsx
import { Trans } from "@turbostarter/i18n";
import { withI18n } from "@turbostarter/i18n/with-i18n";
const Page = () => {
return <Trans i18nKey="common:hello" components={{ bold: <b /> }} />;
};
export default withI18n(Page);
```
Although, to make it available in the server component, you need to wrap it with the `withI18n` HOC.
Given that server components are rendered in parallel, it's uncertain which one will render first. Therefore, it's crucial to initialize the translations before rendering the server component on each page/layout.
## Client components
For client components, you can use the `useTranslation` hook from the `@turbostarter/i18n` package:
```tsx
"use client";
import { useTranslation } from "@turbostarter/i18n";
export default function MyComponent() {
const { t } = useTranslation();
return <div>{t("common:hello")}</div>;
}
```
That's the simplest way to get the translations in a client component.
## Server-side
In all other places (e.g. metadata, API routes, sitemaps etc.) you can use the `getTranslation` method to get the translations server-side:
```ts
import { getTranslation } from "@turbostarter/i18n";
export const generateMetadata = async () => {
const { t } = await getTranslation();
return {
title: t("common:title"),
};
};
```
It automatically checks the user's preferred locale and uses the correct translation.
## Language switcher
TurboStarter ships with a language customizer component that allows you to switch between languages. You can import and use the `LocaleCustomizer` component and drop it anywhere in your application to allow users to change the language seamlessly.
```tsx
import { LocaleCustomizer } from "@turbostarter/ui-web/i18n";
export default function MyComponent() {
return <LocaleCustomizer />;
}
```
The component automatically displays all languages configured in your i18n settings. When a user switches languages, it will:
1. Update the URL to include the new locale prefix (e.g. `/es/dashboard`)
2. Store the selected locale in a cookie for persistence
3. Refresh translations across the entire application
4. Preserve the current page/route during the language switch
This provides a seamless localization experience without requiring any additional configuration.
## Best practices
Here are some recommended best practices for managing translations in your application:
* Use descriptive translation keys that follow a logical hierarchy
```ts
// ✅ Good
"auth.login.title";
// ❌ Bad
"loginTitleForAuth";
```
* Keep translations organized in separate namespaces/files based on features or sections
```
translations/
├── en/
│ ├── auth.json
│ └── common.json
└── pl/
├── auth.json
└── billing.json
```
* Avoid hardcoding text strings - always use translation keys even for seemingly static content
* Always provide a fallback language (usually English) for when translations are missing
* Use pluralization and interpolation features when dealing with dynamic content
```ts
// Pluralization
t("items", { count: 2 }); // "2 items"
// Interpolation
t("welcome", { name: "John" }); // "Welcome, John!"
```
* Regularly review and clean up unused translation keys to keep files maintainable
* Use TypeScript for type-safe translation keys