Hub Overview¶
The CyberEco Hub is the central web application of the CyberEco ecosystem. It provides identity management, privacy controls, ecosystem app navigation, and a unified dashboard for all CyberEco users.
Technology Stack¶
| Layer | Technology |
|---|---|
| Framework | Astro 5 with SSR via @astrojs/node |
| UI Islands | React 18 with client:load hydration |
| Styling | CSS Modules (.module.css) + CSS custom properties (theme.css) |
| Auth | Firebase Authentication (client-side) + httpOnly cookie (server-side) |
| i18n | EN + ES with server createT() and client LanguageProvider |
| Build | Vite (via Astro) |
No Tailwind
The Hub uses CSS Modules and CSS custom properties exclusively. There is no Tailwind CSS dependency.
Architecture¶
The Hub follows Astro's islands architecture: each page is a server-rendered .astro shell that hydrates one or more React components (islands) on the client.
.astro page (SSR shell)
|
+-- imports React island with client:load
|
+-- wrapped in <HubProviders>
|
+-- HubAuthContext (Firebase auth state)
+-- ThemeProvider (light/dark mode)
+-- LanguageProvider (EN/ES locale)
Prerendered vs SSR¶
| Route | Rendering | Reason |
|---|---|---|
/ (landing) |
Prerendered (export const prerender = true) |
Static marketing content |
/coming-soon |
Prerendered | Static placeholder |
| All other routes | SSR | Require auth checks, dynamic data, security headers |
The middleware skips prerendered routes to avoid request.headers warnings at build time.
Source File Inventory¶
The Hub contains 122+ source files across several layers:
| Layer | Count | Description |
|---|---|---|
| Pages | 17 .astro |
Landing, coming-soon, 3 auth pages, 12 protected pages |
| Islands | 15 .tsx + CSS |
SignIn, SignUp, ResetPassword, Dashboard, Apps, MyData, Profile, Privacy, Settings, Billing, Security (4), AuditLogs |
| API Routes | 8 .ts |
Auth (login, set-cookie, generate-token, refresh), Export, Privacy (settings, consent), CSP report |
| Components | 20 .tsx |
ui/ (10 reusable), dashboard/ (3), hub/ (7 layout/nav) |
| Providers | 4 | HubAuthContext, ThemeProvider, LanguageProvider, HubProviders |
| i18n | 7 files | EN + ES translations (common, hub, auth) + server createT() |
| Middleware | 1 | Auth gating, security headers, CORS, CSRF, locale detection |
| CSS | 4 global + 15 modules | global.css, theme.css, landing.css, auth.css + per-component modules |
Key Patterns¶
Islands Pattern¶
Each protected page follows a consistent structure:
// src/islands/DashboardIsland.tsx
import { HubProviders } from '@/providers/HubProviders';
import { DashboardPage } from './DashboardPage';
// Inner component uses hooks (useAuth, useTheme, useLanguage)
function DashboardPage() {
const { user } = useAuth();
// ... render dashboard content
}
// Outer default export wraps in providers
export default function DashboardIsland() {
return (
<HubProviders>
<DashboardPage />
</HubProviders>
);
}
Hook Separation
useAuth and useHubAuth hooks live in providers/useAuth.ts, separate from the HubAuthContext.tsx component. This avoids Vite Fast Refresh mixed-export warnings.
Providers¶
The <HubProviders> wrapper composes all required context providers for islands:
export function HubProviders({ children }: { children: React.ReactNode }) {
return (
<HubAuthProvider>
<ThemeProvider>
<LanguageProvider>
{children}
</LanguageProvider>
</ThemeProvider>
</HubAuthProvider>
);
}
| Provider | Context | Purpose |
|---|---|---|
HubAuthProvider |
HubAuthContext |
Firebase auth state, user object, loading state |
ThemeProvider |
ThemeContext |
Light/dark mode toggle, persisted to localStorage |
LanguageProvider |
LanguageContext |
EN/ES locale, persisted to cybereco-language cookie |
Internationalization (i18n)¶
The Hub supports English and Spanish through two mechanisms:
Server-side (.astro templates):
import { createT } from '@/i18n';
const t = createT(Astro.locals.locale);
// t('hub.dashboard.title') -> "Dashboard" or "Panel de Control"
Client-side (React islands):
import { useLanguage } from '@/providers/LanguageProvider';
const { t, locale, setLocale } = useLanguage();
// t('hub.dashboard.title') -> "Dashboard" or "Panel de Control"
Both read from the same JSON translation files in src/i18n/locales/:
Directory Structure¶
apps/hub/src/
components/
ui/ # 10 reusable UI components (Button, Card, Input, etc.)
dashboard/ # 3 dashboard-specific components
hub/ # 7 layout/navigation components (Header, Sidebar, Footer, etc.)
i18n/
locales/ # EN + ES translation JSON files
index.ts # createT() server utility
islands/ # 15 React islands (one per protected page)
layouts/
BaseLayout.astro
lib/
firebase-init.ts # Lazy Firebase initialization
utils.ts # Shared utilities
pages/
api/ # 8 API route handlers
auth/ # 3 auth page shells
*.astro # 12 protected page shells + landing + coming-soon
providers/
HubAuthContext.tsx
HubProviders.tsx
ThemeProvider.tsx
LanguageProvider.tsx
useAuth.ts # Hook exports (separate from component)
middleware.ts # Single middleware file
Environment Variables¶
The Hub requires Firebase configuration via environment variables. Copy .env.example to .env:
PUBLIC_HUB_URL=http://localhost:4321
PUBLIC_FIREBASE_API_KEY=...
PUBLIC_FIREBASE_AUTH_DOMAIN=...
PUBLIC_FIREBASE_PROJECT_ID=...
PUBLIC_FIREBASE_STORAGE_BUCKET=...
PUBLIC_FIREBASE_MESSAGING_SENDER_ID=...
PUBLIC_FIREBASE_APP_ID=...
JWT_SECRET=... # Server-only, used for token signing
SSO_TOKEN_SECRET=... # Server-only, used for cross-app SSO tokens
Astro Convention
Variables prefixed with PUBLIC_ are exposed to the client bundle. Access them via import.meta.env.PUBLIC_*. Server-only variables (no prefix) are only available in API routes and middleware.
Related Documentation¶
- Auth Flow -- How authentication works end-to-end
- Middleware -- Security headers, CSRF, locale detection
- API Reference -- Full OpenAPI specification for all endpoints