{"id":50711899,"url":"https://github.com/developerdavid2/kite-backend","last_synced_at":"2026-06-09T16:02:45.145Z","repository":{"id":351047135,"uuid":"1209307129","full_name":"developerdavid2/kite-backend","owner":"developerdavid2","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-27T09:25:51.000Z","size":121,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-27T11:18:15.677Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://kite-backend-sigma.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/developerdavid2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-13T09:44:51.000Z","updated_at":"2026-04-27T09:25:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/developerdavid2/kite-backend","commit_stats":null,"previous_names":["developerdavid2/kite-backend"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/developerdavid2/kite-backend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developerdavid2%2Fkite-backend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developerdavid2%2Fkite-backend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developerdavid2%2Fkite-backend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developerdavid2%2Fkite-backend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/developerdavid2","download_url":"https://codeload.github.com/developerdavid2/kite-backend/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developerdavid2%2Fkite-backend/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34114437,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-09T16:02:43.853Z","updated_at":"2026-06-09T16:02:45.139Z","avatar_url":"https://github.com/developerdavid2.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kite-backend\n\nA production-grade REST API built with Node.js, Express, and TypeScript.\nIntegrates with three external APIs to classify names by gender, age, and\nnationality. Stores results in MongoDB with full CRUD support.\n\n---\n\n## Tech Stack\n\n| Technology       | Purpose                 |\n| ---------------- | ----------------------- |\n| **Node.js** v18+ | Runtime                 |\n| **Express** v5   | Web framework           |\n| **TypeScript**   | Strict typing, no `any` |\n| **Mongoose**     | MongoDB ODM             |\n| **Axios**        | HTTP client             |\n| **UUID v7**      | Unique profile IDs      |\n| **Vercel**       | Serverless deployment   |\n\n---\n\n## Architecture\n\n```\nsrc/\n├── config/         → Database connection with cache\n├── models/         → Mongoose schema and model\n├── routes/         → Express router definitions\n├── controllers/    → Request validation and orchestration\n├── services/       → External API calls and business logic\n├── utils/          → Response formatting and classification helpers\n├── types/          → All TypeScript interfaces\n└── middleware/     → Global error handler\n```\n\n**Separation of concerns:**\n\n- `routes/` — maps HTTP paths to controllers, nothing else\n- `controllers/` — validates input, calls services, formats responses\n- `services/` — all external API logic, throws typed errors\n- `utils/` — pure functions, no side effects\n- `types/` — single source of truth for all interfaces\n- `middleware/` — catches all unhandled errors, returns correct status\n\n---\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js v18+\n- MongoDB Atlas account (free tier works)\n\n### Installation\n\n```bash\ngit clone https://github.com/developerdavid2/kite-backend.git\ncd kite-backend\nnpm install\n```\n\n### Environment Variables\n\nCreate a `.env` file in the root:\n\n```env\nMONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/kite-backend\nPORT=3000\n```\n\n### Run Locally\n\n```bash\nnpm run dev\n```\n\nServer starts at `http://localhost:3000`\n\n---\n\n## API Reference\n\n### Stage 0 — Name Classification\n\n#### `GET /api/classify?name={name}`\n\nCalls the Genderize API and returns a processed gender prediction.\n\n**Success Response `200`**\n\n```json\n{\n  \"status\": \"success\",\n  \"data\": {\n    \"name\": \"john\",\n    \"gender\": \"male\",\n    \"probability\": 0.99,\n    \"sample_size\": 1234,\n    \"is_confident\": true,\n    \"processed_at\": \"2026-04-01T12:00:00Z\"\n  }\n}\n```\n\n**Processing Rules**\n\n- `count` from Genderize is renamed to `sample_size`\n- `is_confident` = `probability \u003e= 0.7` AND `sample_size \u003e= 100`\n- `processed_at` is generated fresh on every request via `new Date().toISOString()`\n\n**Error Responses**\n\n| Status | Cause                   | Message                                         |\n| ------ | ----------------------- | ----------------------------------------------- |\n| `400`  | Missing or empty name   | `Missing or empty name parameter`               |\n| `422`  | name is not a string    | `name is not a string`                          |\n| `404`  | No prediction available | `No prediction available for the provided name` |\n| `502`  | Genderize API failed    | `Genderize returned an invalid response`        |\n| `500`  | Unexpected error        | `Internal server error`                         |\n\n---\n\n### Stage 1 — Profile Management\n\n#### `POST /api/profiles`\n\nCalls Genderize, Agify, and Nationalize APIs in parallel and stores the\nresult. If the name already exists, returns the existing profile without\ncalling the APIs again.\n\n**Request Body**\n\n```json\n{ \"name\": \"ella\" }\n```\n\n**Success Response `201 Created`**\n\n```json\n{\n  \"status\": \"success\",\n  \"data\": {\n    \"id\": \"b3f9c1e2-7d4a-4c91-9c2a-1f0a8e5b6d12\",\n    \"name\": \"ella\",\n    \"gender\": \"female\",\n    \"gender_probability\": 0.99,\n    \"sample_size\": 1234,\n    \"age\": 46,\n    \"age_group\": \"adult\",\n    \"country_id\": \"DK\",\n    \"country_probability\": 0.85,\n    \"created_at\": \"2026-04-01T12:00:00Z\"\n  }\n}\n```\n\n**Duplicate Response `200`**\n\n```json\n{\n  \"status\": \"success\",\n  \"message\": \"Profile already exists\",\n  \"data\": { \"...existing profile...\" }\n}\n```\n\n---\n\n#### `GET /api/profiles`\n\nReturns all profiles. Supports optional case-insensitive filtering.\n\n**Query Parameters**\n\n| Parameter    | Type   | Example            |\n| ------------ | ------ | ------------------ |\n| `gender`     | string | `?gender=male`     |\n| `country_id` | string | `?country_id=NG`   |\n| `age_group`  | string | `?age_group=adult` |\n\nParameters are combinable: `?gender=male\u0026country_id=NG\u0026age_group=adult`\n\n**Success Response `200`**\n\n```json\n{\n  \"status\": \"success\",\n  \"count\": 2,\n  \"data\": [\n    {\n      \"id\": \"id-1\",\n      \"name\": \"john\",\n      \"gender\": \"male\",\n      \"age\": 25,\n      \"age_group\": \"adult\",\n      \"country_id\": \"US\"\n    }\n  ]\n}\n```\n\n---\n\n#### `GET /api/profiles/:id`\n\nReturns a single profile by UUID.\n\n**Success Response `200`**\n\n```json\n{\n  \"status\": \"success\",\n  \"data\": {\n    \"id\": \"b3f9c1e2-7d4a-4c91-9c2a-1f0a8e5b6d12\",\n    \"name\": \"john\",\n    \"gender\": \"male\",\n    \"gender_probability\": 0.99,\n    \"sample_size\": 1234,\n    \"age\": 25,\n    \"age_group\": \"adult\",\n    \"country_id\": \"US\",\n    \"country_probability\": 0.85,\n    \"created_at\": \"2026-04-01T12:00:00Z\"\n  }\n}\n```\n\n---\n\n#### `DELETE /api/profiles/:id`\n\nDeletes a profile by UUID. Returns `204 No Content` on success.\n\n---\n\n## Classification Logic\n\n### Age Groups\n\n| Age Range | Group      |\n| --------- | ---------- |\n| 0 – 12    | `child`    |\n| 13 – 19   | `teenager` |\n| 20 – 59   | `adult`    |\n| 60+       | `senior`   |\n\n### Nationality\n\nThe country with the highest probability in the Nationalize response\narray is selected as `country_id`.\n\n---\n\n## Error Handling\n\nAll errors follow this shape:\n\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"\"\n}\n```\n\n**External API edge cases — returns `502`, nothing is stored:**\n\n- Genderize returns `gender: null` or `count: 0`\n- Agify returns `age: null`\n- Nationalize returns an empty country array\n\n**Profile errors:**\n\n| Status | Cause                    |\n| ------ | ------------------------ |\n| `400`  | Missing or empty name    |\n| `422`  | name is not a string     |\n| `404`  | Profile not found        |\n| `502`  | Any external API failure |\n| `500`  | Unexpected server error  |\n\n---\n\n## Testing\n\n### Classify Endpoint\n\n```bash\n# Happy path\ncurl \"http://localhost:3000/api/classify?name=john\"\n\n# Missing name → 400\ncurl \"http://localhost:3000/api/classify\"\n\n# Empty name → 400\ncurl \"http://localhost:3000/api/classify?name=\"\n\n# Array name → 422\ncurl \"http://localhost:3000/api/classify?name[]=john\"\n\n# Unknown name → 404\ncurl \"http://localhost:3000/api/classify?name=xzqwerty\"\n```\n\n### Profiles Endpoints\n\n```bash\n# Create\ncurl -X POST http://localhost:3000/api/profiles \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"john\"}'\n\n# Get all\ncurl http://localhost:3000/api/profiles\n\n# Filter\ncurl \"http://localhost:3000/api/profiles?gender=male\u0026country_id=US\"\n\n# Get one\ncurl http://localhost:3000/api/profiles/{id}\n\n# Delete\ncurl -X DELETE http://localhost:3000/api/profiles/{id}\n\n# Duplicate\ncurl -X POST http://localhost:3000/api/profiles \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"john\"}'\n\n# Missing name → 400\ncurl -X POST http://localhost:3000/api/profiles \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n\n# Wrong type → 422\ncurl -X POST http://localhost:3000/api/profiles \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": 123}'\n\n# Unknown name → 502\ncurl -X POST http://localhost:3000/api/profiles \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"xzqwerty\"}'\n```\n\n---\n\n## Deployment\n\nDeployed on Vercel as a serverless function.\n\n- `api/index.ts` exports the Express app as default — Vercel handles the server\n- `vercel.json` routes all traffic to `api/index.ts`\n\nAdd `MONGODB_URI` in the Vercel dashboard under\n**Settings → Environment Variables**.\n\n```bash\n# Deploy via CLI\nvercel\n\n# Or push to GitHub — Vercel auto-deploys on push\ngit push origin main\n```\n\n---\n\n## Environment Variables\n\n| Variable      | Required | Description                      |\n| ------------- | -------- | -------------------------------- |\n| `MONGODB_URI` | ✅ Yes   | MongoDB Atlas connection string  |\n| `PORT`        | ❌ No    | Local dev port (default: `3000`) |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeveloperdavid2%2Fkite-backend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeveloperdavid2%2Fkite-backend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeveloperdavid2%2Fkite-backend/lists"}