## AI Master Prompt: Energy Compass MVP ##
**1. PROJECT OVERVIEW:**
The "Energy Compass" application aims to provide real-time, transparent, and actionable insights into Great Britain's electricity generation and consumption. It addresses the challenge of understanding the complex energy landscape, particularly the significant shift towards renewables. The core value proposition is to empower individuals and businesses with data to make informed decisions about their energy usage, promoting efficiency and sustainability. Users will be able to monitor live data feeds from the National Grid, visualize trends in renewable energy adoption, track price and emission fluctuations, and receive personalized recommendations to optimize their energy consumption patterns for cost savings and environmental benefit.
**2. TECH STACK:**
- **Framework:** Next.js (App Router)
- **Language:** TypeScript
- **Styling:** Tailwind CSS
- **ORM:** Drizzle ORM (PostgreSQL compatible)
- **Database:** PostgreSQL (using Vercel Postgres or similar)
- **Authentication:** NextAuth.js (Credentials Provider for email/password and OAuth for Google/GitHub)
- **UI Components:** shadcn/ui (for accessible, re-usable components like Buttons, Cards, Tables, Charts, Modals, Forms)
- **Charting Library:** Recharts (for interactive and responsive charts)
- **State Management:** Zustand or Jotai (for global state management, especially for user preferences and real-time data updates)
- **Form Handling:** React Hook Form + Zod (for validation)
- **API Layer:** Server Actions and Route Handlers (Next.js App Router features)
- **Deployment:** Vercel (recommended for seamless Next.js integration)
- **Optional:** `date-fns` for date manipulation, `clsx` for conditional class names.
**3. DATABASE SCHEMA (PostgreSQL with Drizzle ORM):**
```typescript
// schema.ts
import { pgTable, serial, timestamp, varchar, boolean, real, jsonb, integer, primaryKey, foreignKey }
from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';
// Users Table
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: varchar('name'),
email: varchar('email', { length: 255 }).notNull().unique(),
emailVerified: timestamp('emailVerified', { mode: 'date' }),
image: varchar('image'),
createdAt: timestamp('createdAt').default(sql`NOW()`),
updatedAt: timestamp('updatedAt').default(sql`NOW()`),
});
// Accounts Table (for NextAuth.js OAuth)
export const accounts = pgTable('accounts', {
userId: integer('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
type: varchar('type', { length: 255 }).$type<AdapterAccount['type']>().notNull(),
provider: varchar('provider', { length: 255 }).notNull(),
providerAccountId: varchar('providerAccountId', { length: 255 }).notNull(),
refresh_token: text('refresh_token'),
access_token: text('access_token'),
expires_at: integer('expires_at'),
token_type: varchar('token_type', { length: 255 }),
scope: varchar('scope', { length: 255 }),
id_token: text('id_token'),
session_state: varchar('session_state', { length: 255 }),
}, (t) => ({
pk: primaryKey(t.provider, t.providerAccountId),
}));
// Sessions Table (for NextAuth.js)
export const sessions = pgTable('sessions', {
sessionToken: varchar('sessionToken', { length: 255 }).notNull().primaryKey(),
userId: integer('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
expires: timestamp('expires', { mode: 'date' }).notNull(),
});
// Verification Tokens Table (for NextAuth.js)
export const verificationTokens = pgTable('verificationTokens', {
identifier: varchar('identifier', { length: 255 }).notNull(),
token: varchar('token', { length: 255 }).notNull(),
expires: timestamp('expires', { mode: 'date' }).notNull(),
}, (
t
) => ({
pk: primaryKey(t.identifier, t.token),
}));
// User Preferences Table
export const userPreferences = pgTable('userPreferences', {
userId: integer('userId').primaryKey().references(() => users.id, { onDelete: 'cascade' }),
notificationsEnabled: boolean('notificationsEnabled').default(true),
preferredUnits: varchar('preferredUnits', { length: 50 }).default('metric'), // e.g., 'metric', 'imperial'
lowPriceThreshold: real('lowPriceThreshold'), // e.g., a specific price per MWh
highRenewableThreshold: real('highRenewableThreshold'), // e.g., percentage
updatedAt: timestamp('updatedAt').default(sql`NOW()`),
});
// Real-time Energy Data Table (Simplified - In a real MVP, this would likely be fetched from an external API and potentially cached or aggregated, not stored long-term per minute)
// For MVP, we can simulate this with a single row or fetch directly. If caching is needed:
export const currentEnergyData = pgTable('currentEnergyData', {
id: serial('id').primaryKey(),
timestamp: timestamp('timestamp', { withTimezone: true, mode: 'date' }).notNull(),
totalDemand: real('totalDemand'), // GW
totalGeneration: real('totalGeneration'), // GW
generationPercentage: real('generationPercentage'), // %
fossilFuelGeneration: real('fossilFuelGeneration'), // GW
renewableGeneration: real('renewableGeneration'), // GW
otherGeneration: real('otherGeneration'), // GW
pricePerMwh: real('pricePerMwh'), // £
emissionsPerKwh: real('emissionsPerKwh'), // g
interconnectorFlow: real('interconnectorFlow'), // GW
storageLevel: real('storageLevel'), // GW (or %)
// Add specific sources if needed for deeper analysis
solarGeneration: real('solarGeneration'), // GW
windGeneration: real('windGeneration'), // GW
hydroGeneration: real('hydroGeneration'), // GW
nuclearGeneration: real('nuclearGeneration'), // GW
biomassGeneration: real('biomassGeneration'), // GW
});
// User-Defined Thresholds/Alerts Table (Optional for MVP, could be part of preferences)
// export const userAlerts = pgTable('userAlerts', { ... });
// Relations (Implicit with foreign keys for now)
```
**4. CORE FEATURES & USER FLOW:**
* **Authentication Flow:**
1. User lands on the homepage.
2. Sees options to "Sign Up" or "Log In".
3. **Sign Up:** User provides email and password (or uses Google/GitHub OAuth).
4. **Log In:** User provides credentials or uses OAuth.
5. Upon successful authentication, `NextAuth.js` creates a session.
6. User is redirected to the Dashboard.
7. **Protected Routes:** Dashboard, Settings pages are protected. Unauthenticated users are redirected to the login page.
8. **Session Management:** Session is maintained via cookies. User can log out.
9. **Edge Case:** Handling invalid credentials, OAuth errors, email verification (if implemented).
* **Dashboard - Real-time Energy Overview:**
1. **Fetch Data:** On page load, fetch latest energy data (simulated or from a real API source). Use Server Actions or Route Handlers for backend fetching/caching.
2. **Display Key Metrics:** Show `Total Demand`, `Total Generation`, `Renewable Percentage`, `Price/MWh`, `Emissions/kWh` in prominent cards (using shadcn/ui Card component).
3. **Visualize Generation Mix:** Display a Donut or Pie chart (Recharts) showing the breakdown of generation by source (Fossil Fuels, Renewables, Other).
4. **Real-time Updates:** Implement polling or WebSockets (if feasible for MVP) to update key metrics without full page reloads (e.g., every 60 seconds).
5. **User Preferences:** Load user-specific thresholds for alerts/visual cues if available.
6. **Edge Case:** Handle empty states (no data available), API errors during fetching.
* **Detailed Analysis Page:**
1. **Fetch Historical/Detailed Data:** Fetch hourly or daily data for the past 24 hours, week, or year.
2. **Display Time-Series Charts:** Use Recharts to display:
* Price per MWh over time.
* Emissions per kWh over time.
* Demand vs. Generation over time.
* Renewable Generation vs. Fossil Fuel Generation over time.
3. **Data Filtering/Selection:** Allow users to select time ranges (Past Day, Past Week, Past Year).
4. **Interactivity:** Charts should be interactive (tooltips on hover).
5. **Edge Case:** Handle scenarios with missing data points in historical logs.
* **Optimization Recommendations (MVP Lite):**
1. **Fetch User Consumption (Simulated/Manual Input):** For MVP, assume a user has manually entered their average daily consumption or peak hours. In a future version, this could be integrated with smart meters or utility APIs.
2. **Compare with Grid Data:** Compare user's typical consumption times/levels with the real-time grid data (price, renewable percentage).
3. **Display Recommendations:** Based on user preferences (e.g., `lowPriceThreshold`, `highRenewableThreshold`):
* "Consider running high-consumption appliances between 2 AM - 5 AM when prices are typically lower." (Conditional styling/message)
* "Renewable energy generation is currently at 90%. This might be a good time to charge electric vehicles." (Conditional styling/message)
4. **UI:** Display recommendations clearly on the Dashboard or a dedicated section using alert-like components.
5. **Edge Case:** If user data is unavailable or preferences are not set, display a prompt to configure them.
* **Settings Page:**
1. **Profile Section:** Allow users to view/edit their name and email (email change requires verification).
2. **Notification Preferences:** Toggle notifications on/off.
3. **Threshold Settings:** Input fields (using shadcn/ui form components, validated with Zod) for `lowPriceThreshold` and `highRenewableThreshold`.
4. **OAuth Management:** Display connected OAuth accounts (Google, GitHub) and provide an option to disconnect.
5. **Log Out Button:** Clear session and redirect to the homepage.
6. **Save Changes:** Use Server Actions to update `userPreferences` table.
7. **Edge Case:** Input validation errors, confirmation prompts before saving.
**5. API & DATA FETCHING:**
* **Authentication API:** Handled by NextAuth.js (`/api/auth/[...nextauth]`).
* **Energy Data API (Internal/Proxy):**
* `GET /api/energy/current`: Fetches the latest aggregated energy data. Returns JSON payload like: `{ timestamp: string, totalDemand: number, ... }`.
* `GET /api/energy/historical?range=day`: Fetches historical data for the specified range. Returns JSON payload like: `{ data: Array<{ timestamp: string, pricePerMwh: number, ... }>, range: string }`.
* *Implementation Note:* For the MVP, this API might fetch from a public API (like Elexon Portal API if accessible and suitable) and cache the results aggressively, or use mock data defined in `sampleData`. If using a real API, implement robust error handling and rate limiting.
* **User Preferences API (Server Actions):**
* `updateUserPreferences(prefs)`: Server Action triggered from the Settings page to update the `userPreferences` table.
* **Data Fetching in Components:**
* **Client Components:** Use `fetch` with cache options or libraries like SWR/React Query for client-side data fetching and caching, especially for real-time updates.
* **Server Components:** Fetch data directly within Server Components using Drizzle ORM or Server Actions for initial page loads.
* **Data Flow:** Server Actions handle mutations and database writes. Route Handlers act as API endpoints. Client components fetch data from these endpoints or directly invoke Server Actions.
**6. COMPONENT BREAKDOWN (Next.js App Router):**
* **`app/layout.tsx`:** Root layout (includes `<html>`, `<body>`, global providers, Tailwind CSS setup, possibly main navigation).
* **`app/page.tsx`:** Landing page (Public, links to auth).
* **`app/auth/signin/page.tsx`:** Sign-in page (using NextAuth.js components or custom implementation).
* **`app/(app)/dashboard/page.tsx`:** Main dashboard (Protected). Fetches and displays real-time data cards and charts.
* `components/ui/Card.tsx`: For metric display.
* `components/charts/GenerationMixDonutChart.tsx`: Recharts component.
* `components/dashboard/RealTimeMetrics.tsx`: Component responsible for fetching and displaying live stats.
* **`app/(app)/analysis/page.tsx`:** Detailed analysis page (Protected). Displays historical charts.
* `components/charts/TimeSeriesChart.tsx`: Reusable Recharts component for price, emissions, demand/generation.
* `components/analysis/DateRangeSelector.tsx`: For selecting time periods.
* **`app/(app)/settings/page.tsx`:** User settings page (Protected).
* `components/settings/ProfileForm.tsx`: User profile update form.
* `components/settings/NotificationForm.tsx`: Notification preferences.
* `components/settings/ThresholdForm.tsx`: Threshold input form (using shadcn/ui's `Form`, `Input`, `Label`).
* **`app/(app)/layout.tsx`:** Application layout (Protected, includes sidebar/header navigation).
* **`components/ui/`:** Shared shadcn/ui components (Button, Input, Card, Sheet, Modal, Table, etc.).
* **`components/nav/Navbar.tsx`:** Top navigation bar.
* **`components/nav/Sidebar.tsx`:** Sidebar navigation (for protected routes).
* **`components/auth/UserAvatar.tsx`:** Displays user avatar/name in navbar.
* **`components/layout/Footer.tsx`:** Footer component.
* **`lib/auth.ts`:** NextAuth.js configuration.
* **`lib/db.ts`:** Drizzle ORM database connection setup.
* **`lib/validators.ts`:** Zod validation schemas.
* **`actions/`:** Server Actions directory (e.g., `preferencesActions.ts`).
* **`hooks/`:** Custom React hooks (e.g., `useRealtimeData.ts`).
* **`types/`:** TypeScript interfaces and types.
**7. UI/UX DESIGN & VISUAL IDENTITY:**
* **Design Style:** Minimalist Clean with a touch of futuristic data visualization.
* **Color Palette:**
* Primary (Dark Mode): `#0F172A` (Background), `#94A3B8` (Secondary Text), `#FFFFFF` (Primary Text), `#38BDF8` (Accent/Interactive)
* Primary (Light Mode): `#F8FAFC` (Background), `#475569` (Secondary Text), `#0F172A` (Primary Text), `#0EA5E9` (Accent/Interactive)
* Chart Colors: Use shades of green for renewables (`#22C55E`), blue for hydro/nuclear (`#3B82F6`), orange/red for fossil fuels (`#F97316`), grey for others (`#9CA3AF`).
* **Typography:** Tailwind CSS default font (Inter or similar sans-serif).
* Headings: Semibold/Bold, larger sizes.
* Body Text: Regular weight.
* **Section Layout:** Use cards for key metrics. Full-width sections for charts with padding. Clear visual hierarchy.
* **Responsive Rules:** Mobile-first approach. Sidebar collapses into a hamburger menu on smaller screens. Charts adapt to container size. Ensure readability on all devices.
* **Visual Elements:** Subtle gradients on interactive elements or chart axes. Clean icons (from shadcn/ui or Lucide Icons).
**8. SAMPLE/MOCK DATA:**
* **`currentEnergyData` (Example Row):**
```json
{
"timestamp": "2024-07-26T18:30:00Z",
"totalDemand": 34.6,
"totalGeneration": 29.2,
"generationPercentage": 84.5,
"fossilFuelGeneration": 5.75, // 19.7% of 29.2
"renewableGeneration": 13.65, // 46.9% of 29.2
"otherGeneration": 4.8,
"pricePerMwh": 137.47,
"emissionsPerKwh": 95.0,
"interconnectorFlow": 5.4,
"storageLevel": 2.1,
"solarGeneration": 0.21,
"windGeneration": 16.06,
"hydroGeneration": 0.58,
"nuclearGeneration": 4.46,
"biomassGeneration": 1.03
}
```
* **`userPreferences` (Example for User ID 1):**
```json
{
"userId": 1,
"notificationsEnabled": true,
"preferredUnits": "metric",
"lowPriceThreshold": 50.0,
"highRenewableThreshold": 85.0
}
```
* **Historical Data Snippet (for `analysis` page):**
```json
[
{ "timestamp": "2024-07-25T00:00:00Z", "pricePerMwh": 45.2, "emissionsPerKwh": 70.0, "renewableGeneration": 18.5 },
{ "timestamp": "2024-07-25T01:00:00Z", "pricePerMwh": 42.1, "emissionsPerKwh": 65.0, "renewableGeneration": 19.2 },
// ... more data points
{ "timestamp": "2024-07-26T18:00:00Z", "pricePerMwh": 135.0, "emissionsPerKwh": 93.0, "renewableGeneration": 14.0 }
]
```
* **Mock User Data:**
* User 1: John Doe (john.doe@example.com), Google OAuth connected.
* User 2: Jane Smith (jane.smith@example.com), Email/Password.
**9. TURKISH TRANSLATIONS (Key UI Elements):**
* **App Title:** Enerji Pusulası
* **Sign Up:** Kayıt Ol
* **Log In:** Giriş Yap
* **Dashboard:** Kontrol Paneli
* **Analysis:** Analiz
* **Settings:** Ayarlar
* **Logout:** Çıkış Yap
* **Real-time Data:** Gerçek Zamanlı Veriler
* **Current Price:** Anlık Fiyat
* **Emissions:** Emisyonlar
* **Demand:** Talep
* **Generation:** Üretim
* **Renewables:** Yenilenebilirler
* **Fossil Fuels:** Fosil Yakıtlar
* **Nuclear:** Nükleer
* **Hydro:** Hidroelektrik
* **Wind:** Rüzgar
* **Solar:** Güneş
* **Biomass:** Biyokütle
* **Interconnectors:** Enterkonnektörler
* **Storage:** Depolama
* **Past Day:** Dün
* **Past Week:** Geçen Hafta
* **Past Year:** Geçen Yıl
* **Your Consumption:** Tüketiminiz
* **Optimization Tips:** Optimizasyon İpuçları
* **Enable Notifications:** Bildirimleri Etkinleştir
* **Save Changes:** Değişiklikleri Kaydet
* **Profile:** Profil
* **Preferences:** Tercihler
* **Energy Source:** Enerji Kaynağı
* **Loading...:** Yükleniyor...
* **No data available:** Veri bulunamadı.
* **Error fetching data:** Veri alınamadı.
**10. ANIMATIONS:**
* **Page Transitions:** Subtle fade-in/slide-in animations for new page content using `AnimatePresence` from `framer-motion` or similar CSS transitions.
* **Button Hovers:** Slight scale-up or background color change on interactive elements.
* **Chart Loading:** Placeholder animations or skeleton loaders while charts are being fetched/rendered.
* **Real-time Metric Updates:** Subtle number interpolation or color flash to indicate a value has changed.
* **Component Mounts:** Gentle fade-in for cards and data points as they appear.
**11. EDGE CASES & VALIDATION:**
* **Authentication:** Handle expired sessions, invalid login attempts, OAuth callback errors, email not verified errors.
* **Data Fetching:** Gracefully handle API errors, network issues, and empty datasets from the source. Display user-friendly messages and fallback states (e.g., "Last updated: X minutes ago").
* **Form Validation:** Implement real-time validation on settings forms using Zod and React Hook Form. Provide clear error messages next to fields.
* **Empty States:** Design informative empty states for dashboard widgets or analysis charts when no data is available (e.g., "Historical data for this period is not yet available.").
* **Permissions:** Ensure only authenticated users can access protected routes and settings.
* **API Rate Limiting:** If using an external API, implement client-side or server-side rate limiting to avoid exceeding usage quotas.
* **Data Integrity:** Ensure data displayed is consistent (e.g., percentages add up logically, though the source might have nuances like exceeding 100% for exports).