# Supabase content service setup

The website is a static HTML site. Supabase supplies hosted authentication, a Postgres content store, row-level access policies, and a private image bucket; StormerHost continues to serve the HTML/CSS/JavaScript files. The browser uses only the Supabase project URL and its publishable (or legacy `anon`) key. Never put a service-role key, database password, or secret key in this site.

## 1. Create the Supabase project

1. Create a Supabase project and keep its database password in a password manager.
2. In **Project Settings → API**, copy the Project URL and publishable key (or legacy `anon` key).
3. In **SQL Editor**, run [`setup.sql`](./setup.sql).
4. In **Authentication → Providers → Email**, enable email/password sign-in and disable public sign-ups. The school administrator must be invited/created by a project owner; do not enable open registration for this dashboard.
   Verify that the project reports sign-ups disabled after saving. The dashboard only grants content access to users listed in `site_admins`, but disabling public sign-ups prevents uninvited accounts from being created.
5. In **Authentication → URL Configuration**, set the production Site URL to the StormerHost HTTPS domain and add the exact production `forgot-password.html` URL to the allowed redirect URLs. Add the matching localhost URL only when testing locally. Password recovery redirects back to this page to complete the reset.
   The reset request normally uses the current page URL. If production reset emails must always go to one fixed URL, set `passwordResetRedirectTo` in `js/supabase-config.js` to that exact HTTPS `forgot-password.html` URL and allow the same URL in Supabase. Do not set it to localhost for production.
6. After creating the administrator user in Supabase Auth, insert that account as a site admin in SQL Editor:

   ```sql
   insert into public.site_admins (user_id)
   select id from auth.users
   where lower(email) = lower('admin@your-school-domain.example')
   on conflict (user_id) do nothing;
   ```

   Repeat this only for trusted content editors. An authenticated account without a `site_admins` row cannot access drafts, upload images, or edit content.

If sign-in reports valid credentials but says the account is not an administrator, confirm the invited user is present in **Authentication → Users** and rerun the `site_admins` insert above using that user's exact email address. If password reset links expire or return to the wrong page, correct the allowed redirect URL in step 5 and request a fresh link.

## 2. Configure the static site

Edit [`../js/supabase-config.js`](../js/supabase-config.js) and set the two public values:

```js
window.ONIWAA_SUPABASE_CONFIG = {
  url: 'https://your-project-ref.supabase.co',
  anonKey: 'your-project-publishable-or-anon-key'
};
```

The URL and publishable/anon key are designed to be public. Security comes from Supabase Auth, row-level security, and storage policies—not from hiding this key. Do not use a service-role or secret key here.

Upload the `index` folder contents to the StormerHost document root, preserving the `js`, `css`, and `supabase` folders. Use the host's HTTPS site URL when configuring Supabase. Since this setup makes browser requests directly to Supabase, StormerHost does not need to run PHP or Node; if the host applies outbound/API restrictions, allow HTTPS requests to the Supabase project domain.

The browser integration uses the Supabase JavaScript SDK as an ES module from `esm.sh`. Serve the site over HTTPS (or localhost for development); opening the HTML files directly with `file://` does not support the required module loading.

## 3. Sign in and publish

Open `login.html`, sign in with the invited administrator account, and open `dashboard.html`. The dashboard redirects signed-out visitors to login and checks administrator membership on the server before showing draft management. Create an event/news item, gallery photo, or staff profile; use **Save draft** to keep it private or **Publish now** to show it on the public site. Draft records are only visible to site admins. The `oniwaa-media` bucket is private; public pages obtain short-lived signed image URLs only for published media.

## Notes

- Existing gallery photos, events and staff entries in the static website remain in place. New published records are loaded from Supabase by the public pages.
- Content changes are live in Supabase; the files on StormerHost are not rewritten by the dashboard.
- Supabase project availability, authentication and database policies must be configured before the live feature works. When the config is empty, the dashboard displays setup guidance instead of pretending that content was saved.
- Configure backups and account recovery for the Supabase project owner before relying on it for production content.
