# Melake Mihiret — Live Portfolio and Blog

Responsive portfolio for Melake Mihiret, built for static hosting such as Yegara. Blog and news posts are read from a Supabase database, so publishing from the admin panel updates the live site without re-uploading content files.

## Supabase setup (one time)

1. Create a Supabase project on the Free plan. Save the database password privately; the website does not need it.
2. In the project's dashboard, copy the **Project URL** and **publishable key** from **Connect** (or **Settings → API Keys**) into `supabase-config.js`. The publishable key is intended for browser apps. Never use a secret or service_role key in this folder.
3. Open **SQL Editor → New Query**, paste the contents of `schema.sql`, and click **Run**. This creates the posts table, enables row-level security, allows public visitors to read published articles, and restricts post changes to authorized admin accounts.
4. In **Authentication → Users**, create your email/password admin account. Copy its user ID. In the SQL Editor, run:

   ```sql
   insert into public.site_admins (user_id)
   values ('PASTE-YOUR-AUTH-USER-UUID-HERE');
   ```

5. Upload the site files to your hosting account. Keep `index.html`, `admin.html`, `post.html`, and the JavaScript/CSS files at the website root. SQL files are for the Supabase SQL Editor, not the public website.
6. Run `contact-messages.sql` in the SQL Editor after `schema.sql` to add the private contact inbox and its rate-limit table.
7. Visit `/admin.html`, sign in with the account above, and publish a post. The live site's Blog & news section will show it automatically.

The browser app uses only the Supabase publishable key. Database row-level security controls access; never put a secret/service_role key in the browser. The admin panel has no public sign-up option. Cover images can be added as HTTPS image URLs.

## Files

- `index.html`: portfolio homepage
- `admin.html`: authenticated post editor
- `post.html`: public article page
- `schema.sql`: one-time blog database schema and access policies
- `contact-messages.sql`: contact inbox schema, access policies, and server email rate limiting
- `supabase/functions/contact-notification/index.ts`: private email notification and visitor confirmation function
- `supabase/config.toml`: function deployment settings
- `supabase-config.js`: project URL and publishable key go here

## Contact form, inbox, and automatic email

The public form saves messages to `contact_messages`. After `contact-messages.sql` is run, the signed-in admin can review them at `/admin.html` → Contact inbox, mark them read, reply using their email app, or delete them. The public browser can submit a message but cannot read the inbox. Email notifications and the automatic visitor reply require the one-time setup below.

1. Create a Resend account and verify a sender domain you control. Add the DNS records Resend gives you in your domain's DNS settings. Until the domain is verified, Resend will not send from it.
2. In Supabase, open **Edge Functions → Deploy a new function → Via Editor**. Name the function `contact-notification`, replace the template with the contents of `supabase/functions/contact-notification/index.ts`, and deploy it. This endpoint accepts public contact submissions and includes a server-side limit of three notifications per IP every ten minutes; leave its public access enabled as set in `supabase/config.toml`.
3. In **Edge Functions → Secrets**, add:
   - `RESEND_API_KEY`: your Resend API key
   - `CONTACT_TO_EMAIL`: `melakemihiret2@gmail.com`
   - `CONTACT_FROM_EMAIL`: a sender on your verified domain, for example `Melake Mihiret <portfolio@your-verified-domain>`
   - `SITE_ORIGIN`: the exact website origin, such as `https://your-site.netlify.app` or `https://mebachatech.pro.et` (no trailing slash)
4. The Supabase project already provides `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` to Edge Functions. Do not add either value to the public website or send it in chat. `SITE_ORIGIN` must exactly match the scheme, host, and optional port visitors use. Supabase Functions can read project secrets from their environment; secret values belong in the Dashboard Secrets page only.
5. Send a test message from the live site. It should appear in the Admin → Contact inbox, send a notification to your inbox, and send an acknowledgment to the visitor. Email delivery is limited to three messages per source IP every ten minutes; only a one-way hash is stored for this limit.

If email setup is unfinished, messages still save to the admin inbox and the form tells the sender that email notifications are not active yet. They can use the direct email or Telegram links meanwhile.

The Blog & news section now supports search and category filters. No additional database setup is needed for that feature.