Policies
The Policies app is the central hub for all legal, privacy, and compliance content, built with Next.js 16 and featuring full internationalization support.
Features
Legal Pages
- Privacy Policy - Data collection, usage, and user rights
- Terms of Service - Legal terms and conditions
- Cookie Policy - Cookie usage and consent information
- Security - Security practices and policies
- FAQ - Frequently asked questions
Competition Rules
Dedicated section for competition-specific terms and rules.
Internationalization
Full multi-language support:
- English (default)
- German
Language detection based on browser preferences with manual override.
Pages & Routes
| Route | Description |
|---|---|
/ | Overview/index page |
/privacy | Privacy policy |
/terms | Terms of service |
/terms/competition | Competition rules |
/cookies | Cookie policy |
/security | Security practices |
/faq | Frequently asked questions |
All routes are localized under /{locale}/ (e.g., /en/privacy, /de/privacy).
Technology Stack
| Technology | Purpose |
|---|---|
| Next.js 16 | React framework with App Router |
| next-intl | Internationalization |
| TailwindCSS 4 | Styling |
| @elcto/ui | Shared UI components |
| @elcto/cookies-consent | Cookie consent management |
Project Structure
platform/policies/
├── src/
│ ├── app/
│ │ ├── [locale]/ # Localized routes
│ │ │ ├── cookies/ # Cookie policy
│ │ │ ├── faq/ # FAQ
│ │ │ ├── privacy/ # Privacy policy
│ │ │ ├── security/ # Security practices
│ │ │ ├── terms/ # Terms of service
│ │ │ │ └── competition/
│ │ │ ├── layout.tsx
│ │ │ └── page.tsx
│ │ ├── api/
│ │ │ ├── auth/ # NextAuth handlers
│ │ │ ├── health/ # Health check endpoint
│ │ │ └── user/ # User endpoints
│ │ ├── layout.tsx
│ │ └── globals.css
│ ├── components/
│ ├── lib/
│ └── types/
├── messages/ # i18n translation files
│ ├── en.json
│ └── de.json
├── public/
├── src/proxy.ts # Next.js proxy (renamed from middleware in v16)
├── next.config.ts
├── package.json
└── tsconfig.json
Environment Variables
| Variable | Description | Required |
|---|---|---|
NEXTAUTH_URL | The base URL of the app | Yes |
NEXTAUTH_SECRET | Secret for signing tokens | Yes |
API_URL | Rust API URL | Yes |
NEXT_PUBLIC_API_URL | Public API URL | Yes |
Development
cd platform/policies
# Install dependencies
pnpm install
# Run development server
pnpm dev
# Build for production
pnpm build
# Start production server
pnpm start
# Run linting
pnpm lint
URLs:
- Production:
https://policies.elcto.com - Development:
http://localhost:3004
Cookie Consent Integration
The Policies app integrates with the @elcto/cookies-consent library to provide GDPR-compliant cookie consent:
import { CookieBanner, useCookieConsent } from '@elcto/cookies-consent';
function App() {
const { consent, updateConsent } = useCookieConsent();
return (
<>
<CookieBanner
onAcceptAll={() => updateConsent({ analytics: true, marketing: true })}
onRejectAll={() => updateConsent({ analytics: false, marketing: false })}
/>
{/* App content */}
</>
);
}
API Health Monitoring
The Policies app includes real-time API health monitoring using the shared ApiHealthBanner component from @elcto/ui:
Integration
// src/components/ApiHealthBanner.tsx
import {
ApiHealthBanner as BaseApiHealthBanner,
useApiHealth as baseUseApiHealth,
useShowApiHealthBanner,
type ApiHealthBannerLabels,
} from "@elcto/ui/components";
import { useTranslations } from "next-intl";
export function useApiHealth(baseInterval = 30000, maxInterval = 600000) {
return baseUseApiHealth({
baseInterval,
maxInterval,
apiUrl: process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000",
});
}
export function ApiHealthBanner({ apiHealth, show, fixedTop, onRefresh }) {
const t = useTranslations("apiHealth");
const labels: ApiHealthBannerLabels = {
unreachable: t("unreachable"),
serviceIssues: t("serviceIssues"),
database: t("database"),
redis: t("redis"),
websocket: t("websocket"),
checking: t("checking"),
refreshNow: t("refreshNow"),
};
return (
<BaseApiHealthBanner
apiHealth={apiHealth}
show={show}
labels={labels}
fixedTop={fixedTop}
onRefresh={onRefresh}
/>
);
}
Usage in PoliciesLayout
The ApiHealthBanner is integrated into the main PoliciesLayout component:
// src/components/PoliciesLayout.tsx
import { ApiHealthBanner, useApiHealth, useShowApiHealthBanner } from "@/components/ApiHealthBanner";
export function PoliciesLayout({ children }) {
const { state: apiHealth, refresh: refreshApiHealth } = useApiHealth();
const showApiHealthBanner = useShowApiHealthBanner(apiHealth);
return (
<>
<Header />
<Navigation />
<ApiHealthBanner
apiHealth={apiHealth}
show={showApiHealthBanner}
fixedTop="7.5rem"
onRefresh={refreshApiHealth}
/>
<main className={showApiHealthBanner ? "pt-[10rem]" : "pt-[7.5rem]"}>
{children}
</main>
</>
);
}
Features
- Exponential Backoff: Health checks use exponential backoff when failures occur to avoid overwhelming the server
- Real-time Status: Shows API connectivity, database, Redis, and WebSocket status
- Manual Refresh: Users can manually trigger a health check
- i18n Support: All messages are translated via
next-intl - Fixed Positioning: Banner appears below the header and navigation with proper offset
Required Translations
Add the following to your messages/{locale}.json files:
{
"apiHealth": {
"unreachable": "Unable to connect to the API server. Some features may be unavailable.",
"serviceIssues": "Service issues:",
"database": "Database",
"redis": "Redis",
"websocket": "WebSocket",
"checking": "Checking...",
"refreshNow": "Click to refresh now"
}
}
Next Steps
- Backend - Backend documentation
- ID - Identity service documentation
- Cookie Consent Library - Cookie consent components