{"id":15295973,"url":"https://github.com/arifintahu/project-structure-api","last_synced_at":"2026-03-07T17:13:52.412Z","repository":{"id":58180626,"uuid":"411470228","full_name":"arifintahu/project-structure-api","owner":"arifintahu","description":"Complete project template for building RESTful API with Typescript.","archived":false,"fork":false,"pushed_at":"2024-03-10T22:57:20.000Z","size":644,"stargazers_count":137,"open_issues_count":0,"forks_count":22,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-01T13:34:52.234Z","etag":null,"topics":["expressjs","project-template","rest-api","typescript"],"latest_commit_sha":null,"homepage":"","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/arifintahu.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}},"created_at":"2021-09-28T23:45:25.000Z","updated_at":"2025-09-20T08:13:08.000Z","dependencies_parsed_at":"2024-03-10T23:47:34.859Z","dependency_job_id":null,"html_url":"https://github.com/arifintahu/project-structure-api","commit_stats":null,"previous_names":[],"tags_count":3,"template":true,"template_full_name":null,"purl":"pkg:github/arifintahu/project-structure-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arifintahu%2Fproject-structure-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arifintahu%2Fproject-structure-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arifintahu%2Fproject-structure-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arifintahu%2Fproject-structure-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arifintahu","download_url":"https://codeload.github.com/arifintahu/project-structure-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arifintahu%2Fproject-structure-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30222732,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T17:00:40.062Z","status":"ssl_error","status_checked_at":"2026-03-07T17:00:39.026Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["expressjs","project-template","rest-api","typescript"],"created_at":"2024-09-30T18:08:48.501Z","updated_at":"2026-03-07T17:13:52.397Z","avatar_url":"https://github.com/arifintahu.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv id=\"top\"\u003e\u003c/div\u003e\n\n[![Contributors][contributors-shield]][contributors-url]\n[![Forks][forks-shield]][forks-url]\n[![Stargazers][stars-shield]][stars-url]\n[![Issues][issues-shield]][issues-url]\n\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ch3 align=\"center\"\u003eProject Structure API\u003c/h3\u003e\n\n  \u003cp align=\"center\"\u003e\n    A production-ready project template for building RESTful APIs with TypeScript, Express, and Sequelize\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"https://github.com/arifintahu/project-structure-api/issues\"\u003eReport Bug\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/arifintahu/project-structure-api/issues\"\u003eRequest Feature\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eTable of Contents\u003c/summary\u003e\n  \u003col\u003e\n    \u003cli\u003e\u003ca href=\"#about-the-project\"\u003eAbout The Project\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#architecture\"\u003eArchitecture\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#docker\"\u003eDocker\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#api-reference\"\u003eAPI Reference\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#openapi-spec\"\u003eOpenAPI Spec\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#testing\"\u003eTesting\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#project-structure\"\u003eProject Structure\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e\u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/details\u003e\n\n## About The Project\n\nA clean, scalable Node.js API boilerplate with proper separation of concerns. Built with modern tooling (Node 22+, TypeScript 5.7, ESLint 9) and production-grade features including security hardening, structured logging, health checks, graceful shutdown, and CI/CD.\n\n### Built With\n\n| Category      | Technology                                                                                                                           |\n| ------------- | ------------------------------------------------------------------------------------------------------------------------------------ |\n| **Runtime**   | [Node.js](https://nodejs.org/) v22+                                                                                                  |\n| **Language**  | [TypeScript](https://www.typescriptlang.org/) 5.7                                                                                    |\n| **Framework** | [Express.js](https://expressjs.com/) 4.x                                                                                             |\n| **ORM**       | [Sequelize](https://sequelize.org/) 6.x                                                                                              |\n| **Database**  | [PostgreSQL](https://www.postgresql.org/)                                                                                            |\n| **Auth**      | [JSON Web Token](https://www.npmjs.com/package/jsonwebtoken) + [bcrypt](https://www.npmjs.com/package/bcrypt)                        |\n| **Security**  | [Helmet](https://helmetjs.github.io/) + [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)                       |\n| **Docs**      | [Swagger](https://swagger.io/) (swagger-jsdoc + swagger-ui-express)                                                                  |\n| **Testing**   | [Jest](https://jestjs.io/) + [ts-jest](https://kulshekhar.github.io/ts-jest/) + [Supertest](https://www.npmjs.com/package/supertest) |\n| **Linting**   | [ESLint](https://eslint.org/) 9 (flat config) + [Prettier](https://prettier.io/)                                                     |\n| **CI/CD**     | [GitHub Actions](https://github.com/features/actions)                                                                                |\n| **Container** | [Docker](https://www.docker.com/) + Docker Compose                                                                                   |\n\n### Features\n\n- **Layered architecture** — Routes → Controllers → Services → Repositories → Models\n- **Security hardening** — Helmet headers, rate limiting, body size limits, env-based CORS\n- **Request tracing** — `X-Request-Id` UUID per request, included in logs and response headers\n- **Structured logging** — JSON format in production (for log aggregation), colorized in development\n- **Health check** — `GET /health` with database connectivity status\n- **Graceful shutdown** — Handles `SIGTERM`/`SIGINT`, drains connections, closes DB pool\n- **DB connection pooling** — Configurable Sequelize pool (min/max/acquire/idle)\n- **Typed error handling** — Custom `AppError` hierarchy with proper HTTP status codes\n- **Consistent API responses** — `ApiResponse` utility for uniform success/error/paginated responses\n- **Pagination** — Built-in paginated list endpoints with `?page=1\u0026limit=10`\n- **Password hashing** — Automatic bcrypt hashing via Sequelize model hooks\n- **Environment validation** — Required env vars checked at startup with clear errors\n- **JWT authentication** — Token-based auth with role-based access control\n- **OpenAPI 3.0** — Inline JSDoc specs co-located with routes + JSON spec export\n- **Docker** — Multi-stage build, non-root user, health check, Compose with PostgreSQL\n- **CI/CD** — GitHub Actions pipeline (lint → build → test)\n- **Pre-commit hooks** — Husky + lint-staged for ESLint and Prettier on commit\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Architecture\n\n```\nRequest → Route → Middleware (auth, validation) → Controller → Service → Repository → Model → DB\n                                                      ↓\n                                               ApiResponse (success/error)\n```\n\n| Layer            | Responsibility                                 | Example                              |\n| ---------------- | ---------------------------------------------- | ------------------------------------ |\n| **Routes**       | HTTP method + URL mapping, middleware chaining | `POST /api/v1/users`                 |\n| **Middlewares**  | Auth, validation, rate limiting, request ID    | `Auth.authenticate`, `Validate(...)` |\n| **Controllers**  | Parse request, call service, send response     | `UserController.createUser`          |\n| **Services**     | Business logic, validation rules               | `UserService.createUser`             |\n| **Repositories** | Database queries via Sequelize                 | `UserRepository.getUsers`            |\n| **Models**       | Schema definition, hooks, associations         | `User`, `Role`                       |\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Getting Started\n\n### Prerequisites\n\n- **Node.js** v22 or higher\n- **PostgreSQL** server running (or use Docker)\n- **npm** (comes with Node.js)\n\n### Installation\n\n1. **Clone or use as template**\n\n    ```sh\n    git clone https://github.com/arifintahu/project-structure-api.git\n    cd project-structure-api\n    ```\n\n    Or click [**Use this template**](https://github.com/arifintahu/project-structure-api/generate) on GitHub.\n\n2. **Install dependencies**\n\n    ```sh\n    npm ci\n    ```\n\n3. **Configure environment**\n\n    ```sh\n    cp .env.example .env\n    ```\n\n    Edit `.env` with your settings:\n\n    ```env\n    NODE_ENV=development\n    APP_NAME=my-project\n    SERVER=development\n    PORT=3001\n    SECRET=your-secret-key\n    API_VERSION=v1\n\n    # CORS\n    CORS_ORIGIN=*\n\n    # Rate Limiting\n    RATE_LIMIT_WINDOW_MS=900000\n    RATE_LIMIT_MAX=100\n\n    # Database\n    DB_HOST=localhost\n    DB_DATABASE=mydb\n    DB_USERNAME=postgres\n    DB_PASSWORD=postgres\n    DB_PORT=5432\n    DB_DIALECT=postgres\n    DB_TIMEZONE=Asia/Jakarta\n    DB_LOG=true\n\n    # Database Connection Pool\n    DB_POOL_MIN=2\n    DB_POOL_MAX=10\n    ```\n\n    \u003e **Required vars**: `DB_HOST`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`. The app will fail fast with a clear error if any are missing.\n\n4. **Build the project**\n\n    ```sh\n    npm run build\n    ```\n\n5. **Sync database tables**\n\n    ```sh\n    npm run sync-db\n    ```\n\n6. **Start the server**\n\n    ```sh\n    npm run start\n    ```\n\n    For development with auto-reload:\n\n    ```sh\n    npm run start-watch\n    ```\n\n7. **Verify**\n    - Health check: [http://localhost:3001/health](http://localhost:3001/health)\n    - Swagger docs: [http://localhost:3001/docs/v1](http://localhost:3001/docs/v1)\n    - OpenAPI spec: [http://localhost:3001/docs/v1/spec.json](http://localhost:3001/docs/v1/spec.json)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Docker\n\nRun the entire stack (API + PostgreSQL) with Docker Compose:\n\n```sh\n# Start services\ndocker compose up --build\n\n# Start in background\ndocker compose up --build -d\n\n# Stop services\ndocker compose down\n\n# Stop and remove volumes\ndocker compose down -v\n```\n\nThe Compose file includes:\n\n- **app** — Node API built with multi-stage Dockerfile (non-root user, health check)\n- **db** — PostgreSQL 16 Alpine with persistent volume and health check\n\nEnvironment variables can be overridden via `.env` file or inline:\n\n```sh\nDB_PASSWORD=mysecret PORT=8080 docker compose up --build\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Usage\n\n### Adding a New Resource\n\nFollow this pattern to add a new resource (e.g., `Product`):\n\n1. **Model** — Create `src/api/models/Product.ts` with Sequelize schema\n2. **Repository interface** — Create `src/api/repositories/interfaces/IProductRepository.ts`\n3. **Repository** — Create `src/api/repositories/ProductRepository.ts`\n4. **Service interface** — Create `src/api/services/interfaces/IProductService.ts`\n5. **Service** — Create `src/api/services/ProductService.ts`\n6. **Controller** — Create `src/api/controllers/ProductController.ts`\n7. **Validation** — Add rules in `src/api/middlewares/validator/requirements/`\n8. **Routes** — Create `src/api/routes/v1/products.ts` with inline `@swagger` JSDoc, register in `src/api/routes/v1/index.ts`\n9. **Tests** — Add `__test__/` folders in repositories and services\n\n### Error Handling\n\nUse typed errors in services for proper HTTP status codes:\n\n```typescript\nimport { NotFoundError, ConflictError } from '../../errors/AppError';\n\n// 404 - Resource not found\nthrow new NotFoundError('Product not found');\n\n// 409 - Conflict (duplicate)\nthrow new ConflictError('Product SKU must be unique');\n\n// 401 - Unauthorized\nthrow new UnauthorizedError('Invalid credentials');\n\n// 403 - Forbidden\nthrow new ForbiddenError('Insufficient permissions');\n\n// 422 - Validation error\nthrow new ValidationError('Invalid input data');\n```\n\n### API Responses\n\nControllers use `ApiResponse` for consistent response format:\n\n```typescript\nimport ApiResponse from '../../utils/response/ApiResponse';\n\n// Standard response\nApiResponse.success(res, 'Product created', product, 201);\n\n// Paginated response\nApiResponse.paginated(res, 'Products fetched', paginatedResult);\n```\n\n**Response formats:**\n\n```json\n// Success\n{ \"message\": \"Product created\", \"data\": { ... } }\n\n// Paginated\n{ \"message\": \"Products fetched\", \"items\": [...], \"total\": 50, \"page\": 1, \"limit\": 10, \"totalPages\": 5 }\n\n// Error\n{ \"message\": \"Product not found\", \"statusCode\": 404 }\n```\n\n### Pagination\n\nList endpoints accept query parameters:\n\n```\nGET /api/v1/users?page=2\u0026limit=20\n```\n\nDefault: `page=1`, `limit=10`.\n\n### Available Scripts\n\n| Script                    | Description                       |\n| ------------------------- | --------------------------------- |\n| `npm run start`           | Start the server                  |\n| `npm run start-watch`     | Start with auto-reload (nodemon)  |\n| `npm run build`           | Compile TypeScript to `dist/`     |\n| `npm run build-watch`     | Compile with watch mode           |\n| `npm run test`            | Run tests with coverage           |\n| `npm run test:noCoverage` | Run tests without coverage        |\n| `npm run lint`            | Run ESLint                        |\n| `npm run prettier`        | Format code with Prettier         |\n| `npm run sync-db`         | Sync Sequelize models to database |\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## API Reference\n\n### Health\n\n| Method | Endpoint  | Description                 | Auth |\n| ------ | --------- | --------------------------- | ---- |\n| `GET`  | `/health` | Health check with DB status | No   |\n\n### Authentication\n\n| Method | Endpoint         | Description               | Auth |\n| ------ | ---------------- | ------------------------- | ---- |\n| `POST` | `/api/v1/login`  | Login with email/password | No   |\n| `POST` | `/api/v1/signup` | Register new user         | No   |\n\n### Users\n\n| Method   | Endpoint                        | Description            | Auth  |\n| -------- | ------------------------------- | ---------------------- | ----- |\n| `GET`    | `/api/v1/users?page=1\u0026limit=10` | List users (paginated) | Admin |\n| `POST`   | `/api/v1/users`                 | Create user            | Admin |\n| `GET`    | `/api/v1/users/:id`             | Get user details       | Admin |\n| `PUT`    | `/api/v1/users/:id`             | Update user            | Admin |\n| `DELETE` | `/api/v1/users/:id`             | Delete user            | Admin |\n\n### Roles\n\n| Method | Endpoint        | Description | Auth  |\n| ------ | --------------- | ----------- | ----- |\n| `GET`  | `/api/v1/roles` | List roles  | Admin |\n| `POST` | `/api/v1/roles` | Create role | Admin |\n\n\u003e Use `Authorization: Bearer \u003ctoken\u003e` header for authenticated endpoints.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## OpenAPI Spec\n\nAPI documentation uses **OpenAPI 3.0** with inline `@swagger` JSDoc annotations co-located with route definitions. This means the spec stays in sync with the code automatically.\n\n### Swagger UI\n\nAvailable in development at `/docs/v1`:\n\n```\nhttp://localhost:3001/docs/v1\n```\n\n### JSON Spec Export\n\nGet the raw OpenAPI JSON spec (useful for client SDK generation):\n\n```\nGET http://localhost:3001/docs/v1/spec.json\n```\n\nUse this with tools like:\n\n- [openapi-generator](https://openapi-generator.tech/) — Generate client SDKs in any language\n- [Postman](https://www.postman.com/) — Import collection from OpenAPI spec\n- [Redoc](https://redocly.com/) — Alternative API docs renderer\n\n### Adding Docs to a New Route\n\nAdd `@swagger` JSDoc comments directly above route definitions:\n\n```typescript\n/**\n * @swagger\n * /products:\n *   get:\n *     summary: Get products\n *     description: Get paginated list of products\n *     tags: [Products]\n *     security:\n *       - bearerAuth: []\n *     parameters:\n *       - in: query\n *         name: page\n *         schema:\n *           type: integer\n *           default: 1\n *       - in: query\n *         name: limit\n *         schema:\n *           type: integer\n *           default: 10\n *     responses:\n *       200:\n *         description: Products fetched successfully\n *         content:\n *           application/json:\n *             schema:\n *               $ref: '#/components/schemas/PaginatedResponse'\n */\nproductsRouter.route('/').get(Auth.authenticate, ProductController.getProducts);\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Testing\n\n```sh\n# Run all tests with coverage\nnpm test\n\n# Run without coverage\nnpm run test:noCoverage\n\n# Run specific test file\nnpx jest src/api/services/__test__/UserService.test.ts\n```\n\n### Test Types\n\n| Type            | Location                 | Description                                |\n| --------------- | ------------------------ | ------------------------------------------ |\n| **Unit**        | `services/__test__/`     | Service business logic (mocked repos)      |\n| **Unit**        | `repositories/__test__/` | Repository data access (mocked models)     |\n| **Integration** | `routes/__test__/`       | Full HTTP request → response via supertest |\n\nIntegration tests verify health check, request ID, security headers, authentication enforcement, and input validation.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Project Structure\n\n```\n├── .github/workflows/ci.yml       # GitHub Actions CI pipeline\n├── .husky/                         # Git hooks (pre-commit: lint-staged)\n├── src/\n│   ├── @types/                     # Custom type declarations\n│   ├── api/\n│   │   ├── controllers/            # Request handling, response formatting\n│   │   ├── middlewares/\n│   │   │   ├── auth/               # JWT authentication \u0026 role checking\n│   │   │   ├── handlers/           # Global error handler\n│   │   │   ├── morgan/             # HTTP request logging (with request ID)\n│   │   │   ├── requestId/          # X-Request-Id generation\n│   │   │   └── validator/          # Input validation (express-validator)\n│   │   ├── models/                 # Sequelize models \u0026 type definitions\n│   │   ├── repositories/\n│   │   │   ├── interfaces/         # Repository contracts\n│   │   │   ├── __test__/           # Repository unit tests\n│   │   │   └── *.ts                # Data access layer\n│   │   ├── routes/\n│   │   │   ├── v1/                 # Route definitions with inline @swagger docs\n│   │   │   └── __test__/           # Integration tests (supertest)\n│   │   ├── services/\n│   │   │   ├── interfaces/         # Service contracts\n│   │   │   ├── __test__/           # Service unit tests\n│   │   │   └── *.ts                # Business logic layer\n│   │   └── types/                  # Request DTOs \u0026 pagination types\n│   ├── config/\n│   │   ├── appConfig.ts            # Centralized configuration (CORS, rate limit, DB pool)\n│   │   └── validateEnv.ts          # Startup environment validation\n│   ├── constants/                  # App-wide constants\n│   ├── database/                   # DB connection (with pool config) \u0026 table sync\n│   ├── errors/\n│   │   └── AppError.ts             # Typed error class hierarchy\n│   ├── utils/\n│   │   ├── jwt/                    # JWT sign/verify helpers\n│   │   ├── logger/                 # Winston logger (JSON prod / colorized dev)\n│   │   ├── response/               # ApiResponse utility\n│   │   ├── swagger/                # OpenAPI config (scans route files)\n│   │   └── helpers.ts              # Misc utilities\n│   ├── server.ts                   # Express app (helmet, rate limit, CORS, health check)\n│   └── index.ts                    # Entry point (graceful shutdown)\n├── Dockerfile                      # Multi-stage build, non-root user\n├── docker-compose.yml              # App + PostgreSQL 16\n├── .dockerignore\n├── eslint.config.mjs               # ESLint v9 flat config\n├── jest.config.json                # Jest + ts-jest config\n├── tsconfig.json                   # TypeScript config (ES2022, Node16)\n└── package.json\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## Contributing\n\nContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\n1. Fork the Project\n2. Create your Feature Branch (`git checkout -b feature/feature-name`)\n3. Commit your Changes (`git commit -m 'Add some feature-name'`)\n4. Push to the Branch (`git push origin feature/feature-name`)\n5. Open a Pull Request\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES --\u003e\n\n[contributors-shield]: https://img.shields.io/github/contributors/arifintahu/project-structure-api.svg?style=for-the-badge\n[contributors-url]: https://github.com/arifintahu/project-structure-api/graphs/contributors\n[forks-shield]: https://img.shields.io/github/forks/arifintahu/project-structure-api.svg?style=for-the-badge\n[forks-url]: https://github.com/arifintahu/project-structure-api/network/members\n[stars-shield]: https://img.shields.io/github/stars/arifintahu/project-structure-api.svg?style=for-the-badge\n[stars-url]: https://github.com/arifintahu/project-structure-api/stargazers\n[issues-shield]: https://img.shields.io/github/issues/arifintahu/project-structure-api.svg?style=for-the-badge\n[issues-url]: https://github.com/arifintahu/project-structure-api/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farifintahu%2Fproject-structure-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farifintahu%2Fproject-structure-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farifintahu%2Fproject-structure-api/lists"}