Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ link's build current automatically.
- [Architecture](docs/ARCHITECTURE.md) — how the pieces fit, selection, reminders, security
- [Roadmap](docs/ROADMAP.md) — shipped phases and what's next
- [Backend](backend/README.md) — API endpoints, auth, running locally
- [Email templates](docs/EMAIL_TEMPLATES.md) — branded Supabase emails and installation
- [Deployment](mobile/DEPLOYMENT.md) — EAS builds, OTA updates, release runbook

## Contributing
Expand Down
6 changes: 6 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ backend/
│ │ └── users.py profile bootstrap (safety net for the DB trigger)
│ └── api/v1/ health, topics, daily
├── migrations/ # plain SQL, applied in filename order
├── email-templates/ # account email HTML installed manually in Supabase Auth
├── tests/ # 25 tests: token verification, selection, HTTP
├── Dockerfile # what Railway builds
└── .env.example # copy to .env — never commit the filled copy
Expand Down Expand Up @@ -106,6 +107,11 @@ confusion attacks, both of which are covered by tests.
`user_id` is taken from the verified token's `sub` claim and from nowhere else.
No endpoint accepts a user id as a parameter.

Supabase Auth sends signup, recovery, and enabled security notifications using
the project's configured sender. See [Email templates](../docs/EMAIL_TEMPLATES.md)
for the three branded HTML files and manual installation steps. An app deployment
does not publish these templates or change SMTP settings.

## Content generation

