Nodejs-Assessments
    • NodejsBackendEngineer2026-Assessment

    NodejsBackendEngineer2026-Assessment

    Backend Engineers Wanted - Contract to Full-Time Opportunity#

    Resilience 17 Venture Studio is seeking exceptional backend engineers. This is a 1-year contract with strong potential for conversion to full-time for candidates who demonstrate outstanding work ethics and execution.

    What We're Looking For#

    We need engineers who can:
    Follow instructions carefully - Strong attention to detail and precision
    Work efficiently - Ability to move quickly while maintaining quality
    Code confidently with AI assistants - Must be comfortable using GitHub Copilot, Cursor, or similar AI coding tools
    Master vanilla JavaScript fundamentals - Strong grasp of core JavaScript concepts (you'll use Express.js for routing, but we value engineers who understand the fundamentals)
    Take initiative - Identify and solve problems proactively
    Produce quality work - Consistently deliver clean, functional code
    Start immediately - We need people available to begin right away

    The Role#

    You'll be implementing well-defined and thoroughly documented API/backend service contracts and business requirements. This role focuses on precise execution of clear specifications in a fast-paced environment.
    Key Responsibilities:
    Build robust backend services using Node.js and Express
    Implement API contracts with precision and attention to detail
    Work with MongoDB for data persistence
    Deploy applications on cloud platforms (Heroku/Render)
    Collaborate in an agile team environment
    Report directly to the Engineering Lead

    Essential Requirements#

    Immediate availability - We need engineers ready to start as soon as possible
    Node.js (vanilla JavaScript) and Express.js - this is our primary stack
    MongoDB experience
    Understanding of RESTful API design and implementation
    Git/GitHub proficiency
    Strong debugging and problem-solving skills
    Ability to follow project templates and coding standards precisely
    Bonus points: working knowledge of any of PHP, Python, or Java in addition to Node.js

    What We Offer#

    100% remote work
    Flexible schedule - deliverables matter more than hours
    Real conversion opportunity - Exceptional performers will be offered full-time positions
    Fintech/Banking industry exposure - Work on cutting-edge financial technology
    Venture Studio environment - Fast-paced, innovative, entrepreneurial culture

    How to Apply#

    DEADLINE: June 24, 2026
    Complete our technical assessment and submit it via this Google form. You must provide:
    1.
    Publicly accessible GitHub repository with your solution
    2.
    Deployed BASE URL only (e.g., https://submission.herokuapp.com)
    Do NOT include any versioning in your URL - no /v1, /api/v1, or similar
    Do NOT include endpoint paths in your submission
    If your base URL is https://submission.herokuapp.com, we will test against POST https://submission.herokuapp.com/creator-cards, GET https://submission.herokuapp.com/creator-cards/:slug, and DELETE https://submission.herokuapp.com/creator-cards/:slug

    Technical Assessment#

    IMPORTANT: You must use the provided project template
    šŸ“¦ Backend Template Repository
    IMPORTANT: Follow the instructions to the letter
    The ability to follow instructions precisely is a core part of what this assessment evaluates. A correct, working implementation that did not follow the instructions to the letter will NOT be considered.
    Build a Creator Card microservice API that lets creators publish a shareable profile card showcasing their links and service rates (think "link-in-bio" cards with rate cards attached).
    Note: This assessment is a standalone technical exercise. It is not a reflection of the products or domain you will actually work on.

    Overview#

    Your task is to create a REST API with three endpoints: one that creates Creator Cards after validating them against the rules below, one that publicly retrieves a card by its slug while respecting draft status and private access controls, and one that deletes a card by its slug.

    The Creator Card Entity#

    FieldTypeConstraintsDescription
    idstringULIDStored as _id in MongoDB, but ALWAYS serialized as id in API responses
    titlestring3–100 characterse.g. "George Cooks"
    descriptionstringmax 500 characterse.g. "George Cooks is a weekly cooking podcast by Chef George AmadiObi"
    slugstring5–50 characters; unique; letters, numbers, hyphens and underscores onlyPublic identifier used for card retrieval
    creator_referencestringexactly 20 charactersIdentifies the creator on the consuming service
    links[]array of objects—Links the creator wants to showcase
    links[].titlestring1–100 charactersTitle of the link
    links[].urlstringmax 200 characters; must start with http:// or https://Link URL
    service_ratesobject—Rates offered by the creator for services
    service_rates.currencystringenum: NGN | USD | GBP | GHSCurrency for all rates on the card
    service_rates.rates[]array of objectsnon-empty if service_rates is presentIndividual service rates
    service_rates.rates[].namestring3–100 characterse.g. "IG Story Post"
    service_rates.rates[].descriptionstringmax 250 charactersDescription of the service
    service_rates.rates[].amountnumberpositive integer (min 1)Minor units: kobo for NGN, cents for USD, pence for GBP, pesewas for GHS
    statusstringenum: draft | publishedDrafts can NEVER be retrieved via the public endpoint
    access_typestringenum: public | privateDefaults to public
    access_codestringexactly 6 alphanumeric charactersRequired if access_type is private
    creatednumber—Unix epoch milliseconds
    updatednumber—Unix epoch milliseconds
    deletednumber | null—null unless the card has been deleted
    Important - _id vs id: In MongoDB the document identifier lives in the _id field, per MongoDB convention. However, all front-facing API responses must expose it as id. Your serialization layer is responsible for this mapping - a response containing _id is incorrect.

    Endpoint 1: Create Creator Card#

    Path: POST /creator-cards
    Request Format:
    {
      "title": "George Cooks",
      "description": "George Cooks is a weekly cooking podcast by Chef George AmadiObi",
      "slug": "george-cooks",
      "creator_reference": "crt_8f2k1m9x4p7w3q5z",
      "links": [
        {"title": "YouTube Channel", "url": "https://youtube.com/@georgecooks"},
        {"title": "Instagram", "url": "https://instagram.com/georgecooks"}
      ],
      "service_rates": {
        "currency": "NGN",
        "rates": [
          {"name": "IG Story Post", "description": "One Instagram story mention", "amount": 5000000},
          {"name": "Recipe Feature", "description": "Featured recipe segment on the podcast", "amount": 15000000}
        ]
      },
      "status": "published",
      "access_type": "public"
    }
    Field Requirements:
    FieldRequiredRules
    titleYesString, 3-100 characters
    descriptionNoString, max 500 characters
    slugNo5-50 characters; letters, numbers, hyphens (-) and underscores (_) only; must be unique across all cards
    creator_referenceYesString of exactly 20 characters
    linksNoArray; each entry must have a title (1-100 chars) and a valid url (max 200 chars) starting with http:// or https://
    service_ratesNoIf present: currency must be one of NGN, USD, GBP, GHS; rates must be a non-empty array; each rate must have a name (3-100 chars), a description (max 250 chars), and an amount that is a positive integer (minor units - no decimals, no negatives, no zero)
    statusYesMust be exactly draft or published
    access_typeNoMust be public or private if present; defaults to public when omitted
    access_codeConditionalRequired if access_type is private; must be exactly 6 alphanumeric characters (letters and numbers only). Must NOT be provided when access_type is public or omitted
    A note on validation: The project template ships with a validator DSL (VSL) that handles field-level validation - types, required fields, lengths, and enums - and returns its own formatted error responses. Use it. Your job is to ensure all validation failures return HTTP 400, and to implement the business rules the validator cannot express (slug uniqueness, the conditional access_code rules, retrieval access control). Those business rules carry the custom error codes defined below.
    Slug Auto-Generation:
    If slug is omitted, your service must auto-generate one from the title:
    1.
    Lowercase the title
    2.
    Replace whitespace with hyphens
    3.
    Remove any characters that are not letters, numbers, hyphens, or underscores
    4.
    If the result is shorter than 5 characters OR already taken by another card, append a hyphen followed by a random 6-character alphanumeric suffix (e.g., cook-a8x2k1)
    If slug IS provided by the client and is already taken, return the SL02 error - do NOT silently modify a client-provided slug.
    Response Format (Success - HTTP 200):
    {
      "status": "success",
      "message": "Creator Card Created Successfully.",
      "data": {
        "id": "01JG8XYZA2B3C4D5E6F7G8H9J0",
        "title": "George Cooks",
        "description": "George Cooks is a weekly cooking podcast by Chef George AmadiObi",
        "slug": "george-cooks",
        "creator_reference": "crt_8f2k1m9x4p7w3q5z",
        "links": [
          {"title": "YouTube Channel", "url": "https://youtube.com/@georgecooks"},
          {"title": "Instagram", "url": "https://instagram.com/georgecooks"}
        ],
        "service_rates": {
          "currency": "NGN",
          "rates": [
            {"name": "IG Story Post", "description": "One Instagram story mention", "amount": 5000000},
            {"name": "Recipe Feature", "description": "Featured recipe segment on the podcast", "amount": 15000000}
          ]
        },
        "status": "published",
        "access_type": "public",
        "access_code": null,
        "created": 1767052800000,
        "updated": 1767052800000,
        "deleted": null
      }
    }
    Note: access_code is returned in the creation response (the creator needs to know it), but it is NEVER returned by the public retrieval endpoint.
    Response Format (Business Rule Error - HTTP 400):
    {
      "status": "error",
      "message": "Slug is already taken",
      "code": "SL02"
    }

    Endpoint 2: Public Card Retrieval#

    Path: GET /creator-cards/:slug
    Retrieves a single Creator Card by its slug. This is the public endpoint that powers shareable card links.
    Access Rules (apply in this order):
    1.
    If no card with that slug exists → HTTP 404, error code NF01
    2.
    If the card exists but its status is draft → HTTP 404, error code NF02 (drafts are not publicly retrievable; the distinct code lets API callers distinguish "does not exist" from "exists but is a draft")
    3.
    If the card is private and no access_code query parameter was supplied → HTTP 403, error code AC03
    4.
    If the card is private and the supplied access_code does not match → HTTP 403, error code AC04
    5.
    Otherwise → HTTP 200 with the card data
    Private card access: clients supply the pin as a query parameter:
    GET /creator-cards/george-cooks?access_code=A1B2C3
    Response Format (Success - HTTP 200):
    {
      "status": "success",
      "message": "Creator Card Retrieved Successfully.",
      "data": {
        "id": "01JG8XYZA2B3C4D5E6F7G8H9J0",
        "title": "George Cooks",
        "description": "George Cooks is a weekly cooking podcast by Chef George AmadiObi",
        "slug": "george-cooks",
        "creator_reference": "crt_8f2k1m9x4p7w3q5z",
        "links": [
          {"title": "YouTube Channel", "url": "https://youtube.com/@georgecooks"}
        ],
        "service_rates": {
          "currency": "NGN",
          "rates": [
            {"name": "IG Story Post", "description": "One Instagram story mention", "amount": 5000000}
          ]
        },
        "status": "published",
        "access_type": "public",
        "created": 1767052800000,
        "updated": 1767052800000,
        "deleted": null
      }
    }
    Note: The access_code field is OMITTED entirely from retrieval responses, even for private cards accessed with the correct pin. The identifier is exposed as id, never _id.
    Response Format (Error):
    {
      "status": "error",
      "message": "Creator card not found",
      "code": "NF01"
    }

    Endpoint 3: Delete Creator Card#

    Path: DELETE /creator-cards/:slug
    Deletes the card tied to the given slug.
    Request Format:
    {
      "creator_reference": "crt_8f2k1m9x4p7w3q5z"
    }
    Field Requirements:
    FieldRequiredRules
    creator_referenceYesString of exactly 20 characters
    Behavior:
    If no card with that slug exists → HTTP 404, error code NF01
    On success → HTTP 200, returning the deleted card in the same response format as the creation endpoint
    Once a card is deleted, it must no longer be retrievable via the public retrieval endpoint (GET /creator-cards/:slug returns HTTP 404, NF01)
    Response Format (Success - HTTP 200):
    {
      "status": "success",
      "message": "Creator Card Deleted Successfully.",
      "data": {
        "id": "01JG8XYZA2B3C4D5E6F7G8H9J0",
        "title": "George Cooks",
        "description": "George Cooks is a weekly cooking podcast by Chef George AmadiObi",
        "slug": "george-cooks",
        "creator_reference": "crt_8f2k1m9x4p7w3q5z",
        "links": [
          {"title": "YouTube Channel", "url": "https://youtube.com/@georgecooks"},
          {"title": "Instagram", "url": "https://instagram.com/georgecooks"}
        ],
        "service_rates": {
          "currency": "NGN",
          "rates": [
            {"name": "IG Story Post", "description": "One Instagram story mention", "amount": 5000000},
            {"name": "Recipe Feature", "description": "Featured recipe segment on the podcast", "amount": 15000000}
          ]
        },
        "status": "published",
        "access_type": "public",
        "access_code": null,
        "created": 1767052800000,
        "updated": 1767052800000,
        "deleted": 1767139200000
      }
    }

    Custom Error Codes#

    Field-level validation errors (wrong types, missing required fields, length violations, invalid enum values) are handled by the template's validator and simply need to return HTTP 400. The codes below are the custom business rule errors you must implement yourself:
    Business RuleError CodeHTTP CodeExample Message
    Slug must be unique across all cardsSL02400"Slug is already taken"
    access_code is required when access_type is privateAC01400"access_code is required when access_type is private"
    access_code must not be set on public cardsAC05400"access_code can only be set on private cards"
    Card with the given slug does not existNF01404"Creator card not found"
    Card exists but is in draft statusNF02404"Creator card not found"
    Access code required to view private cardAC03403"This card is private. An access code is required"
    Invalid access codeAC04403"Invalid access code"
    Important Notes:
    The message field should contain a clear, human-readable message (never empty)
    The messages in the table are examples - you may customize them to be more descriptive
    The code must match exactly as specified in the table above
    Retrieval access rules (NF01, NF02, AC03, AC04) must be applied in the order listed in the Access Rules section
    Note that NF01 and NF02 both return HTTP 404 with similar messages - the code is what allows an API caller to tell them apart
    Additional Checks & Business Logic:
    You are free to take liberties and include additional checks, constraints, or business logic beyond what is specified - so long as nothing you add conflicts with the instructions given here. The specified request/response shapes, error codes, and HTTP statuses must remain exactly as defined. Thoughtful additions are welcome and may come up for discussion at the interview stage.

    Requirements#

    1.
    Use the provided Node.js project scaffold template - Backend Template
    You must follow the backend template structure exactly (services, endpoints, messages, middleware conventions)
    Use the template's validator (VSL) for field-level validation
    Use the template's error utilities for throwing business rule errors
    Do not deviate from the project organization
    2.
    MongoDB Required - Cards must be persisted in MongoDB
    Use MongoDB Atlas free tier (or similar) for your deployed instance
    Documents use _id internally per MongoDB convention; API responses must expose id
    Slug uniqueness must hold across all requests, including auto-generated slugs
    3.
    Deploy your solution to Heroku, Render, or similar platform
    All three endpoints must be publicly accessible
    No authentication required - do NOT implement or require API keys, bearer tokens, or any auth headers
    No URL versioning - endpoints must live at the root of your base URL: POST {base_url}/creator-cards, NOT POST {base_url}/v1/creator-cards or POST {base_url}/api/creator-cards
    4.
    Error Handling - All errors must return appropriate JSON responses with proper HTTP status codes
    All validation failures (framework or custom) must return HTTP 400
    Malformed JSON bodies and unexpected server errors must not crash your service
    5.
    Code Quality - Clean, readable, well-organized code that follows the template structure

    Testing Your Solution#

    Valid Test Cases:
    Test Case 1 - Full creation:
    POST /creator-cards
    {
      "title": "George Cooks",
      "description": "Weekly cooking podcast",
      "slug": "george-cooks",
      "creator_reference": "crt_8f2k1m9x4p7w3q5z",
      "links": [{"title": "YouTube", "url": "https://youtube.com/@georgecooks"}],
      "service_rates": {
        "currency": "NGN",
        "rates": [{"name": "IG Story Post", "description": "One story mention", "amount": 5000000}]
      },
      "status": "published"
    }
    Expected: HTTP 200, card created with access_type defaulting to "public", response contains id (not _id)
    Test Case 2 - Slug auto-generation:
    POST /creator-cards
    {
      "title": "Ada Designs Things",
      "creator_reference": "crt_a1b2c3d4e5f6g7h8",
      "status": "published"
    }
    Expected: HTTP 200, slug auto-generated as "ada-designs-things"
    Test Case 3 - Private card creation:
    POST /creator-cards
    {
      "title": "VIP Rate Card",
      "creator_reference": "crt_x9y8z7w6v5u4t3s2",
      "status": "published",
      "access_type": "private",
      "access_code": "A1B2C3"
    }
    Expected: HTTP 200, access_code "A1B2C3" returned in creation response
    Test Case 4 - Retrieving a public published card:
    GET /creator-cards/george-cooks
    Expected: HTTP 200 with card data, no access_code field, identifier exposed as id
    Test Case 5 - Retrieving a private card with correct pin:
    GET /creator-cards/vip-rate-card?access_code=A1B2C3
    Expected: HTTP 200 with card data, no access_code field in response
    Test Case 6 - Deleting a card:
    DELETE /creator-cards/ada-designs-things
    {
      "creator_reference": "crt_a1b2c3d4e5f6g7h8"
    }
    Expected: HTTP 200, the deleted card returned in the same format as the creation response, with deleted set
    Invalid Test Cases:
    Test Case 7 - Duplicate slug:
    POST /creator-cards
    {
      "title": "Another George",
      "slug": "george-cooks",
      "creator_reference": "crt_m1n2b3v4c5x6z7l8",
      "status": "published"
    }
    Expected: HTTP 400, SL02 (assuming Test Case 1 already created this slug)
    Test Case 8 - Missing access_code on private card:
    POST /creator-cards
    {
      "title": "Secret Card",
      "creator_reference": "crt_q1w2e3r4t5y6u7i8",
      "status": "published",
      "access_type": "private"
    }
    Expected: HTTP 400, AC01
    Test Case 9 - access_code on a public card:
    POST /creator-cards
    {
      "title": "Public Card",
      "creator_reference": "crt_q1w2e3r4t5y6u7i8",
      "status": "published",
      "access_type": "public",
      "access_code": "A1B2C3"
    }
    Expected: HTTP 400, AC05
    Test Case 10 - Framework validation failure:
    POST /creator-cards
    {
      "title": "Bad Status Card",
      "creator_reference": "crt_q1w2e3r4t5y6u7i8",
      "status": "archived"
    }
    Expected: HTTP 400 with the validator's error response ("archived" is not a valid status). We are checking the HTTP code here, not a custom error code.
    Test Case 11 - Retrieving a non-existent card:
    GET /creator-cards/does-not-exist-123
    Expected: HTTP 404, NF01
    Test Case 12 - Retrieving a draft card:
    GET /creator-cards/my-draft-card
    Expected: HTTP 404, NF02 (card exists but is a draft)
    Test Case 13 - Retrieving a private card without a pin:
    GET /creator-cards/vip-rate-card
    Expected: HTTP 403, AC03
    Test Case 14 - Retrieving a private card with a wrong pin:
    GET /creator-cards/vip-rate-card?access_code=WRONG1
    Expected: HTTP 403, AC04
    Test Case 15 - Deleting a non-existent card:
    DELETE /creator-cards/does-not-exist-123
    {
      "creator_reference": "crt_q1w2e3r4t5y6u7i8"
    }
    Expected: HTTP 404, NF01
    Test Case 16 - Retrieving a deleted card:
    GET /creator-cards/ada-designs-things
    Expected: HTTP 404, NF01 (assuming Test Case 6 deleted this card)

    Submission Checklist#

    Before submitting, ensure:
    āœ… Your GitHub repository is public and contains clean, well-documented code
    āœ… Your solution follows the provided template structure exactly (services, endpoints, messages)
    āœ… All three endpoints are deployed and publicly accessible
    āœ… Field-level validation uses the template's validator and returns HTTP 400 on failure
    āœ… All custom business rule errors return the correct code and HTTP status (SL02, AC01, AC05, NF01, NF02, AC03, AC04)
    āœ… Drafts return 404 with NF02 on the public endpoint and access codes never leak in retrieval responses
    āœ… Deleting a card returns the deleted card in the creation response format, and deleted cards return 404 (NF01) on the public endpoint
    āœ… API responses expose id, never _id
    āœ… Slug auto-generation and uniqueness work correctly
    āœ… No auth required to call your endpoints - no API keys or bearer tokens
    āœ… Your endpoints are at the root of your base URL with no versioning (/creator-cards, not /v1/creator-cards)
    āœ… You've tested with multiple valid and invalid cases
    āœ… You've re-read the instructions and followed them to the letter

    Application Process#

    Submissions open: June 10, 2026.
    Submissions close: June 24, 2026.
    Submit your completed assessment using this Google form
    Your submission must include:
    GitHub repository link (public)
    Deployed base URL only, with no versioning and no endpoint paths (e.g., https://submission.herokuapp.com)

    Modified atĀ 2026-06-10 17:44:50
    Built with