Senior backend/tooling engineering skill for the EdMeCa Academy platform. Use when: writing or debugging Node.js scripts, configuring Vite/Netlify, working with Supabase (schema, RLS, auth, storage), managing Drizzle ORM migrations, operating the Smartsheet CLI, setting up environment variables, adding Netlify Functions, configuring Resend email, or reviewing build/deploy configuration. Triggers on: "script", "Node.js", "build", "Vite", "Netlify", "deploy", "Supabase", "database", "schema", "migration", "Drizzle", "API", "Smartsheet", "environment", "env", "serverless", "function", "email", "Resend", "CI", "backend", "auth", "OAuth", "RLS".
Node.js ESM scripts · Vite 7 · Netlify (static + Functions) · Supabase (Auth + Postgres + Storage) · Drizzle ORM · Express server · Resend email · Smartsheet REST API · Environment variable management
Root
├── vite.config.ts ← Build config (root: "client", out: "client/dist")
├── netlify.toml ← Deploy config, redirects, security headers, env per context
├── shared/
│ └── schema.ts ← Drizzle ORM schema (shared between client types + server)
├── server/ ← Express server (if used for SSR or API proxying)
├── api/
│ └── analyze-financials.ts ← Serverless-style API handler
├── scripts/
│ ├── smartsheet-cli.js ← Smartsheet REST API CRUD
│ ├── security-audit.mjs ← Security report generator
│ └── setup.js ← Dev environment bootstrap
├── netlify/functions/ ← Netlify serverless functions (ESM .mjs format)
├── supabase/ ← Supabase local config + migrations
└── deliverables/ ← Project documentation HTML
All scripts use — always use /, never .
"type": "module")importexportrequire()// Required boilerplate for __dirname in ESM
import { fileURLToPath } from 'url';
import path from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
process.exit(1) on fatal errors; log a human-readable message first.| Variable | Purpose | Required by |
|---|---|---|
VITE_SUPABASE_URL | Supabase project URL | Client (all pages) |
VITE_SUPABASE_ANON_KEY | Supabase anon key | Client (all pages) |
VITE_ENABLE_LOGIN | Login button gate | Client header |
SESSION_SECRET | Express session secret | Server |
RESEND_API_KEY | Transactional email | Server / Netlify Functions |
SMARTSHEET_API_TOKEN | Smartsheet REST auth | scripts/smartsheet-cli.js |
SMARTSHEET_SHEET_ID | Target Smartsheet sheet | scripts/smartsheet-cli.js |
Rules:
VITE_* prefix exposes vars to the client bundle — never put secrets here.VITE_ vars are server/function only..env.local is gitignored and holds real values locally.netlify.toml or Netlify dashboard.Login gate pattern (only acceptable way to check):
const isLoginEnabled = import.meta.env.VITE_ENABLE_LOGIN === "true";
smtp.resend.com:465, sender [email protected])gen-lang-client-0996272869 (BUG-003: consent screen name pending — see copilot-instructions)http://localhost:5173/**, https://edmeca.co.za/**, https://staging--edmecaacademy.netlify.app/**useAuth() checks are UX only.publiclogos — contains logo.png for email templates.shared/schema.tssupabase/ folder or Drizzle KitKey settings in vite.config.ts:
root: "client" — Vite treats client/ as project root@ alias → client/src/outDir → client/distenvDir → project root (so .env at root is loaded, not client/.env)port: 5173, host: trueWhen modifying vite.config.ts:
envDir at project root — env files live there.root without also updating netlify.toml's publish path.npm run build (not just npm run dev) before shipping.netlify.toml)| Branch | Context | Login | Deploy |
|---|---|---|---|
main | production | VITE_ENABLE_LOGIN=false | Auto |
staging | staging | VITE_ENABLE_LOGIN=true | Auto |
development | branch-deploy | VITE_ENABLE_LOGIN=true | Auto |
git checkout staging ; git merge main --no-edit ; git push origin staging
git checkout development ; git merge main --no-edit ; git push origin development
git checkout main
X-Frame-Options: DENYX-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-originnetlify/functions/<name>.mjs (ESM)Access-Control-Allow-Origin to known origins (edmeca.co.za, staging URL) — never *scripts/smartsheet-cli.js)| Sheet | ID |
|---|---|
| SDLC Tasks | 1413139749883780 |
| Test Cases | 3745437451243396 |
| Bug Tracker | 789091202322308 |
| Column | ID |
|---|---|
| STATUS | 5778398742531972 |
| % Complete | 3526598928846724 |
node scripts/smartsheet-cli.js sheet # list rows
node scripts/smartsheet-cli.js complete <taskId> # mark 100% Complete
node scripts/smartsheet-cli.js status <taskId> "<val>" # set status string
node scripts/smartsheet-cli.js sync # show recent git commits
git add <files>git commit -m "type(scope): description [X.Y]" (hook auto-updates task X.Y)git push origin mainsmartsheet/EDMECA_Academy_SDLC_Tasks.csvedmeca.co.za — verified[email protected]