{"id":51370853,"url":"https://github.com/amir-zouerami/schematica-api","last_synced_at":"2026-07-03T06:31:08.276Z","repository":{"id":320764482,"uuid":"1078470828","full_name":"Amir-Zouerami/schematica-api","owner":"Amir-Zouerami","description":"💥 Schematica V2.0 - A Collaborative API Documentation Platform.","archived":false,"fork":false,"pushed_at":"2025-11-29T19:55:01.000Z","size":792,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-30T21:31:01.305Z","etag":null,"topics":["api-documentation","documentation-tool","nestjs","openapi","openapi3","swagger","swagger-ui"],"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/Amir-Zouerami.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":"2025-10-17T19:36:46.000Z","updated_at":"2025-11-29T19:55:06.000Z","dependencies_parsed_at":"2025-10-25T19:26:15.548Z","dependency_job_id":null,"html_url":"https://github.com/Amir-Zouerami/schematica-api","commit_stats":null,"previous_names":["amir-zouerami/schematica-api"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Amir-Zouerami/schematica-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amir-Zouerami%2Fschematica-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amir-Zouerami%2Fschematica-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amir-Zouerami%2Fschematica-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amir-Zouerami%2Fschematica-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Amir-Zouerami","download_url":"https://codeload.github.com/Amir-Zouerami/schematica-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amir-Zouerami%2Fschematica-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35075799,"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-07-03T02:00:05.635Z","response_time":110,"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":["api-documentation","documentation-tool","nestjs","openapi","openapi3","swagger","swagger-ui"],"created_at":"2026-07-03T06:31:07.783Z","updated_at":"2026-07-03T06:31:08.239Z","avatar_url":"https://github.com/Amir-Zouerami.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🏗️ Schematica Backend API\n\n![Schematica Backend Cover](https://github.com/user-attachments/assets/e73d72fd-3d32-4300-b8c7-b023c3e687ec)\n\n[![CI](https://github.com/amir-zouerami/schematica-api/actions/workflows/ci.yml/badge.svg?branch=main\u0026style=for-the-badge)](https://github.com/amir-zouerami/schematica-api/actions/workflows/ci.yml)\n[![License](https://img.shields.io/badge/License-GPLv3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0)\n\n\u003e **The high-performance, event-driven engine powering the Schematica platform.**\n\n**Schematica** is a collaborative API design and documentation workspace. This repository contains the **Backend API**, engineered to provide a robust, scalable foundation for managing OpenAPI specifications, handling real-time concurrency, and enforcing granular access control.\n\nIt is built as a showcase of modern backend engineering principles, prioritizing **Type Safety**, **Clean Architecture**, and **Developer Experience**.\n\n\u003e **Note:** This repository works in tandem with the [Schematica Frontend](https://github.com/Amir-Zouerami/schematica-frontend).\n\u003e This project was originally built as an internal tool to solve specific workflow friction points at my previous company. It is now provided as \"source-available\" for educational purposes.\n\n---\n\n## 🏗️ Architectural Overview\n\nThe Schematica API avoids the \"Spaghetti Monolith\" trap by adopting a **Modular, Event-Driven Architecture**.\n\n### 1. Domain-Driven Modules\nThe application structure mirrors the business domain. Code is organized into cohesive modules (`ProjectsModule`, `LockingModule`) rather than technical layers. This ensures that related logic sits together, making the codebase intuitive to navigate and easy to scale.\n\n### 2. Decoupled Event-Driven Core\nA core principle of this system is the strict separation of **Primary Business Logic** from **Side Effects**. We utilize `@nestjs/event-emitter` to achieve this decoupling.\n\n*   **The Problem:** In many apps, a `createProject` service method grows to 100 lines because it has to send emails, write audit logs, and notify Slack.\n*   **Our Solution:** The `ProjectsService` performs **only** the database transaction and emits a typed event (`PROJECT_CREATED`).\n*   **The Benefit:** Independent Listeners handle the side effects. If the Notification Service fails, the Audit Log is still written, and the User's request still succeeds. This results in a highly resilient system.\n\n### 3. Hybrid Access Control (RBAC + ABAC)\nSecurity is implemented in two layers for defense-in-depth:\n1.  **Coarse-Grained (`RolesGuard`):** Protects entire routes based on a user's system-wide role (e.g., only an `admin` can access `/admin/*`).\n2.  **Fine-Grained (`AccessControlService`):** Implements Attribute-Based Access Control (ABAC). It evaluates complex conditions at runtime—checking Project Ownership, Team Membership, and Deny Lists—to authorize specific resources.\n\n### 4. High-Performance State Management\nFor features requiring high-frequency updates (like **Collaborative Editing Locks**), we bypass the database entirely. The `LockingService` manages ephemeral state using in-memory structures, ensuring the real-time experience remains distinct from persistent storage latency.u\n\n---\n\n## ✨ Key Features\n\n### 🔐 Security \u0026 Access Control\n*   **Hybrid Auth:** Supports both **Local Strategy** (Bcrypt hashing) and **OAuth2** (GitLab) via Passport.js.\n*   **Secure Sessions:** Uses `fastify-secure-session` with `@fastify/cookie` for robust session management.\n*   **ABAC (Attribute-Based Access Control):** Beyond simple Roles (`admin` vs `user`), we implement fine-grained guards (`ProjectOwnerGuard`, `ProjectViewerGuard`) that evaluate ownership and team membership at runtime.\n*   **Environment Vault:** Project secrets (API Keys, Tokens) are encrypted at rest using `AES-256-GCM` before entering the database.\n\n### ⚡ Real-Time Collaboration\n*   **Pessimistic Locking:** Prevents \"last-write-wins\" race conditions. When a user edits an endpoint, a WebSocket event locks that resource globally. Other users see the lock status update instantly via `Socket.IO`.\n*   **Live Notifications:** mentions (`@username`) in notes trigger instant alerts to connected clients.\n\n### 🛠️ API Governance Engine\n*   **Spectral Linting:** Integrated `@stoplight/spectral` engine to lint OpenAPI specs against a custom ruleset (`.spectral.yaml`) on every save or import.\n*   **Spec Reconciliation:** A smart diffing engine that compares an imported OpenAPI JSON against the database state, determining exactly which endpoints to Create, Update, or Delete (Soft Sync).\n\n### 🚀 Dynamic Mock Server\n*   **Zero-Config Mocking:** The API can instantly generate mock responses for *any* endpoint defined in a project.\n*   **Faker Integration:** Leverages `json-schema-faker` and `@faker-js/faker` to generate realistic, schema-compliant data (names, emails, UUIDs) based on the OpenAPI schema definition.\n*   **Locale \u0026 State Support:** Clients can request specific HTTP status codes (e.g., test a `404`) or locales (e.g., `fa`, `en`) via headers.\n\n---\n\n## 📚 API Collection\n\nFor a quick start, import the official Postman Collection. It includes environment variables and pre-configured requests for Auth, Projects, and Mocking.\n\n\u003ca href=\"https://raw.githubusercontent.com/Amir-Zouerami/schematica-api/refs/heads/main/docs/postman/Schematica%20v2.postman_collection.json\" target=\"_blank\"\u003e\u003cimg src=\"https://run.pstmn.io/button.svg\" alt=\"Run In Postman\" style=\"width: 128px; height: 32px;\"\u003e\u003c/a\u003e\n\n\n---\n\n## 🛠 Tech Stack\n\nWe chose a stack that balances developer ergonomics with raw performance.\n\n| Category          | Technology            | Reasoning                                                                                                                 |\n| :---------------- | :-------------------- | :------------------------------------------------------------------------------------------------------------------------ |\n| **Runtime**       | **Bun**               | Chosen for its ultra-fast startup time (critical for dev loops) and native TypeScript support.                            |\n| **Framework**     | **NestJS**            | Provides the modular structure and dependency injection container needed for enterprise-grade apps.                       |\n| **HTTP Adapter**  | **Fastify**           | Replaces Express.js to maximize throughput and minimize overhead.                                                         |\n| **Database**      | **SQLite** (Dev)      | Keeping the DB portable allows for zero-setup ease of use. Can be swapped for PostgreSQL in production via Prisma.        |\n| **ORM**           | **Prisma**            | Best-in-class type safety. The generated client ensures DB queries align perfectly with TypeScript interfaces.            |\n| **Real-time**     | **Socket.IO**         | Manages WebSocket namespaces and rooms for granular update broadcasting.                                                  |\n| **Documentation** | **Swagger / OpenAPI** | The API is self-documenting. We use `class-validator` decorators to drive both runtime validation and Swagger generation. |\n| **Linting**       | **Spectral**          | An open-source JSON/YAML linter used to govern API design quality programmatically.                                       |\n\n---\n\n## 📂 Project Structure\n\nThe directory structure follows **Domain-Driven Design (DDD)** principles. We avoid grouping files by type (controllers/services) and instead group them by **Module/Domain**.\n\n```text\nsrc/\n├── access-control/      # 🛡️ ABAC Logic (Permissions service)\n├── api-linting/         # 📏 Spectral wrapper service for OAS validation\n├── audit/               # 📋 Event listeners for Audit Logging\n├── auth/                # 🔐 Passport Strategies (JWT, Local, GitLab)\n├── changelog/           # 📜 Event listeners for Changelog generation\n├── common/              # 🧱 Shared Kernel (Guards, Interceptors, Filters, Utils)\n├── config/              # ⚙️ Type-safe configuration namespace\n├── encryption/          # 🔐 AES-256-GCM encryption service for Secrets\n├── locking/             # 🚦 In-Memory resource locking (Services + Gateway)\n├── mock-server/         # 🎭 Dynamic Mocking Engine (Faker + JSON Schema)\n├── notifications/       # 🔔 Notification distribution logic\n├── projects/            # 📦 Core Domain: Projects (Aggregates Endpoints, Envs)\n│   ├── endpoints/       #    - Sub-domain: API Endpoints\n│   ├── environments/    #    - Sub-domain: Env Variables\n│   ├── spec-builder/    #    - Logic to assemble DB records into OpenAPI JSON\n│   └── spec-reconcile/  #    - Logic to diff JSON against DB records\n└── main.ts              # 🚀 Application Bootstrap\n```\n\n---\n\n## 🏗️ Architectural Deep Dives\n\n### 1. Hybrid Access Control (RBAC + ABAC)\nSecurity is implemented in layers for defense-in-depth:\n\n1.  **Route Level (RBAC):** The `RolesGuard` protects entire controllers based on system roles.\n    ```typescript\n    @Roles(Role.admin) // Only Admins can touch this\n    @Controller('admin/users')\n    ```\n2.  **Resource Level (ABAC):** The `AccessControlService` performs logic-heavy checks. It inspects the `Project`, the `User`, and their `TeamMembership` to determine access (Owner vs. Viewer).\n    ```typescript\n    // Inside ProjectOwnerGuard\n    const canOwn = await this.accessControlService.canOwnProject(user, projectId);\n    ```\n\n### 2. The \"Side-Effect\" Architecture\nTo keep business logic clean, we strictly separate **Actions** from **Reactions** using `EventEmitter2`.\n\n*   **Scenario:** A user updates an endpoint's status.\n*   **Service Layer:** Updates the database record. Emits `EndpointEvent.STATUS_UPDATED`. Returns the result.\n*   **Audit Listener:** Catches event -\u003e Writes to `AuditLog` table.\n*   **Changelog Listener:** Catches event -\u003e Formats a human-readable message (\"User X changed status to Published\") -\u003e Writes to `Changelog` table.\n*   **Notification Listener:** Catches event -\u003e Checks for watchers -\u003e Dispatches WebSocket message.\n\n**Benefit:** If the Audit Logger fails, the User's request still succeeds. The system is loosely coupled and highly resilient.\n\n### 3. Monolithic Deployment Strategy (The `public/` folder)\nWhile the Frontend and Backend are developed in separate repositories for clear separation of concerns, they are designed to be deployed as a **Single Unit**.\n\nThe `AppModule` is configured to serve static assets from the `public/` directory (excluding the `/api` prefix).\n\n*   **Workflow:**\n    1.  Build the [Schematica Frontend](https://github.com/Amir-Zouerami/schematica-frontend).\n    2.  Place the resulting `dist/` files into `schematica-api/public/`.\n    3.  Start the NestJS server.\n*   **Result:** The NestJS app serves the API on `/api/v2/...` and the React SPA on `/`.\n*   **Why?** This eliminates CORS issues in production, simplifies deployment (one container to manage), and allows cookies to be shared securely between the API and the UI.\n\n### 4. Smart Spec Reconciliation\nImporting an OpenAPI file isn't just a database overwrite. The `SpecReconciliationService` acts as a specialized \"Diff Engine\":\n\n1.  **Normalize:** It flattens the incoming JSON spec into a map of `method:path` keys.\n2.  **Compare:** It fetches existing endpoints from the DB.\n3.  **Decision Matrix:**\n    *   *Match:* Compare signatures. If different, mark for **Update**.\n    *   *New:* Mark for **Create**.\n    *   *Missing:* Mark for **Delete**.\n4.  **Execute:** Runs the calculated changes inside a single Prisma Transaction to ensure atomicity.\n\n---\n\n## 🚀 Getting Started\n\nFollow these steps to get the Schematica platform running locally.\n\n### Prerequisites\n*   **[Bun](https://bun.sh/)** (v1.1+) - The runtime and package manager.\n*   **Git** - Version control.\n*   *(Optional)* **Docker** - If you prefer running a PostgreSQL instance instead of the default SQLite dev database.\n\n### 1. Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/Amir-Zouerami/schematica-api.git\ncd schematica-api\n\n# Install dependencies using Bun\nbun install\n```\n\n### 2. Environment Configuration\n\nCopy the example configuration file. The default settings are tuned for local development.\n\n```bash\ncp .env.example .env\n```\n\n\u003e **🔑 Critical Security Note:**\n\u003e The `.env` file contains the `ENCRYPTION_KEY`. This key is used to encrypt/decrypt sensitive Environment Secrets (API Keys) in the database. If you change this key, all previously encrypted secrets in the DB will become unreadable.\n\n### 3. Database Setup \u0026 Seeding\n\nWe use **Prisma** to manage the schema and seeding. The seed script is comprehensive—it doesn't just add users; it constructs an entire mock ecosystem (Projects, Teams, Endpoints, and encrypted Secrets).\n\n```bash\n# Run migrations and seed the database\nbun run migrate:reset\n```\n\n**What gets seeded?**\n*   **Users:** `amir.zouerami` (Admin), `brooklyn.lee` (Member), `guest.user` (Guest).\n*   **Password:** `password123` (for all seeded users).\n*   **Projects:**\n    *   *Project Nova:* A full public-facing API spec.\n    *   *Project Apollo:* An internal microservice spec.\n*   **Teams:** Engineering hierarchy (Backend, Frontend, Leadership).\n\n### 4. Running the Server\n\n```bash\n# Start in development mode (Hot Reload)\nbun run start:dev\n\n# Start in production mode\nbun run start:prod\n```\n\nThe API will be available at `http://localhost:3000/api/v2`.\nThe Swagger documentation is at `http://localhost:3000/docs`.\n\n---\n\n## 🖥️ Frontend Integration (The \"Public\" Folder)\n\nTo experience the full platform, you need to serve the UI. This backend is configured to serve the Single Page Application (SPA) static files from the `/public` directory.\n\n1.  Clone and build the [Schematica Frontend](https://github.com/Amir-Zouerami/schematica-frontend).\n    ```bash\n    git clone https://github.com/Amir-Zouerami/schematica-frontend.git\n    cd schematica-frontend\n    bun install\n    bun run build\n    ```\n2.  Copy the contents of the frontend `dist/` folder into the backend `public/` folder.\n    ```bash\n    # From the frontend directory\n    cp -r dist/* ../schematica-api/public/\n    ```\n3.  Restart the NestJS server. Access the app at `http://localhost:3000`.\n\n*Note: The API routes are prefixed with `/api/v2`, so they do not conflict with the frontend routing.*\n\n---\n\n## 🚢 Production Deployment\n\nThis project uses **SQLite** in production. While this simplifies infrastructure, it requires specific attention to Data Persistence.\n\n### 💾 Data Persistence (Critical)\n\n**⚠️ STOP AND READ:**\nIf you are deploying to **Docker**, **Kubernetes**, **Render**, **Railway**, or any containerized environment, the filesystem is **ephemeral**.\n\nYou **MUST** mount a **Persistent Volume** for the database file. If you do not, your database (and all user data) will be permanently wiped every time the application restarts or re-deploys.\n\n**Example Configuration:**\n1.  Mount a volume to `/data` inside your container.\n2.  Set your `DATABASE_URL` to point to that volume.\n\n```env\n# Point to the mounted volume directory\nDATABASE_URL=\"file:/data/production.db\"\n```\n\n### 🔑 Environment Configuration\n\nCreate a specific `.env.prod` file for production. This file is automatically picked up by the production scripts (`start:prod`, `migrate:prod`).\n\nEnsure these variables are set in your production environment secrets:\n\n| Variable                 | Value                | Description                                                                          |\n| :----------------------- | :------------------- | :----------------------------------------------------------------------------------- |\n| `NODE_ENV`               | `production`         | Optimizes NestJS for performance.                                                    |\n| `DATABASE_URL`           | `file:/data/prod.db` | **Must be on a persistent volume.**                                                  |\n| `ENCRYPTION_KEY`         | *(32-byte hex)*      | **CRITICAL.** Used to encrypt Project Secrets. If lost, secrets cannot be recovered. |\n| `JWT_SECRET`             | *(Random string)*    | A strong, long random string for signing auth tokens.                                |\n| `INITIAL_ADMIN_USERNAME` | `admin`              | The username for the system super-admin.                                             |\n| `INITIAL_ADMIN_PASSWORD` | `securePass!`        | The initial password for the super-admin.                                            |\n\n### 🚀 Build \u0026 Deploy Sequence\n\nIn production, we do not use the development seed. Instead, we use a specialized **Production Seed** that safely bootstraps the Root Admin without overwriting data.\n\nRun these commands in your deployment pipeline (or Docker `CMD`):\n\n```bash\n# 1. Install \u0026 Build\nbun install --frozen-lockfile\nbun run build\n\n# 2. Database Bootstrapping\n# Applies schema changes and ensures Root Admin exists.\nbun run migrate:prod\nbun run seed:prod\n\n# 3. Start the Server\nbun run start:prod\n```\n\n### 🧪 Testing Production Locally\n\nIf you want to simulate the production build locally, simply create a `.env.prod` file and use the dedicated scripts:\n\n```bash\n# These scripts automatically load .env.prod\nbun run migrate:prod\nbun run seed:prod\nbun run start:prod\n```\n\nTo **reset** the production database (wipes data and restores Admin user only):\n```bash\nbun run prod:danger:reset\n```\n\n### 👑 First Login\n\n1.  Navigate to your deployment URL.\n2.  Log in using the credentials you defined in `INITIAL_ADMIN_USERNAME` and `INITIAL_ADMIN_PASSWORD`.\n3.  You now have full **Admin** access to create teams, projects, and invite other users.\n\n---\n\n## 🤝 Contribution Policy\n\n**This project is provided as \"Source-Available\" software.**\n\nIt serves three primary purposes:\n1.  **A Portfolio Piece:** Demonstrating high-level architectural decisions, strict typing, and modern backend patterns.\n2.  **Helping The Community:** It gives back to the community i hold so dearly, the open-source community. If you need such a platform for you company, feel free to use it.\n3.  **A Reference Implementation:** Helping other developers learn how to build robust, event-driven systems with NestJS and Prisma.\n\n**⚠️ I am NOT accepting Pull Requests.**\n\nThis was originally an internal tool built for a specific company context and it's being actively used to this day. While I have open-sourced the code for educational purposes, I am not maintaining it as a community-driven project.\n\n**You are highly encouraged to:**\n*   🔱 **Fork** the repository.\n*   🔧 **Modify** it to fit your own needs.\n*   💡 **Use** the patterns found here in your own projects.\n\n---\n\n## 📄 License\n\nThis project is licensed under the **GNU General Public License v3.0**.\n\n\u003cbr /\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003csub\u003eBuilt with 💙, strictly typed, and engineered to last.\u003c/sub\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famir-zouerami%2Fschematica-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famir-zouerami%2Fschematica-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famir-zouerami%2Fschematica-api/lists"}