Backend for the test task "Build app for comments and notifications".
This repository contains the Rails API only. The React frontend lives in a separate repository and is deployed to Vercel.
- Frontend: https://commento-frontend.vercel.app
- Backend: deployed to Render
The production API is configured to accept requests from the Vercel frontend and to use Meilisearch in production.
The implementation covers the requested scope:
- Rails 8.1 API-only application
- Simple token-based authentication
- Comment model with CRUD endpoints
- Meilisearch integration for comment search in production
- Notification model
- Mention notifications when a user is referenced as
@usernamein a comment - Mark one notification or all notifications as read
- Clean separation between controllers, operations, queries, jobs, and models
- Authentication is implemented with
has_secure_passwordonUser - Sessions return a bearer token stored in the
api_tokenstable - Tokens expire after 24 hours
- Every protected endpoint expects
Authorization: Bearer <token>
- Authenticated users can create, list, update, and delete their own comments
GET /api/v1/commentsreturns paginated comments ordered by newest firstPATCH /api/v1/comments/:idis owner-onlyDELETE /api/v1/comments/:idis owner-only
- Searching is done through the
queryparam onGET /api/v1/comments - In production, search uses Meilisearch with sorting by
created_at desc - In development and test, the app falls back to PostgreSQL
ILIKEsearch when Meilisearch is inactive
- Mention notifications are stored in the
notificationstable withkind: mention - When a comment is created with mentions, a background job resolves mentioned usernames and creates notifications
- When a comment is edited, mention changes are reconciled: new mentions are added and removed mentions are deleted
- Notifications can be listed, counted, marked individually as read, or marked all at once as read
- The API also broadcasts notification changes through Action Cable / Solid Cable
Fastest way to review the task from the UI:
- Open the frontend at https://commento-frontend.vercel.app
- Sign up two different users
- Create a comment as one user mentioning the other, for example
Hello @alice - Sign in as the mentioned user and open notifications
- Mark a notification as read
- Search comments by body text
- Edit the original comment and change the mentioned usernames to verify notification reconciliation
Base path: /api/v1
POST /signup- create user and immediately issue a tokenPOST /session- log in and issue a tokenDELETE /session- log out by deleting the current tokenGET /me- return the currently authenticated userGET /users?query=ali- search users by username for mention suggestions
GET /comments?page=1&query=hello- list comments, optionally filtered by bodyPOST /comments- create commentPATCH /comments/:id- update owned commentDELETE /comments/:id- delete owned comment
GET /notifications?page=1- list current user's notificationsGET /notifications/unread_count- unread notification counterPATCH /notifications/:id/mark_as_read- mark one notification as readPATCH /notifications/mark_all_as_read- mark all current user's unread notifications as read
BASE_URL=http://localhost:3000/api/v1Sign up:
curl -X POST "$BASE_URL/signup" \
-H "Content-Type: application/json" \
-d '{"signup":{"username":"alice","password":"s3cr3t!"}}'Log in:
curl -X POST "$BASE_URL/session" \
-H "Content-Type: application/json" \
-d '{"session":{"username":"alice","password":"s3cr3t!"}}'Create a comment:
curl -X POST "$BASE_URL/comments" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"comment":{"body":"Hello @bob"}}'Search comments:
curl "$BASE_URL/comments?query=hello" \
-H "Authorization: Bearer <token>"List notifications:
curl "$BASE_URL/notifications" \
-H "Authorization: Bearer <token>"Mark one notification as read:
curl -X PATCH "$BASE_URL/notifications/1/mark_as_read" \
-H "Authorization: Bearer <token>"- Ruby 4.0.4
- PostgreSQL
- Bundler
Optional for production-like local testing:
- Meilisearch
Install dependencies and prepare the database:
bin/setup --skip-serverStart the Rails API:
bin/devThe API will be available at http://localhost:3000.
Meilisearch is enabled only in production configuration. In development and test, search still works through the Active Record fallback, so a reviewer can verify the search feature locally without running Meilisearch.
To exercise the Meilisearch-backed path in production-style environments, configure:
MEILISEARCH_HOSTMEILISEARCH_API_KEYDATABASE_URLin production deployments
Optional production Action Cable origin overrides:
ACTION_CABLE_ALLOWED_ORIGINS
Run the test suite:
bundle exec rspecRun the project CI command:
bin/ciSwagger/OpenAPI docs are generated from request specs and are available locally at:
http://localhost:3000/api-docs
Generated OpenAPI file:
swagger/v1/swagger.yaml
app/
controllers/ HTTP layer and authentication
models/ persistence and simple domain behavior
operations/ business actions such as login, signup, comment, and notification flows
queries/ reusable search/query objects
jobs/ background processing for mention handling
broadcasts/ Action Cable notification broadcasts
Important implementation details:
- mention extraction lives on
Comment#mentioned_usernames - comment creation queues mention processing
- comment updates reconcile added and removed mentions
- notification lists are paginated with Pagy
- real-time notification updates are published on
users:<id>:notifications
- This repository is the backend part of the assignment
- The frontend was intentionally split into a separate React repository and deployed independently to Vercel
- No seed demo accounts are included, so the expected review path is to create users through
POST /api/v1/signupor through the deployed frontend