Schema (W0): - Add garments, garment_wears, outfits tables with Drizzle migrations - Drizzle migrations 0001 (garments/wears) and 0002 (outfits) auto-apply on deploy - RLS policies in drizzle/manual/06-wardrobe-rls.sql (apply via superuser in prod) API (W1–W9): - POST /api/garments/upload — direct upload to R2 garments/ prefix with sharp thumbnail - POST /api/garments/tag — vision tagging via LiteLLM, defensive parse, category validated - GET/POST /api/garments — list with composable filters, create - GET/PATCH/DELETE /api/garments/[id] — detail, edit, delete - POST /api/garments/[id]/wear — log worn date - GET /api/garments/outgrowth — pure SQL, explicit size ordering (no lexicographic sort) - GET /api/garments/packing — active garments grouped by category - GET /api/garments/outfit — Open-Meteo weather + deterministic outfit pairing, no LLM - GET/POST /api/garments/outfits + DELETE [id] — saved outfits Pages: - /wardrobe — grid with status/category/size/season filters + outgrowth nudge - /wardrobe/add — 3-step capture→vision→form, size required, batch-friendly - /wardrobe/[id] — detail/edit/status lifecycle + wear history - /wardrobe/packing — packing checklist by category - /wardrobe/outfit — weather-aware suggestions with shown basis - /wardrobe/saved-outfits — view/delete saved combinations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
43 lines
1.3 KiB
TypeScript
43 lines
1.3 KiB
TypeScript
// Gurugram coordinates (product is explicitly Gurugram-targeted)
|
||
const LAT = 28.4595;
|
||
const LON = 77.0266;
|
||
|
||
export interface WeatherSnapshot {
|
||
tempC: number;
|
||
description: string;
|
||
season: "summer" | "monsoon" | "winter";
|
||
}
|
||
|
||
// Maps temperature band to Gurugram season label.
|
||
// < 15°C → winter
|
||
// 15–28°C → monsoon (shoulder / rain season)
|
||
// > 28°C → summer
|
||
function tempToSeason(tempC: number): "summer" | "monsoon" | "winter" {
|
||
if (tempC < 15) return "winter";
|
||
if (tempC <= 28) return "monsoon";
|
||
return "summer";
|
||
}
|
||
|
||
export async function getGurgaonWeather(): Promise<WeatherSnapshot> {
|
||
try {
|
||
const url = `https://api.open-meteo.com/v1/forecast?latitude=${LAT}&longitude=${LON}¤t_weather=true`;
|
||
const res = await fetch(url, { next: { revalidate: 1800 } }); // cache 30 min
|
||
if (!res.ok) throw new Error(`weather API ${res.status}`);
|
||
const data = await res.json();
|
||
const tempC: number = data.current_weather?.temperature ?? 30;
|
||
const season = tempToSeason(tempC);
|
||
const descriptions: Record<string, string> = {
|
||
summer: "hot",
|
||
monsoon: "warm",
|
||
winter: "cool",
|
||
};
|
||
return {
|
||
tempC,
|
||
description: descriptions[season],
|
||
season,
|
||
};
|
||
} catch {
|
||
// Fallback to summer (Gurugram default)
|
||
return { tempC: 35, description: "hot", season: "summer" };
|
||
}
|
||
}
|