Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8417c72
feat: add teacher onboarding MVP updates
CarlyAThomas Apr 10, 2026
d081915
docs: update TODO with join link review section and ZZZ notes status
CarlyAThomas Apr 10, 2026
eb5f9cb
test: update classInviteTable snapshot after GraphQL/StudentInvitesPa…
CarlyAThomas Apr 10, 2026
d91d4dd
feat: teacher onboarding MVP (remove student-only components)
CarlyAThomas May 12, 2026
6b85ae6
feat: add teacher invite email, feature flag, acceptance flow, and tests
CarlyAThomas May 12, 2026
2ce56d9
feat: add teacher invite implementation files (feature flag, email, a…
CarlyAThomas May 12, 2026
bb1cf13
chore: remove test files with external dependencies
CarlyAThomas May 12, 2026
391e149
docs: update TODO to note manual integration testing
CarlyAThomas May 12, 2026
7ccaf64
chore: remove onboarding notes docs from teacher MVP branch
CarlyAThomas May 12, 2026
b612767
chore: ignore and untrack development/production env files
CarlyAThomas May 12, 2026
c277ad1
docs: add tracked env templates for development and production
CarlyAThomas May 12, 2026
7d5ef35
fix: remove nested anchors in Link components and refactor email util…
CarlyAThomas May 12, 2026
9ac4f49
feat: polish teacher invite flow and styling
CarlyAThomas May 18, 2026
6cbab30
fix: quote Accept Invitation in onboarding email text
CarlyAThomas Jun 5, 2026
867b52d
fix: remove unrelated StudentInvitation model, squash to single migra…
CarlyAThomas Sep 2, 2026
4987938
fix: don't hardcode Auth0 in teacher invite sign-in
CarlyAThomas Sep 2, 2026
a80a4c4
test: cover teacher invitation status transitions and email matching
CarlyAThomas Sep 3, 2026
96fd310
test: cover access control on /classes for non-teacher accounts
CarlyAThomas Sep 3, 2026
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
2 changes: 0 additions & 2 deletions .env.development

This file was deleted.

13 changes: 13 additions & 0 deletions .env.development.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
GITHUB_OAUTH_PROVIDER_ENABLED = "true"
DANGEROUS_ACCOUNT_LINKING_ENABLED = "true"
TEACHER_INVITES_ENABLED = "true"

# Teacher invitation email delivery for local testing
# Replace these with your actual SMTP provider credentials
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
SMTP_FROM="freeCodeCamp Classroom <no-reply@classroom.local>"
CLASSROOM_APP_BASE_URL=http://localhost:3001
2 changes: 0 additions & 2 deletions .env.production

This file was deleted.

13 changes: 13 additions & 0 deletions .env.production.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
GITHUB_OAUTH_PROVIDER_ENABLED = "false"
DANGEROUS_ACCOUNT_LINKING_ENABLED = "false"
TEACHER_INVITES_ENABLED = "true"

# Teacher invitation email delivery for production
# Replace these with your production SMTP provider credentials
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key
SMTP_FROM="freeCodeCamp Classroom <no-reply@classroom.freecodecamp.org>"
CLASSROOM_APP_BASE_URL=https://classroom.freecodecamp.org
49 changes: 49 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,52 @@ GITHUB_SECRET=
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
AUTH0_ISSUER=https://example-tenant.auth0.com

# Teacher invitation email delivery (REQUIRED for teacher invites to work)
#
# For local development, you can use a service like Gmail (with an app password) or Mailtrap for testing.
# If you are using Gmail, to set up Gmail Credentials:
# 1. Enable 2-Step Verification on your Google account.
# 2. Go to myaccount.google.com/apppasswords
# 3. Create a new app password by writing in a writing in a new app name (use "FCC Classroom") and select Create.
# 4. Google generates a 16-character password. Copy that password (not your Gmail password)
# and use it as the SMTP_PASS in your .env.development file. For example:
# 5. Copy that password (not your Gmail password)
# 6. Update .env.development:
# SMTP_USER=your-email@gmail.com
# SMTP_PASS=xxxx xxxx xxxx xxxx # (the 16-char app password Google generated)

# For production, you should use a reliable SMTP provider like SendGrid, AWS SES, or similar.

# Teacher invite rollout flag
# true = enable admin teacher invite UI/API and acceptance flow
# false = disable teacher invite endpoints and hide admin teacher invite panel
TEACHER_INVITES_ENABLED=true

# LOCAL DEVELOPMENT (.env.development):
# - Use your personal/test email provider (Gmail, Mailtrap, etc.)
# - Set CLASSROOM_APP_BASE_URL to your local URL (http://localhost:3001)
# - Example for Gmail:
# SMTP_HOST=smtp.gmail.com
# SMTP_PORT=587
# SMTP_SECURE=false
# SMTP_USER=your-email@gmail.com
# SMTP_PASS=your-app-password (not your Gmail password)
#
# PRODUCTION (.env.production):
# - Use your production SMTP provider (SendGrid, AWS SES, etc.)
# - Set CLASSROOM_APP_BASE_URL to your live URL (https://classroom.freecodecamp.org)
# - Example for SendGrid:
# SMTP_HOST=smtp.sendgrid.net
# SMTP_PORT=587
# SMTP_SECURE=false
# SMTP_USER=apikey
# SMTP_PASS=your-sendgrid-api-key
#
CLASSROOM_APP_BASE_URL=http://localhost:3001
SMTP_HOST=
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=
SMTP_PASS=
SMTP_FROM="freeCodeCamp Classroom <no-reply@classroom.local>"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ yarn-error.log*

# local env files
.env.local
.env.development
.env.development.local
.env.test.local
.env.production
.env.production.local
.env

Expand Down
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,79 @@ In production environments with separate domains (e.g., `classroom.freecodecamp.
- No port conflicts occur because domains are different
- The port changes in this repository are primarily for local development

### Teacher Invitation Email Setup

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation is great, but I'm concerned the README.md is getting too long. Can you create a subpage for this documentation and link it from the README?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a separate issue & PR for this! Issue #593 and PR #605


Teacher invitations now send a secure acceptance link by email. Configure these variables in your `.env` file:

| Variable | Description | Example |
| ------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `CLASSROOM_APP_BASE_URL` | Public URL used to build invitation links. Falls back to `NEXTAUTH_URL` when omitted. | `http://localhost:3001` |
| `SMTP_HOST` | SMTP server hostname | `smtp.sendgrid.net` |
| `SMTP_PORT` | SMTP server port | `587` |
| `SMTP_SECURE` | SMTP TLS mode (`true` for implicit TLS, commonly port 465) | `false` |
| `SMTP_USER` | SMTP username (if required by provider) | `apikey` |
| `SMTP_PASS` | SMTP password/API key (if required by provider) | `your-secret` |
| `SMTP_FROM` | Sender identity for invite emails | `freeCodeCamp Classroom <no-reply@classroom.local>` |
| `TEACHER_INVITES_ENABLED` | Rollout flag for teacher invitation flow (admin panel + APIs + accept endpoint) | `true` |

**Local Development Setup:**

Use `.env.development.example` as a template and create your own local `.env.development`.

In `.env.development`, configure SMTP for testing with your personal email provider:

If you are setting up your local development with Gmail, you will need to create an App Password for SMTP authentication.

1. Go to <https://myaccount.google.com/apppasswords>
2. Type in the name of the Application (FCC Classroom) and select create.
3. Google generates a 16-character password
4. Copy that password (not your Gmail password)
5. Update `.env.development` with the generated App Password:

```
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
```

Do not change the spacing in the generated App Password. It should be entered as a single string with spaces in the `.env` file.
For example, if your generated App Password is `abcd efgh ijkl mnop`, enter it in `.env` as `abcd efgh ijkl mnop` (including the spaces).

## Testing Notes for Teacher Invitation Flow

- Use two email accounts when testing the flow:
- one admin account
- one teacher account
- The admin account is the one that must be configured with the SMTP app password. Please see the README.md for Local Development Setup of Teacher Invitation Email Setup.
- Open the teacher account in an incognito browser so there is no sign-in conflict when accepting the invite email.

**Production Setup:**

Use `.env.production.example` as a template and create your own local `.env.production`.

In `.env.production`, configure SMTP for your production email service:

```
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key
```

**Acceptance Flow:**

1. Admin creates or resends a teacher invite from the admin dashboard.
2. Classroom sends a secure invitation email with a link in the form `/teacher/invite/<token>`.
3. Invited teacher receives the email and clicks the link.
4. Teacher signs in with the invited email and accepts the invite.
5. The pending invitation is marked as accepted and the teacher role is activated.

### Teacher Role Assignment

Manual role assignment is no longer required for teacher onboarding when invites are enabled.
Teachers are promoted to the `TEACHER` role when they accept a valid invitation using the invited email account.

---

### Join us in our [Discord Chat](https://discord.gg/qcynkd4Edx) here.
Expand Down
Loading