Authentication, Git Workflow and Tests

3.Staff Badges, a Logbook and a Stock Check

A

In this chapter

Anna makes the waitlist safe and solid: organiser logins with hashed passwords and sessions, permission checks, a proper Git workflow even when working alone, and unit and integration tests that run automatically — reviewing Acts 15, 17 and 22 in a real project.

16–18 min

The Problem in Real Life

2:30 PM. Liam wanders over and, as a joke, sends DELETE /events/1/waitlist/2 from his laptop. It works. Someone's place in the queue disappears. He looks guilty; Anna laughs. "Point taken. Logins next."

John adds a note on his clipboard and says only: "Remember Act 22. And Act 17. Hack Day projects still get attacked and still break."

J

Working alone is no excuse to skip the safety nets.

John

"It's Just a Hack Day Project" vs. Building It Like Real Software

Anyone can do anything

Without logins and permission checks, any visitor can delete anyone's place in line.

One big folder of changes

Without commits and branches, one bad change can break everything with no way back.

Does it still work?

Every new feature can quietly break an old one, unless tests check it automatically.

Adding Authentication, a Git Workflow and Tests

The shop analogy, continued: the shop now needs staff badges (only staff go behind the counter), a logbook of every change to the stock (so mistakes can be undone), and a daily stock check that confirms everything is where it should be. In software: authentication and authorization, Git, and tests.

  • Authentication for organisers (Act 22): organisers sign up with email and password; passwords are stored only as bcrypt hashes. After login, the server creates a session and sends an HttpOnly, Secure, SameSite cookie. Fans don't need accounts — they join with just an email, which keeps joining easy.
  • Authorization — who may do what (Act 22): a small middleware requireOrganiser checks the session. Then each organiser endpoint checks ownership: you can only see or edit the waitlist of an event you created — otherwise 404 (Act 25's pattern). Liam's joke now returns 401.
  • Basic protections: rate-limit the join and login endpoints (bots, Act 22), validate every input, never log passwords or full emails in plain text, and keep the session secret in an environment variable (Act 16).
  • Git workflow, even alone (Act 15): git init in the first minute, a .gitignore for node_modules and .env (Act 16) before the first commit, small commits with clear messages (Act 25's Conventional Commits), and a branch per feature (feature/auth) merged into main only when it works. When she breaks something at 4 PM, git diff and git restore (Act 15) get her back in seconds.
  • Unit tests (Act 17): test small pieces alone: email validation, position calculation. Fast and precise.
  • Integration tests (Act 17): test the real API against a test database: join returns 201; joining twice returns 409; an organiser can't see another organiser's list; a removed fan's position disappears and everyone moves up. The supertest library sends real HTTP requests to the app without starting a server.
  • Run tests on every push (Act 19): a small GitHub Actions workflow runs npm ci, the linter and the tests on every push and pull request — with a PostgreSQL service container for the integration tests. Even working alone, her main branch can only receive green code.
Table — Integration tests for the waitlist
TestExpected
Fan joins with a valid email201 Created
Same email joins again409 Conflict
Invalid email400 Bad Request
Position after someone ahead is removedMoves up by one
Delete an entry without logging in401 Unauthorized
Organiser B reads organiser A's list404 Not Found
Table — Anna's first Git history
CommitWhat it did
chore: initial project with .gitignorenode_modules and .env ignored from the start
feat: create eventsMigration + POST /events
feat: join waitlist and get positionCore feature
feat(auth): organiser signup and loginbcrypt + sessions
test: integration tests for waitlist14 tests
fix: positions update after removalBug found by a test
Ownership check for organiser endpoints
async function requireEventOwner(req, res, next) {
if (!req.session.organiserId) {
return res.status(401).json({ error: { code: "login_required" } });
}
const { rows } = await db.query(
"SELECT id FROM events WHERE id = $1 AND organiser_id = $2",
[req.params.id, req.session.organiserId]
);
if (!rows.length) return res.status(404).json({ error: { code: "event_not_found" } });
next();
}
app.get("/events/:id/waitlist", requireEventOwner, listWaitlist);
app.delete("/events/:id/waitlist/:entryId", requireEventOwner, removeEntry);
An integration test (Vitest + supertest)
it("does not let one organiser read another organiser's waitlist", async () => {
const eventId = await createEventAs("organiser-a@test.example");
const agentB = await loggedInAgent("organiser-b@test.example");
const res = await agentB.get(`/events/${eventId}/waitlist`);
expect(res.status).toBe(404);
});

By 6 PM on day one: organisers can sign up and log in; only they can manage their own events; fans join with an email; 14 tests pass locally and in CI; and the Git history reads like a story: feat: create events, feat: join waitlist, feat(auth): organiser signup and login, test: integration tests for waitlist, fix: positions update after removal. Liam tries his joke again: 401 Unauthorized. He gives a thumbs up.

Key Takeaway

Build a hack project like real software: organisers authenticate with bcrypt-hashed passwords and secure session cookies; every organiser action checks ownership on the server; rate limits and validation protect public endpoints. Use Git from the first minute — .gitignore before the first commit, small clear commits, a branch per feature. Write unit tests for small pieces and integration tests against a test database, and run them in CI on every push.

Why This Matters

Interviewers who look at your portfolio projects check exactly these things: are passwords hashed, are permissions checked on the server, is there a real Git history, and are there tests that run in CI? A small project that does all four says far more about you than a big one that does none.

Day one ends with a solid app — on Anna's laptop. Day two's goal: put it on the internet, at a real address, with a padlock in the browser.

Next