use std::path::Path;
#[derive(Debug, Clone, Copy)]
pub struct TechCard {
pub tag: &'static str,
pub priority: &'static str, pub text: &'static str,
}
pub const TECH_CARDS: &[TechCard] = &[
TechCard {
tag: "react",
priority: "strong",
text: "useEffect with an empty deps array runs once at mount. If it subscribes, sets a timer, opens a connection, or otherwise allocates, it MUST return a cleanup function to avoid leaks on unmount.",
},
TechCard {
tag: "react",
priority: "constraint",
text: "Never call setState inside the render body. Always inside event handlers, effects, or callbacks. Calling during render causes infinite re-render loops.",
},
TechCard {
tag: "rust",
priority: "strong",
text: "For distributable binaries, prefer rustls over native-tls/openssl. Avoids requiring a system OpenSSL at runtime; cross-compilation is simpler.",
},
TechCard {
tag: "rust",
priority: "strong",
text: "Binaries can use Box<dyn Error> or anyhow::Error freely. Libraries should expose typed errors (thiserror) so downstream code can match cases.",
},
TechCard {
tag: "supabase",
priority: "constraint",
text: "RLS policies must be tested with the anon role explicitly. service_role bypasses RLS entirely and gives misleading 'works for me' results during dev.",
},
TechCard {
tag: "supabase",
priority: "constraint",
text: "Never put service_role keys in client-side code or env vars exposed to the browser. They bypass all RLS and grant full DB access.",
},
];
pub fn detect_tech(project_dir: &Path) -> Vec<String> {
let mut tags = Vec::new();
if project_dir.join("Cargo.toml").exists() {
tags.push("rust".into());
}
if project_dir.join("package.json").exists() {
if let Ok(s) = std::fs::read_to_string(project_dir.join("package.json")) {
if s.contains("\"react\"") || s.contains("\"next\"") {
tags.push("react".into());
}
}
}
if project_dir.join("supabase").is_dir()
|| project_dir.join("supabase").join("config.toml").exists()
{
tags.push("supabase".into());
}
tags
}
pub fn cards_for(tags: &[String]) -> Vec<TechCard> {
TECH_CARDS
.iter()
.filter(|c| tags.iter().any(|t| t == c.tag))
.copied()
.collect()
}