Gemini writes lessons. It does **not** choose subjects.
Expand Down
41 changes: 41 additions & 0 deletions backend/email-templates/confirm-signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Confirm your email — One Concept</title>
</head>
<body style="margin:0;padding:0;background-color:#F4F5FB;">
<!-- Subject: Confirm your email — One Concept -->
<div style="display:none;max-height:0;overflow:hidden;mso-hide:all;">One last step to finish setting up your account.</div>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" bgcolor="#F4F5FB" style="font-family:Arial,Helvetica,sans-serif;">
<tr><td align="center" style="padding:32px 16px;">
<!--[if mso]><table role="presentation" width="560" cellspacing="0" cellpadding="0" border="0"><tr><td><![endif]-->
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="max-width:560px;table-layout:fixed;">
<tr><td bgcolor="#171923" style="padding:24px;">
<p style="margin:0;color:#FFFFFF;font-size:26px;font-weight:bold;letter-spacing:-0.8px;line-height:1.2;">One Concept<span style="color:#A5B4FC;">.</span></p>
<p style="margin:6px 0 0;color:#C5CAD8;font-size:12px;line-height:1.5;">by <a href="https://github.com/Coding-Moves" target="_blank" rel="noopener noreferrer" style="color:#C5CAD8;text-decoration:underline;">Coding Moves</a></p>
</td></tr>
<tr><td style="padding:28px 24px;">
<h1 style="margin:0 0 20px;color:#171923;font-size:32px;font-weight:bold;letter-spacing:-1px;line-height:1.15;overflow-wrap:break-word;word-wrap:break-word;">Confirm your email.</h1>
<p style="margin:0 0 28px;color:#565D6D;font-size:16px;line-height:1.6;">Confirm this address to finish setting up your account.</p>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr><td align="center" bgcolor="#4F46E5" style="border-radius:6px;mso-padding-alt:14px 20px;">
<a href="{{ .ConfirmationURL }}" style="display:block;padding:14px 20px;border:1px solid #4F46E5;border-radius:6px;color:#FFFFFF;font-size:16px;font-weight:bold;line-height:1.5;text-decoration:none;">Confirm email</a>
</td></tr>
</table>
<p style="margin:20px 0 0;color:#565D6D;font-size:14px;line-height:1.6;">Then return to the app and sign in.</p>
</td></tr>
<tr><td bgcolor="#F9FAFC" style="padding:24px;border-top:1px solid #E9EBF4;">
<p style="margin:0 0 16px;color:#565D6D;font-size:13px;line-height:1.6;">If you didn’t sign up, you can ignore this email.</p>
<p style="margin:0 0 6px;color:#565D6D;font-size:12px;line-height:1.6;">Button not working? Copy this link into your browser:</p>
<p style="margin:0;font-size:12px;line-height:1.6;word-break:break-all;overflow-wrap:anywhere;">
<a href="{{ .ConfirmationURL }}" style="color:#4F46E5;text-decoration:underline;word-break:break-all;overflow-wrap:anywhere;">{{ .ConfirmationURL }}</a>
</p>
</td></tr>
</table>
<!--[if mso]></td></tr></table><![endif]-->
</td></tr>
</table>
</body>
</html>
34 changes: 34 additions & 0 deletions backend/email-templates/password-changed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Your password was changed — One Concept</title>
</head>
<body style="margin:0;padding:0;background-color:#F4F5FB;">
<!-- Subject: Your password was changed — One Concept -->
<div style="display:none;max-height:0;overflow:hidden;mso-hide:all;">A security update for your One Concept account.</div>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" bgcolor="#F4F5FB" style="font-family:Arial,Helvetica,sans-serif;">
<tr><td align="center" style="padding:32px 16px;">
<!--[if mso]><table role="presentation" width="560" cellspacing="0" cellpadding="0" border="0"><tr><td><![endif]-->
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="max-width:560px;table-layout:fixed;">
<tr><td bgcolor="#171923" style="padding:24px;">
<p style="margin:0;color:#FFFFFF;font-size:26px;font-weight:bold;letter-spacing:-0.8px;line-height:1.2;">One Concept<span style="color:#A5B4FC;">.</span></p>
<p style="margin:6px 0 0;color:#C5CAD8;font-size:12px;line-height:1.5;">by <a href="https://github.com/Coding-Moves" target="_blank" rel="noopener noreferrer" style="color:#C5CAD8;text-decoration:underline;">Coding Moves</a></p>
</td></tr>
<tr><td style="padding:28px 24px;">
<h1 style="margin:0 0 20px;color:#171923;font-size:28px;font-weight:bold;letter-spacing:-1px;line-height:1.15;overflow-wrap:break-word;word-wrap:break-word;"><span style="display:inline-block;max-width:100%;">Pass&shy;word</span> changed.</h1>
<p style="margin:0 0 16px;color:#565D6D;font-size:16px;line-height:1.6;">Your One Concept password was changed.</p>
<p style="margin:0;color:#565D6D;font-size:14px;line-height:1.6;">If you made this change, no further action is needed.</p>
</td></tr>
<tr><td bgcolor="#F9FAFC" style="padding:24px;border-top:1px solid #E9EBF4;">
<h2 style="margin:0 0 12px;color:#171923;font-size:16px;font-weight:bold;line-height:1.5;">Didn’t make this change?</h2>
<p style="margin:0 0 16px;color:#565D6D;font-size:14px;line-height:1.6;">Open One Concept and use <strong>Forgot password</strong> on the sign-in screen to reset your password.</p>
<p style="margin:0;color:#565D6D;font-size:14px;line-height:1.6;"><a href="mailto:contactmuawia@gmail.com?subject=One%20Concept%20account%20security" style="color:#4F46E5;text-decoration:underline;">Contact support</a> immediately.</p>
</td></tr>
</table>
<!--[if mso]></td></tr></table><![endif]-->
</td></tr>
</table>
</body>
</html>
41 changes: 41 additions & 0 deletions backend/email-templates/reset-password.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Reset your password — One Concept</title>
</head>
<body style="margin:0;padding:0;background-color:#F4F5FB;">
<!-- Subject: Reset your password — One Concept -->
<div style="display:none;max-height:0;overflow:hidden;mso-hide:all;">Choose a new password for your One Concept account.</div>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" bgcolor="#F4F5FB" style="font-family:Arial,Helvetica,sans-serif;">
<tr><td align="center" style="padding:32px 16px;">
<!--[if mso]><table role="presentation" width="560" cellspacing="0" cellpadding="0" border="0"><tr><td><![endif]-->
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" bgcolor="#FFFFFF" style="max-width:560px;table-layout:fixed;">
<tr><td bgcolor="#171923" style="padding:24px;">
<p style="margin:0;color:#FFFFFF;font-size:26px;font-weight:bold;letter-spacing:-0.8px;line-height:1.2;">One Concept<span style="color:#A5B4FC;">.</span></p>
<p style="margin:6px 0 0;color:#C5CAD8;font-size:12px;line-height:1.5;">by <a href="https://github.com/Coding-Moves" target="_blank" rel="noopener noreferrer" style="color:#C5CAD8;text-decoration:underline;">Coding Moves</a></p>
</td></tr>
<tr><td style="padding:28px 24px;">
<h1 style="margin:0 0 20px;color:#171923;font-size:32px;font-weight:bold;letter-spacing:-1px;line-height:1.15;overflow-wrap:break-word;word-wrap:break-word;">Reset your <span style="display:inline-block;max-width:100%;">pass&shy;word.</span></h1>
<p style="margin:0 0 28px;color:#565D6D;font-size:16px;line-height:1.6;">A password reset was requested for your account. Choose a new password below.</p>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr><td align="center" bgcolor="#4F46E5" style="border-radius:6px;mso-padding-alt:14px 20px;">
<a href="{{ .ConfirmationURL }}" style="display:block;padding:14px 20px;border:1px solid #4F46E5;border-radius:6px;color:#FFFFFF;font-size:16px;font-weight:bold;line-height:1.5;text-decoration:none;">Reset password</a>
</td></tr>
</table>
<p style="margin:20px 0 0;color:#565D6D;font-size:14px;line-height:1.6;">Once it’s saved, return to the app and sign in.</p>
</td></tr>
<tr><td bgcolor="#F9FAFC" style="padding:24px;border-top:1px solid #E9EBF4;">
<p style="margin:0 0 16px;color:#565D6D;font-size:13px;line-height:1.6;">If you didn’t request this, ignore this email. Your password won’t change.</p>
<p style="margin:0 0 6px;color:#565D6D;font-size:12px;line-height:1.6;">Button not working? Copy this link into your browser:</p>
<p style="margin:0;font-size:12px;line-height:1.6;word-break:break-all;overflow-wrap:anywhere;">
<a href="{{ .ConfirmationURL }}" style="color:#4F46E5;text-decoration:underline;word-break:break-all;overflow-wrap:anywhere;">{{ .ConfirmationURL }}</a>
</p>
</td></tr>
</table>
<!--[if mso]></td></tr></table><![endif]-->
</td></tr>
</table>
</body>
</html>
1 change: 1 addition & 0 deletions docs/CODEBASE_MAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ learned history, streaks, likes, saved concepts, and push reminders.
| Operations | `.github/workflows/`, `backend/railway.json`, `backend/Dockerfile`, `mobile/eas.json`, `mobile/app.config.js`. |
| Documentation | Root `README.md`, `RELEASING.md`, `CONTRIBUTING.md`, `docs/ARCHITECTURE.md`, `docs/ROADMAP.md`, and the backend/mobile guides. |
| Agent guidance | Root `AGENTS.md`; `mobile/AGENTS.md` adds Expo documentation requirements and `mobile/CLAUDE.md` references it. |
| Authentication email | `backend/email-templates/` contains branded signup, recovery, and password-changed HTML; `docs/EMAIL_TEMPLATES.md` covers manual Supabase installation and activation checks. Templates use the configured sender and are not installed by app deployment. |

