# RRA App — Architecture Notes

## Stack

- **Frontend**: Single HTML file (`index.html`) — vanilla JS, no build step
- **Supabase**: REST API via raw `fetch()` through Node.js proxy (NOT the JS SDK — see below)
- **Auth**: Supabase Auth (email/password), user metadata carries `full_name`, `instansi`
- **Database**: PostgreSQL via Supabase — all calls go through `/api` proxy on VPS
- **Deployment**: Static file on Caddy, served at subdomain

## App Structure

```
/home/ubuntu/kantor/rra-app/
  index.html   ← single file, ~50KB, vanilla JS SPA
  proxy.js     ← Node.js proxy bridging to Supabase (port 3000)
```

### Sections in the HTML:
1. **Auth view** — login / register cards
2. **Dashboard** — list of user's RRA documents
3. **Wizard view** — 5-step form:
   - Step 1: Identifikasi Bahaya (disease, agent, region)
   - Step 2: Jalur Penularan (risk pathways — dynamic add/remove)
   - Step 3: Likelihood + Consequence (5-dimension impact scoring + matrix)
   - Step 4: Mitigasi (pra-ekspor, transportasi, pasca-impor)
   - Step 5: Kesimpulan + recommendations
4. **Preview overlay** — renders filled RRA as formatted HTML
5. **View mode** — read-only view of saved document

### Key Implementation Pattern

```js
const API = '/api';
const SB_KEY = 'sb_publishable_LDervgNHZ88W3a6XrFETOA_gdDXvDPM';
const HEADERS = {'apikey': SB_KEY, 'Authorization': 'Bearer ' + SB_KEY, 'Content-Type': 'application/json'};

async function apiFetch(url, opts = {}) {
  const res = await fetch(API + url, {...opts, headers: {...HEADERS, ...(opts.headers||{})}});
  const text = await res.text();
  let json;
  try { json = JSON.parse(text); } catch { json = {error: text}; }
  if (!res.ok) throw json;
  return json;
}
```

### Tables used:
- `auth.users` — managed by Supabase Auth (no direct inserts)
- `profiles` — extra user fields (full_name, instansi), RLS: own row only
- `rra_documents` — all form data, JSONB for pathways/likelihood arrays, RLS: own rows only

### Data flow:
1. User registers → `handle_new_user()` trigger auto-creates `profiles` row
2. User fills wizard → `buildPayload()` collects all fields → `apiFetch('/rest/v1/rra_documents', {method:'POST', ...})`
3. Dashboard loads → `apiFetch('/rest/v1/rra_documents?select=*&order=created_at.desc')`

## Design Decisions

- **Single HTML file**: No build step, easy to deploy, easy to edit
- **Vanilla JS**: No React/Vue overhead, CDN-only dependencies
- **5-step wizard**: Matches RRA methodology (Identify → Pathway → Assess → Mitigate → Conclude)
- **JSONB for arrays**: `pathways` and `likelihood` stored as JSONB for flexible schema
- **Impact scoring**: 5 dimensions × 5 levels, highest dimension drives overall impact rating
- **Risk matrix**: 5×5 likelihood × consequence table, color-coded cells

## Common Issues

- **`Failed to fetch`** — browser cannot reach Supabase (network/ISP blocks `supabase.co`). Fix: use proxy architecture (see below).
- **Supabase JS SDK bypasses base URL** — `createClient('/', ...)` still calls `supabase.co` directly. There is NO SDK-level workaround. Must replace all SDK calls with raw `fetch()`.
- **Supabase URL unresolvable** — if `nslookup mcgqjqkofsvtqcrzelup.supabase.co 8.8.8.8` returns NXDOMAIN, the URL is wrong. Current verified: `https://mcgqjqkofsvtqcrzelup.supabase.co`.
- **Rate limit on signup** — Supabase limits signup emails. Use distinct test emails or wait 60s between attempts.
- **`email_not_confirmed`** on login — normal, user must click confirmation link in email. For testing, disable "Confirm email" in Supabase Auth settings.
- **VPS cannot reach Supabase** — normal; the proxy makes requests server-side, not the browser.

## Proxy Architecture — REQUIRED

The user's office network blocks `supabase.co` at DNS level. The Supabase JS SDK fails completely with `Failed to fetch`. Solution:

```
Browser → Caddy (HTTPS) → /api/* → Node proxy (port 3000) → Supabase (HTTPS)
```

**Why SDK doesn't work**: Even `createClient('/', anonKey)` — the SDK internally hardcodes all API paths using the project-specific hostname (`mcgqjqkofsvtqcrzelup.supabase.co`). The `baseUrl` parameter only affects URL formatting, not the actual host. There is NO SDK-level workaround for this.

See `references/proxy.js` for the complete working proxy code.
