Add legal pages, ToS acceptance, and alpha banner
- Journal: Impressum (§5 TMG), Terms of Service, GDPR privacy page - Registration flow: required ToS checkbox, termsAcceptedAt persisted - Alpha banner on Journal (always visible); alpha badge on Planner hero - Footer with legal links + GitHub on both apps - Reduce PII: sendDefaultPii=false, Sentry init only after login (Journal) - Drop Sentry from Planner (no login, no consent possible) - Drop localStorage caching from i18n client detection - Sync SSR i18n resources each request so locale edits HMR without restart Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6c1cd23358
commit
cc0f44258a
24 changed files with 773 additions and 206 deletions
|
|
@ -76,6 +76,7 @@ export async function finishRegistration(
|
|||
email,
|
||||
username,
|
||||
domain,
|
||||
termsAcceptedAt: new Date(),
|
||||
});
|
||||
|
||||
await db.insert(credentials).values({
|
||||
|
|
@ -158,7 +159,7 @@ export async function registerWithMagicLink(email: string, username: string): Pr
|
|||
const userId = randomUUID();
|
||||
const domain = process.env.DOMAIN ?? "localhost";
|
||||
|
||||
await db.insert(users).values({ id: userId, email, username, domain });
|
||||
await db.insert(users).values({ id: userId, email, username, domain, termsAcceptedAt: new Date() });
|
||||
|
||||
// Create magic token for verification
|
||||
const token = randomBytes(32).toString("base64url");
|
||||
|
|
|
|||
20
apps/journal/app/lib/operator.ts
Normal file
20
apps/journal/app/lib/operator.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Operator details for the Impressum (§5 TMG / §18 MStV).
|
||||
*
|
||||
* Required by German law. Address must be a reachable physical address.
|
||||
* Email must be a direct contact (no forms-only policy).
|
||||
*/
|
||||
export const operator = {
|
||||
name: "Ullrich Schäfer",
|
||||
address: {
|
||||
street: "Mehringdamm 87",
|
||||
postalCode: "10965",
|
||||
city: "Berlin",
|
||||
country: "Germany",
|
||||
},
|
||||
email: "legal@trails.cool",
|
||||
// Responsible for content per §18 Abs. 2 MStV
|
||||
responsiblePerson: "Ullrich Schäfer",
|
||||
} as const;
|
||||
|
||||
export type Operator = typeof operator;
|
||||
30
apps/journal/app/lib/sentry.client.ts
Normal file
30
apps/journal/app/lib/sentry.client.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import * as Sentry from "@sentry/react";
|
||||
import { useEffect } from "react";
|
||||
import { useLocation, useNavigationType, createRoutesFromChildren, matchRoutes } from "react-router";
|
||||
|
||||
let initialized = false;
|
||||
|
||||
export function initSentryClient() {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
const sentryEnvironment = import.meta.env.VITE_SENTRY_ENVIRONMENT ??
|
||||
(import.meta.env.PROD ? "production" : "development");
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://a32ffcc575d34be072e91b20f247eeee@o4509530546634752.ingest.de.sentry.io/4509530555547728",
|
||||
integrations: [
|
||||
Sentry.reactRouterV7BrowserTracingIntegration({
|
||||
useEffect,
|
||||
useLocation,
|
||||
useNavigationType,
|
||||
createRoutesFromChildren,
|
||||
matchRoutes,
|
||||
}),
|
||||
],
|
||||
environment: sentryEnvironment,
|
||||
tracesSampleRate: sentryEnvironment === "ci" ? 0 : 1.0,
|
||||
enabled: import.meta.env.PROD && sentryEnvironment !== "ci",
|
||||
sendDefaultPii: false,
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue