Skip to content

Commit 0ae301c

Browse files
Merge pull request #3 from foundersandcoders/feature/ap-14-magic-link-authentication
feat: implement magic link authentication
2 parents 41d580f + f68e011 commit 0ae301c

28 files changed

+584
-44
lines changed

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ AIRTABLE_BASE_ID=
33
RESEND_API_KEY=
44
DISCORD_WEBHOOK_URL=
55
MAGIC_LINK_SECRET=
6-
SESSION_SECRET=
6+
SESSION_SECRET=
7+
AUTH_SECRET=

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ vite.config.ts.timestamp-*
2626
Assesment-criteria.md
2727
ksbs.md
2828

29+
plan.md

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,41 @@ Create a `.env.local` file with your Airtable credentials:
1414
AIRTABLE_API_KEY=your_api_key
1515
AIRTABLE_BASE_ID_LEARNERS=your_base_id
1616
AIRTABLE_BASE_ID_FEEDBACK=your_base_id
17+
AUTH_SECRET=your_auth_secret
1718
```
1819

20+
## Staff Access
21+
22+
To grant someone staff access (for managing events):
23+
24+
1. Add them as a **collaborator** in the Airtable workspace
25+
2. Add a record for them in the **Staff - Apprentice Pulse** table (`tblJjn62ExE1LVjmx`), selecting their collaborator profile in the Staff Name field
26+
27+
Staff members can then log in using their collaborator email address.
28+
1929
## Development
2030

2131
```sh
2232
npm run dev
2333
```
2434

35+
## Testing Authentication (Development)
36+
37+
Since magic links are logged to the console (not emailed) during development, follow these steps to test login:
38+
39+
1. **Start the dev server** - `npm run dev`
40+
2. **Call the login endpoint** - Use Postman or curl:
41+
```sh
42+
curl -X POST http://localhost:5173/api/auth/login \
43+
-H "Content-Type: application/json" \
44+
-d '{"email": "[email protected]"}'
45+
```
46+
3. **Copy the token** - Check the server terminal for the magic link URL containing the token
47+
4. **Visit verify in your browser** - Navigate to `http://localhost:5173/api/auth/verify?token=YOUR_TOKEN`
48+
5. **You're logged in** - The session cookie is set and you'll be redirected to `/`
49+
50+
**Important:** The verify step must be done in the browser (not Postman) because the session cookie needs to be set in the browser where you're viewing the app.
51+
2552
## Scripts
2653

2754
| Command | Description |

docs/planning/sprint02.png

80.3 KB
Loading

docs/report.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@
22
I created the boiler plate code, basic CI and deployment at the very beggining off the project (AP-3, AP-2, AP-8).
33
The idea is to have as soon as possible a "Hello world". In this context that would be a deployed sveltkit app that can read and write a value on Airtable.
44

5-
# Testing from the very beginning
5+
# Testing Strategy
66

7-
I created a test script (`scripts/test-airtable.ts`) to verify read and write access to Airtable before building any features. This script uses dotenv to load credentials from `.env.local` and tests creating and reading records from a dedicated test table.
7+
We use Vitest for automated testing with a co-location pattern: test files (`.spec.ts`) live next to the source files they test. This makes tests easy to find and encourages test coverage.
88

9-
The project uses Vitest with Playwright for browser-based component testing, with Playwright browsers installed automatically via a postinstall hook. At the moment test is boilerplate, so we are not really testing any real functionality
9+
**Structure:**
10+
- `src/lib/**/*.spec.ts` - Unit tests for library code
11+
- `src/routes/**/*.spec.ts` - Component tests for pages
12+
13+
**Manual integration scripts** live in `scripts/` and are used for verifying real API connectivity during development:
14+
- `scripts/check-airtable-connection.ts` - Verify Airtable read/write access
15+
- `scripts/check-cohort-apprentices.ts` - Test cohort lookup functionality
16+
- `scripts/fetch-schema.ts` - Fetch and document Airtable schema
17+
18+
This separation keeps automated tests (fast, mocked, run in CI) distinct from manual integration checks (slow, real API, run during development). [P6 - 30%] [P7 - 30%]
1019

1120

1221
# Importing Airtable schema
@@ -70,5 +79,29 @@ During Sprint 02, I identified that certain tasks required permissions I did not
7079

7180
This approach improved visibility into the project status and helped me prioritise effectively, focusing on tasks within my control while maintaining a clear follow-up list for delegated items. [P1 - 50%] [P2 - 40%] [K2, K6]
7281

82+
# Authentication
83+
We use jsonwebtoken library to authenticate learners and staff. This allows us to:
84+
* Generate the magic link token
85+
* Verify the token
86+
87+
**API testing:** We use Postman to manually test the authentication endpoints during development. This allows us to verify request/response payloads and debug the auth flow before building the frontend.
88+
89+
## Role-based Access Control
90+
91+
The `findUserByEmail` function implements role-based authentication by checking two Airtable tables:
92+
93+
1. **Staff table** - Returns `type: 'staff'` for admin access
94+
2. **Apprentices table** - Returns `type: 'student'` for learner access
7395

96+
A technical challenge arose with the Staff table: the email is stored in a `singleCollaborator` field (an Airtable collaborator object with `{ id, email, name }`). Unlike regular text fields, collaborator fields cannot be filtered using Airtable's `filterByFormula`. The solution was to fetch all staff records and iterate through them in code, comparing emails case-insensitively:
97+
98+
```typescript
99+
for (const record of staffRecords) {
100+
const collaborator = record.get(STAFF_FIELDS.COLLABORATOR);
101+
if (collaborator?.email?.toLowerCase() === email.toLowerCase()) {
102+
return { type: 'staff' };
103+
}
104+
}
105+
```
74106

107+
This approach ensures staff members can authenticate regardless of how their email is capitalised in Airtable. [K2 - 40%] [S5 - 30%] [D2 - 20%]

docs/schema.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,19 @@ Intervention and support request tracking.
170170

171171
---
172172

173+
## Staff - Apprentice Pulse
174+
175+
**Table ID:** `tblJjn62ExE1LVjmx`
176+
177+
Staff members for authentication. Uses Airtable collaborators for email lookup.
178+
179+
| Field | ID | Type | Purpose |
180+
|-------|-----|------|---------|
181+
| Id | `fldbTKP32s3Soev91` | autoNumber | Record ID |
182+
| Staff Name | `fldHEHhQInmSdipn8` | singleCollaborator | Collaborator with id, email, name |
183+
184+
---
185+
173186
## Cohorts
174187

175188
**Table ID:** `tbllAnSw8VPYFAa1a`

0 commit comments

Comments
 (0)