## Mobile navigation and presentation

Expand Down
68 changes: 68 additions & 0 deletions docs/EMAIL_TEMPLATES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# One Concept email templates

These three templates customize emails sent by Supabase Auth. They work with
the project's configured sender; installing the HTML does not require Resend,
a purchased domain, or an app update. Provider setup remains separate in
[draft PR #187](https://github.com/Coding-Moves/one-concept/pull/187).

**Merging or releasing the app does not install these files in Supabase.**
Paste the templates into the dashboard to change future emails. The repository
stores their reviewed source; it does not synchronize production settings.

## Install

1. Open the correct Supabase project, then **Authentication → Emails → Templates**.
2. Open each template listed below and set its subject exactly as shown.
3. Replace the body with the entire raw HTML file, starting with `<!doctype html>`.
Copy the file's source, not its rendered browser preview, and save.
4. Under **Security → Password changed**, also enable the notification and save.

| Supabase template | Subject | HTML source |
| --- | --- | --- |
| Confirm sign up | `Confirm your email — One Concept` | [confirm-signup.html](../backend/email-templates/confirm-signup.html) |
| Reset password | `Reset your password — One Concept` | [reset-password.html](../backend/email-templates/reset-password.html) |
| Password changed (Security) | `Your password was changed — One Concept` | [password-changed.html](../backend/email-templates/password-changed.html) |

Keep every `{{ .ConfirmationURL }}` placeholder in signup and recovery. Supabase
fills in the appropriate verification URL; the button and copyable fallback
must both pass through that verification. Password changed reports a completed
change and intentionally has no token or reset-link placeholder. It directs
unrecognized changes to Forgot password in the app and the existing support email.

Preserve the project's existing working redirect configuration. Signup uses the
configured Site URL for `/confirmed`; recovery requests `/reset-password` on the
app's API base URL. The corresponding HTTPS destinations must be allowed in
Supabase's URL Configuration. Do not replace verification links with those
landing-page URLs. See [Supabase email templates](https://supabase.com/docs/guides/auth/auth-email-templates).

## Sending and activation

Template customization and sending capacity are separate. Supabase's default
sender is for testing: it currently sends only to project-team addresses and
allows two emails per hour. Other recipients require custom SMTP, which can be
the owner's existing Gmail setup once configured and tested. These templates
do not remove sender limits or establish delivery. See
[Supabase SMTP documentation](https://supabase.com/docs/guides/auth/auth-smtp)
(checked 2026-09-12).

Before announcing the new emails to users, test with accounts and inboxes you
control under the configured sender's limits:

- Confirm signup, follow the email's button, and successfully sign in to the app.
- Request Forgot password, set a new password through the recovery email, and
sign in with it. Verify the separate Password changed notification arrives.
- Check the design in a real inbox on phone and desktop, the full fallback links,
and the Coding Moves organization and support destinations. Use a second inbox
provider and a non-team recipient when custom SMTP is available.

Record the results before treating production activation as complete. Local
browser previews verify layout, not Gmail/Outlook rendering or live delivery.
No production settings or messages are changed by the template PR itself.

## Design

The dark masthead uses the owner's selected One Concept text branding and links
Coding Moves once to its GitHub organization. The app's current image assets are
Expo starter icons, so the emails do not use them as a logo. Inline styles,
presentation tables, system fonts, and text links need no external assets.
Subjects are separate dashboard fields; the HTML comments do not configure them.
43 changes: 43 additions & 0 deletions docs/WORK_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ claims as completed work.

## Current status

- Published the three branded Supabase templates in non-draft
[PR #188](https://github.com/Coding-Moves/one-concept/pull/188) into `develop`,
from `a6e81f1` on `codex/branded-auth-email-templates`. GitHub reports the PR
mergeable with no conflicts; no CI checks are configured for this PR.
- Resend delivery preparation remains in [draft PR #187](https://github.com/Coding-Moves/one-concept/pull/187).
Its duplicate template files are removed in a follow-up commit. Original
histories are intact. Template installation is independent of a domain purchase
or app release and still requires pasting HTML into Supabase.
- No SMTP settings, live templates, notifications, or production release were
changed. Real inbox rendering and delivery remain unverified.

- Implemented and validated [#151](https://github.com/Coding-Moves/one-concept/issues/151),
shared daily Gemini generation budget, on `codex/151-shared-generation-budget`
from refreshed `origin/develop` (`65eb21d`). Published
Expand All @@ -21,6 +32,38 @@ claims as completed work.
- PR #185 (#150) is merged. Preserve the owner's identity and the preference for
more focused commits in this and future PRs.

## Separate branded email templates — 2026-09-12

- Owner requested the three templates in a separate non-draft PR, allowing
branding to merge while domain/provider setup stays deferred. Rechecked
Supabase documentation: customizing templates does not remove the built-in
sender's team-only/two-emails-per-hour restrictions. Existing configured
Gmail SMTP can be used separately once authenticated and tested.
- Preserved nine original template commits from #187, in order, covering signup,
recovery, copy/spacing improvements, the dark text masthead, the Coding Moves
organization link, and the password-changed notification. Sources are byte for
byte identical to the previously validated versions. The owner selected text
branding; no custom app logo was available.
- Added `docs/EMAIL_TEMPLATES.md` with exact subjects, manual installation,
confirmation placeholders, the security toggle, existing redirect contract,
and activation checks. The guide does not require domain purchase or Resend.
- **Validation:** the unchanged HTML previously passed 60 Chromium scenarios:
48 for signup/recovery and 12 for password changed, across four widths and
normal/doubled/stripped styles, plus normal/long verification URLs. Those checks
covered links, fallback URLs, styled overflow, spacing, action sizes, and no
external resources; mobile/desktop/enlarged previews were inspected. For this
split, verified byte equality with `b0695ca`, inspected app redirect/support
source, checked local Markdown paths/anchors, and ran `git diff --check`.
Browser scenarios were not repeated for identical HTML. Backend/mobile and
live-email tests were not run for this HTML/documentation-only change.
- Commits: `245b7f6` records scope; `d88f432` through `50d065d` preserve the nine
template changes; `4ccba83` adds installation/navigation docs; this handoff is
`docs: record independent email template PR and validation`.
- **Handoff:** merge #188 independently of #187. Then install/test templates in
Supabase before announcing the changed emails. Merging/releasing the app does
not synchronize templates or enable security notifications. Delivery issues
#152/#171 stay open for the remaining operational work; no release PR opened.

## Shared generation budget (#151) — 2026-09-12

- Confirmed both gaps before implementation against the same generation source
Expand Down