You must write all code for this assignment yourself; AI may be used only to explain concepts, suggest debugging strategies, or help you understand errors—not to generate solution code.
Use of AI on This Assignment (Read Carefully)
For this lab, you must write the code yourself.
This assignment is designed to assess your ability to:
- design a database-backed web application,
- implement authentication and authorization,
- connect frontend and backend logic, and
- debug real systems.
If AI writes the code for you, you are skipping the learning goal.
That said, AI is allowed in a limited, specific way.
✅ Allowed uses of AI (encouraged)
You may use AI as a tutor, not as a coder. Examples:
- Conceptual explanations
- “Explain how cookie-based sessions work in Express.”
- “What is bcrypt doing when hashing a password?”
- “Why do we store sessions server-side instead of in the browser?”
- Understanding existing code
- “Explain what this middleware function is doing line by line.”
- “Why does this SQL query fail when
ONLY_FULL_GROUP_BYis enabled?”
- Debugging help
- “I’m getting
ERR_HTTP_HEADERS_SENT. What does that usually mean?” - “Why might my React component re-render infinitely?”
- “This MariaDB foreign key constraint is failing—what are common causes?”
- “I’m getting
- Design advice
- “What tables do I need to support threads and posts?”
- “What fields should be indexed for this query?”
- “What API routes make sense for a threaded messageboard?”
- Small, isolated syntax questions
- “How do I read a cookie in Express?”
- “What does
credentials: 'include'do in fetch?”
These uses help you think, not copy.
❌ Not allowed uses of AI
You may not use AI to generate substantial parts of your solution. Examples:
- ❌ “Write the Express routes for login and registration.”
- ❌ “Generate the React components for the thread list and thread view.”
- ❌ “Create the SQL schema for users, sessions, threads, and posts.”
- ❌ “Write the authentication middleware.”
- ❌ Copy-pasting AI-generated code and making small edits.
If your submission looks like it was produced by an AI system, you will be asked to explain it. If you cannot, it will be treated as unauthorized assistance.
A good rule of thumb
Ask yourself:
“Could I explain every line of this code, out loud, on a whiteboard?”
If the answer is no, you should not submit it.
What we will do if something looks off
- We may ask you to:
- explain a function,
- modify a piece of your code in real time,
- or answer questions about design decisions you made.
This is not a “gotcha.”
It’s how we distinguish learning from outsourcing.
Bottom line
- You write the code.
- AI can help you understand, debug, and think.
- AI must not do the work for you.
Used correctly, AI will make you a better developer, not a faster copy-and-paste machine.
0) What you start with (given)
You already have a working v1 demo:
- Backend
GET /api/healthGET /api/posts(public)POST /api/posts(public)
- Frontend
- shows posts
- allows anyone to post
There is no users, no login, no authorization, no threads.
1) What you will build
After your changes:
Required features
- Register
- User provides: name, email, password
- No email verification. Trust the user input.
- Login / Logout
- Login creates a cookie-based session
- Logout clears the session
- Threads
- When logged in, the user sees a list of threads
- They can:
- click a thread to view it + its posts
- post a reply to that thread
- create a new thread
- Authorization
- Only logged-in users can:
- view the thread list
- view a thread
- create threads
- create posts (replies)
- Only logged-in users can:
Bonus (optional)
- Search
- Search threads by keyword (title + optional body/content)
- Or search posts within a thread
2) Environment assumptions (must follow)
Same as the starter:
- Linux username is your email prefix
jsmith@kenyon.edu→jsmith
- MariaDB database name is db_username
- Both linux and database password are Sxxxx, your student ID.
- Express server port is
41xxwherexxis last 2 digits of student ID
If you use the wrong DB name or port, your app won’t be graded correctly.
To create the VERSION 1 database table:
mysql -u username -p db_username < docs/schema_v1.sql
To log in look at you data base:
mysql -u username -p db_username
Set up server/.env
DB_HOST=localhost
DB_USER=username
DB_PASSWORD=Sxxxx (sudent id)
DB_NAME=db_username
PORT=4101
SESSION_SECRET=SomeRandomString
3) Database schema
Required tables
users
id(PK, auto increment)name(varchar)email(varchar, unique, required)password_hash(varchar, required)created_at
sessions
id(PK, random string OR auto id + separate token; your choice)user_id(FK → users.id)expires_at(datetime)created_at
threads
id(PK)title(varchar, required)created_by(FK → users.id)created_at- (recommended)
last_post_at(datetime) for sorting
posts
id(PK)thread_id(FK → threads.id)user_id(FK → users.id)content(text)created_at
Notes (required behavior)
- Deleting is not required.
- You do not need “edit post”.
- Passwords must not be stored in plain text.
4) Backend API contract (v2)
Create:
docs/API_CONTRACT_v2.md
Your backend must implement these routes exactly.
Auth
POST /api/auth/register
Creates a new user and starts a session.
Request JSON:
{ "name": "Alice", "email": "alice@kenyon.edu", "password": "secret123" }
Response JSON (201):
{ "user": { "id": 3, "name": "Alice", "email": "alice@kenyon.edu" } }
Errors:
- 400 if missing fields
- 409 if email already exists
Also:
- Must set a session cookie (HTTP-only)
POST /api/auth/login
Request JSON:
{ "email": "alice@kenyon.edu", "password": "secret123" }
Response JSON:
{ "user": { "id": 3, "name": "Alice", "email": "alice@kenyon.edu" } }
Errors:
- 400 missing fields
- 401 invalid credentials
Also:
- Must set a session cookie (HTTP-only)
POST /api/auth/logout
Response JSON:
{ "ok": true }
Also:
- Must clear/expire the cookie
GET /api/auth/me
Returns the logged-in user.
Response JSON (200):
{ "user": { "id": 3, "name": "Alice", "email": "alice@kenyon.edu" } }
If not logged in (200):
{ "user": null }
Threads (all require login)
GET /api/threads
Returns thread list, newest activity first.
Response JSON:
{
"threads": [
{
"id": 10,
"title": "Best pizza in Gambier?",
"created_at": "2026-02-04T14:12:00.000Z",
"last_post_at": "2026-02-04T15:30:00.000Z",
"created_by": { "id": 3, "name": "Alice" },
"post_count": 5
}
]
}
POST /api/threads
Creates a new thread and its first post.
Request JSON:
{ "title": "My new thread", "content": "First message in the thread" }
Response JSON (201):
{ "thread_id": 11 }
Errors:
- 400 missing fields
- 401 not logged in
GET /api/threads/:id
Returns one thread and its posts.
Response JSON:
{
"thread": {
"id": 10,
"title": "Best pizza in Gambier?",
"created_at": "2026-02-04T14:12:00.000Z",
"created_by": { "id": 3, "name": "Alice" }
},
"posts": [
{
"id": 77,
"content": "I like Village Inn.",
"created_at": "2026-02-04T15:30:00.000Z",
"author": { "id": 4, "name": "Bob" }
}
]
}
Errors:
- 401 not logged in
- 404 if thread doesn’t exist
POST /api/threads/:id/posts
Adds a reply to a thread.
Request JSON:
{ "content": "Here is my reply" }
Response JSON (201):
{ "post_id": 123 }
Errors:
- 400 missing content
- 401 not logged in
- 404 thread not found
Bonus: Search (optional)
GET /api/threads/search?q=keyword
Response JSON:
{ "threads": [ /* same shape as GET /api/threads */ ] }
5) Frontend behavior contract (v2)
Create:
docs/FRONTEND_CONTRACT_v2.md
Your React app must behave like this:
Pages / views
A) Logged-out
- Show Login form
- Show link/button to Register
- If user visits any “thread” route while logged out:
- redirect back to Login
B) Register page
- Fields: name, email, password
- On success:
- user becomes logged in
- redirect to Thread List
C) Login page
- Fields: email, password
- On success:
- redirect to Thread List
D) Thread List page (logged in)
- Shows list of thread titles
- Each thread shows at least:
- title
- creator name
- last_post_at
- post_count
- Has a “New Thread” button
E) Thread View page (logged in)
- Shows thread title + posts
- Has a reply textarea + submit button
- Posts show: author name + timestamp + content
F) New Thread page (logged in)
- Fields: title + content
- Submitting creates the thread + first post
- Redirect to the new thread view
G) Logout
- A logout button visible when logged in
- On logout:
- redirect to Login
Technical requirements
- Use cookie-based sessions (credentials included in fetch)
- On app start, call
/api/auth/meto determine whether logged in
6) Implementation requirements (grading-critical)
- Passwords
- Must be hashed (example: bcrypt)
- Sessions
- Must be server-side sessions stored in DB table
sessions - Cookie stores a session token/id (not the user id)
- Must be server-side sessions stored in DB table
- Authorization
- Every
/api/threads*route must require login
- Every
- No hidden “magic state”
- The backend is the source of truth
- The frontend should not “pretend” it is logged in without
/api/auth/me
7) Deliverables
You will submit:
- A link to your GitHub repo
- Your completed:
docs/schema_v2.sqldocs/API_CONTRACT_v2.mddocs/FRONTEND_CONTRACT_v2.md
- Your updated backend + frontend code
- A short
README.mdsection describing:- how to init DB for v1 (
make initdb-v1) - how to run server/client
- any bonus features implemented
- how to init DB for v1 (
8) Suggested checkpoints
- Create schema v1 and confirm
make initdb-v1 work - Implement register/login/logout/me (test with curl or Postman)
- Implement
GET /api/threadsand display in React - Implement thread view + replying
- Implement new thread creation
- Bonus: search
9) Grading rubric (example)
- 40% Backend correctness (routes + auth + sessions + DB)
- 40% Frontend behavior contract compliance
- 10% Code quality (structure, naming, error handling)
- 10% Documentation (v1 schema + contracts + README)
- Bonus up to +10% for search
