Work / coursework
Research Position Portal
Flask portal where faculty post research positions and students apply, with email-confirmed accounts and a Dockerised AWS deployment.
- Kind
- coursework
- Status
- complete
- Role
- team of 4: team liaison, top contributor
- Period
- Nov 2025 – Dec 2025
- Affiliation
- WPI CS3733 Software Engineering
Problem
Undergraduate research positions at a university are matched almost entirely through informal channels. A professor mentions an opening in a lecture, or a student emails around hoping to catch one. Faculty have no clean way to advertise what they need. Students have no way to see what exists or to present the coursework that would qualify them.
The portal gives both sides a structured surface: faculty post positions with concrete requirements, students maintain a profile of majors, courses taken, programming languages and interests. Applications carry references.
Data
The interesting part is the relational model, because the matching problem is
really a modelling problem. Users are polymorphic: Student and Faculty both
inherit a shared User. The qualification surface is normalised across
Major, Course, TakenCourse, ProgrammingLang and TopicOfInterest.
Position, Application and Reference carry the workflow itself.
- Store: SQLAlchemy models over SQLite, with Flask-Migrate handling schema migrations
- Scale: a course project, so the data is seeded rather than organic, with no real user volume behind it
Approach
Flask with blueprint separation (auth, student, faculty, main, errors)
keeps the two user roles isolated rather than tangled behind conditionals.
Authentication is session-based: Flask-Login holds the session. Passwords
are hashed with Werkzeug’s generate_password_hash rather than stored. Faculty
accounts additionally require email confirmation before they can post: a
signed, expiring token generated with itsdangerous and delivered by
Flask-Mail, redeemed at a /confirm/<token> route. The gate exists because a
faculty account is the one that can create positions, so it is the account
worth verifying.
Deployment is containerised with Docker and runs on AWS EC2. The image
self-signs a TLS certificate with OpenSSL at build time and starts by applying
migrations (flask db upgrade) before serving over HTTPS on port 3001. The
team’s AWS runbook also provisions an RDS PostgreSQL instance, though the
pinned dependencies ship no PostgreSQL driver. The container as built runs on
SQLite.
Process was Agile across four people over six weeks, with the team liaison role carrying communication with the course staff and the largest share of the implementation on the merged branch.
Experiments
What didn’t work
pytest is pinned and the suite is empty. requirements.txt carries
pytest==8.4.2 and there is a tests/ package, but it contains nothing except
an empty __init__.py: no tests at all. On a six-week course
project with a fixed demo date, testing was the thing that kept losing to
features. The dependency was added in anticipation of a suite that never
got written. Naming it here is more useful than quietly leaving the dependency
to imply coverage that does not exist.
Auth0 was specified and never built. The requirements document offers SSO through Auth0 as an alternative to email-and-password login. No Auth0 SDK, no OAuth flow and no token handling ever landed. What shipped is the Flask-Login and Werkzeug path described above. The spec was written optimistically at the start of the term and never revised once the scope became clear.
The PostgreSQL story is a runbook, not a build. The AWS guide walks through provisioning RDS PostgreSQL, but no driver was ever added to the image, so the deployed container ran the same SQLite file the laptops did. The gap went unnoticed because nothing in the demo needed the data to survive a redeploy.
The graded deployment is gone. The EC2 instance backing the demo no longer answers, which is the ordinary fate of a free-tier box after a term ends, but it does mean the only remaining evidence is the source.