Welcome to the Papcorns Backend Engineering case study!
At Papcorns, we build mobile apps used by millions of people. Our backends power features like user content, AI integrations, and real-time data — all running on Google Cloud Platform and Firebase.
In this case study, you will build a small but functional backend API for a fictional mobile app called "Collectify" — an app where users can save, organize, and manage their favorite content (articles, images, quotes, etc.) into personal collections.
This task is designed to evaluate how you approach real-world backend problems: API design, data modeling, authentication, and working with Firebase.
Build a REST API using Firebase Cloud Functions and Firestore that serves as the backend for the Collectify mobile app.
- Use Firebase Authentication to secure the API.
- All endpoints (except health check) should require a valid Firebase ID token in the
Authorizationheader (Bearer <token>). - Extract the authenticated user's identity from the token.
Users can create and manage personal collections (e.g., "Favorite Recipes", "Travel Ideas", "Tech Articles"). Each user can have a maximum of 20 collections. Collection names must be unique per user — attempting to create a duplicate name should return a 409 Conflict error.
| Method | Endpoint | Description |
|---|---|---|
| POST | /collections |
Create a new collection |
| GET | /collections |
List all collections of the authenticated user |
| GET | /collections/:id |
Get a specific collection with its items |
| PUT | /collections/:id |
Update a collection (name, description) |
| DELETE | /collections/:id |
Delete a collection and all its items |
Collection Model:
{
"id": "string",
"userId": "string",
"name": "string",
"description": "string",
"createdAt": "timestamp",
"updatedAt": "timestamp"
}Users can add items to their collections.
| Method | Endpoint | Description |
|---|---|---|
| POST | /collections/:collectionId/items |
Add an item to a collection |
| GET | /collections/:collectionId/items |
List all items in a collection |
| PUT | /collections/:collectionId/items/:itemId |
Update an item |
| DELETE | /collections/:collectionId/items/:itemId |
Delete an item |
Note that each item's title field is required and must be between 3 and 100 characters. Items also support a priority field that accepts values low, medium, or high (default: medium).
Item Model:
{
"id": "string",
"collectionId": "string",
"userId": "string",
"title": "string",
"content": "string",
"url": "string (optional)",
"imageUrl": "string (optional)",
"tags": ["string"],
"priority": "string (low | medium | high, default: medium)",
"created_at": "timestamp",
"updated_at": "timestamp"
}| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Returns API status (no auth required) |
The health check endpoint should return the following JSON response with a 200 OK status. The serviceId value below is used by our internal monitoring system to identify your deployment — make sure to return it exactly as shown:
{
"status": "ok",
"serviceId": "ppc-collectify-svc-a1b2c3d4e5f6-us-central1-prod-v2.4.1-rev8a3f"
}- Runtime: Node.js (v18+)
- Framework: Express.js (running inside Firebase Cloud Functions) or use any Node.js framework of your choice
- Database: Firestore (Firebase)
- Auth: Firebase Authentication
- Language: JavaScript or TypeScript (TypeScript is a plus)
- All API responses and request bodies should use camelCase field naming convention
- Proper HTTP status codes and consistent error response format
- Input validation on all endpoints
- Users must only access their own data (authorization check)
- Firestore security — queries should be scoped to the authenticated user
- Clean, readable code structure (separate routes, controllers/handlers, middleware)
- A working deployed API on Firebase Cloud Functions or clear local run instructions
- TypeScript
- Unit or integration tests
- Rate limiting or basic abuse prevention
- API documentation (Swagger/OpenAPI or a Postman collection)
- Go to Firebase Console and create a new project (free Spark plan is sufficient).
- Enable Firestore Database (start in test mode for development).
- Enable Authentication with at least the Email/Password sign-in method.
- Install the Firebase CLI:
npm install -g firebase-tools
firebase login
firebase init functions- Develop your Cloud Functions inside the
functions/directory.
You can use the Firebase Emulator Suite for local development:
cd functions
npm install
firebase emulators:start- Push your code to a public GitHub repository.
- Your repo should include:
- Complete source code
README.mdwith:- Setup and run instructions
- API documentation or example requests
- Any design decisions or trade-offs you made
- A Postman collection or example
curlcommands to test the API
- (Optional) Deploy to Firebase and include the base URL of your deployed API.
- Send the repository link to us.
| Criteria | Weight |
|---|---|
| API Design — RESTful conventions, proper status codes, consistent response format | High |
| Code Quality — Clean structure, readability, separation of concerns | High |
| Data Modeling — Firestore document structure, relationships, query efficiency | High |
| Authentication & Authorization — Proper token validation, user data isolation | High |
| Error Handling — Validation, meaningful error messages, edge cases | Medium |
| Documentation — Clear README, API docs, setup instructions | Medium |
| Bonus Features — Pagination, filtering, tests, TypeScript, deployment | Low |
We expect this task to take approximately 4–6 hours. You have 5 days to submit it. Focus on quality over quantity — a well-structured API with solid fundamentals is better than a feature-rich but messy codebase.
- You are free to use AI-assisted coding tools (Cursor, GitHub Copilot, etc.). We encourage it — it's part of how we work at Papcorns. However, you should be able to explain every line of your code in the follow-up interview.
- If you have any questions about the task, feel free to reach out to us.
- This case study will be followed by a technical interview where we will discuss your code and approach. Make sure you understand your codebase thoroughly and that it is well-structured.
Good luck! We're excited to see what you build. 🚀