Week 6 - Authentication and real-time updates¶
During this week you will add user separation to your application, implement real-time features to improve the user experience, and start measuring what your application does.
Development requirements¶
Below you will find new user stories to implement. As a soft-recommendation, if you have not already, then you should do all input validations in both frontend and backend.
Conflicting requirements
If user stories from different weeks conflict with each other, the newest week's user story takes precedence. Requirements may evolve as the project progresses, and later weeks may refine or supersede earlier specifications.
As a user, I want to create an account and log in so that I can identify myself and manage my own content.
- The application stack must have its own authentication system. You may implement authentication yourself in the code or set up an authentication/identity provider service.
- Users should be able to register with a username and password.
- The password should have reasonable requirements (length, symbol variation).
- Passwords must be stored securely using proper hashing algorithms (e.g., bcrypt, argon2). When implementing authentication yourself, be sure to use an appropriate hashing algorithm, when using an authentication service, make sure it's using secure hashing algorithms.
- Users should be able to log in with their credentials.
- Each post should display the username of the author instead of having an input field for the author.
As a user, I still want the option to post anonymously so that I can share thoughts without revealing my identity.
- Users must be logged in to create posts.
- Users should have the option to post anonymously (e.g., via a toggle/checkbox when creating a post).
- When posting anonymously, the post should display "anonymous" instead of the username.
- Anonymous posts are still associated with the user's account internally, allowing them to manage these posts when logged in.
As a user, I want to be able to change my password so that I can maintain the security of my account.
- Users must be able to change their password while logged in.
- The password change functionality should require the current password for verification.
- New passwords should follow the same security requirements as registration.
As a user, I want to be able to make my posts private after posting them so that I can control if my content is visible to others.
- Users should be able to change the privacy status of their own posts after they have been created.
- There should be a way to toggle a post between public and private (e.g., a button or switch on the post).
- Only the post author can change the privacy status of their post.
- Private posts should only be visible to the user who created them.
- Other users should not be able to see or access private posts.
- This applies to both regular posts and posts made anonymously.
- Users can make their anonymous posts private when logged in with the account that created them.
As a user, I want to see post changes immediately without refreshing the page so that I have a live view of them.
- When any user upvotes or downvotes a post, all other users viewing the page should see the updated vote count in near-real-time or real-time.
- When any user creates a new post, all other users viewing the page should see the new post appear in near-real-time or real-time.
- When any user toggles post privacy, all other users viewing the page should see that post disappear or appear in near-real-time or real-time.
- The application must use a bidirectional communication protocol (e.g., WebSocket) rather than simple polling.
- The real-time updates should work smoothly even when multiple users are interacting simultaneously.
- New posts should appear seamlessly without disrupting the user's current view.
As a visitor, I want to be able to view posts without creating an account so that I can browse content before deciding to register.
- The page should be viewable without authentication (anonymous browsing).
- Visitors who are not logged in can see all public posts.
- Visitors cannot interact with posts (no creating posts, voting, or making posts private) unless they are logged in.
- The interface should clearly indicate which actions require authentication.
As a user, I want my votes to be counted fairly so that each person can only vote once per post.
- Each user can upvote or downvote each post only once.
- If a user has already voted on a post, they should be able to change their vote (from upvote to downvote or vice versa) or remove their vote.
- Vote counts should accurately reflect the number of unique users who voted.
Operational requirements¶
Database for persistent storage¶
Your application must now store information (users, posts, votes) in a persistent database. This can be either:
- A relational database (RDBMS) e.g. PostgreSQL.
- A NoSQL database e.g. MongoDB.
The choice of database is yours.
Application metrics¶
From this week on, your application should tell you what it is doing. You will instrument your backend with OpenTelemetry and expose the results in the Prometheus text format, as shown in the lecture. Next week, these metrics will be sent to the course monitoring system, and you will add the metrics that matter most.
Complete
Instrument your backend using the OpenTelemetry SDK for your language:
- Expose your metrics at
/metricson a separate port from your application (we recommend9464), using the SDK's Prometheus exporter. - Create at least three metrics, one of each type:
- a counter, e.g. votes cast, or logins by result (
success/failure), - a gauge (an
UpDownCounterin OTel), e.g. currently open WebSocket connections, - a histogram, e.g. request duration.
- a counter, e.g. votes cast, or logins by result (
- Use bounded labels only: values from a small, known set (
direction="up",result="failure"). Never use usernames, user IDs, post IDs or raw URLs as labels. - Record durations in seconds and sizes in bytes.
Histogram buckets
Check the default bucket boundaries of your SDK. Some defaults (0, 5, 10, 25 … 10000) assume milliseconds. If you record seconds into them, every request lands in the first bucket. Set the boundaries explicitly, e.g. 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5.
Do not expose the metrics port
The metrics port is for monitoring, not for the internet. Do not open it in your security group. If you manage your VM with Ansible, keep it that way in your playbook too.
Verify
On your VM, run curl -s localhost:9464/metrics. You should see your own metrics, each with # HELP and # TYPE lines. Use the application, run curl again and check that the values change. From your own computer, the port should not be reachable.
Tip
The maturity of the OpenTelemetry Prometheus exporter differs between languages. If it is not available or not stable for yours, ask a TA before choosing an alternative.
Documentation requirements¶
What we expect your documentation to have?
Refer back to previous weeks' documentation
- Do you need to update anything you wrote in previous weeks?
Authentication system
- How does your authentication work (registration, login, sessions)?
- What password hashing algorithm did you or your identity provider service use and why?
- How do you track post ownership for both regular and anonymous posts?
Real-time updates
- What technology did you use for real-time communication?
- How do you handle real-time vote and post updates?
Database
- What database did you choose and why?
- What is your database structure (schema/collections)?
Private posts
- How do you prevent other users from seeing private posts?
- When a user tries to view/modify a post, how do you check if they own it?
Metrics
- Which metrics did you create, and what does each one measure?
- Why did you choose that metric type (counter, gauge, histogram) for each?
- Which labels do you use, and what values can they take?
- On which port are the metrics served, and how is it protected from outside access?
- Include a short excerpt of your
/metricsoutput.
Tasks¶
- Go through the user stories and implement all new features.
- Start holding user data in a database.
- Instrument your backend with OpenTelemetry and expose at least three metrics (counter, gauge, histogram) on /metrics, on a separate port that is not publicly reachable.
- Keep your backend unit test coverage at least 50%.
- Implement unit tests for functions that do password hashing, verification and changing.
- Go through the documentation requirements and make sure to keep your documentation up to date.