InkSync is a modular full-stack blogging platform built to simulate the separation of concerns between API services and user-facing interfaces. Designed with scalability, maintainability, and CI/CD automation in mind, the project consists of:
- A fully documented RESTful API with Swagger
- A user-friendly frontend UI to create, edit, and delete posts
- In-memory data handling for simplified backend logic
- Two independently deployed services via Azure App Services
- CI/CD pipelines via GitHub Actions
- 📰 InkSync UI
- 🖋️ InkSync API
- 📖 Swagger Docs
- 🛠 GitHub Repo
- 🛠 Azure DevOps
InkSync was designed to:
- Demonstrate real-world REST API design and frontend-backend separation
- Practice modularization by keeping API and UI codebases independent
- Work with Swagger/OpenAPI for automated documentation
- Simulate client-server communication via Axios and Express
- Set up reliable CI/CD pipelines using GitHub Actions
- Experiment with multi-app deployment on Azure App Services
- API Service (
/api) handles all CRUD operations for blog posts - UI Service (
/ui) fetches and manipulates post data via HTTP requests to the API - Separate package.json, deployment settings, and hosting plans
- Routes:
GET /posts,GET /posts/:id,POST /posts,PATCH /posts/:id,DELETE /posts/:id - All data is stored in an in-memory array to mimic backend behavior
- JSON responses returned using
res.json() - Auto-incremented
idand generateddatefields
- API is fully documented with OpenAPI 3.0 specs
- Accessible at
/api-docs - Schemas:
PostandPostInput - All methods, parameters, and response types defined with live examples
-
UI built using Express, EJS, and Axios
-
Routes:
/- Homepage (list all posts)/new- Create post form/edit/:id- Edit post form
-
Includes cancel buttons, form validations, and dynamic rendering
| Layer | Tech Stack |
|---|---|
| Backend | Node.js, Express |
| Frontend | Express, EJS, CSS, Axios |
| API Docs | Swagger UI, OpenAPI |
| Deployment | Azure App Services, GitHub Actions |
| Versioning | GitHub + Azure Repos (read-only) |
InkSync
├── .github/workflows
│ ├── api.yml # GitHub Actions for API deployment
│ └── ui.yml # GitHub Actions for UI deployment
├── api
│ ├── data/posts.js # In-memory blog post data
│ ├── public/styles/index.css # API styles
│ ├── views/index.ejs # API landing page view
│ ├── index.js # API server entry point
│ ├── package.json # API dependencies
│ ├── package-lock.json # API lockfile
│ └── swagger.json # OpenAPI documentation
├── ui
│ ├── public/styles/index.css # UI styles
│ ├── views/index.ejs # UI homepage
│ ├── views/modify.ejs # Create/Edit post view
│ ├── index.js # UI server entry point
│ ├── package.json # UI dependencies
│ └── package-lock.json # UI lockfile
├── README.md # Project documentation
└── DeploymentChallenges.md # Detailed deployment log and postmortem
InkSync is deployed as two independent Node.js applications using Azure App Services, with automated CI/CD handled by GitHub Actions, and Azure DevOps retained for source control tracking and potential future CI/CD use.
-
Created Azure App Services
-
Two App Service instances were provisioned:
InkSync-API— Hosts the RESTful APIInkSync-UI— Hosts the frontend blog interface
-
Each service was configured with:
-
Runtime: Node.js 18
-
Startup Command (set in Azure Portal → Configuration → General Settings):
cd api && npm install && npm start # for API cd ui && npm install && npm start # for UI
-
-
-
Version Control Configuration
-
Both GitHub and Azure Repos were added as remotes:
- GitHub is now the primary development + CI/CD platform
- Azure Repos is kept for version control backup and logs
-
Remote setup:
git remote add origin https://github.com/junaid-mohammad/InkSync.git git remote add azure https://Junaid-Arif@dev.azure.com/Junaid-Arif/InkSync/_git/InkSync
-
Development is pushed to both remotes to maintain visibility:
git add . git commit -m "Deploy update" git push origin main # Triggers GitHub Actions git push azure main # Pushes to Azure Repos for tracking
-
-
GitHub Actions CI/CD Configuration
- Two workflows created in
.github/workflows/:api.yml: Deploys API service onapi/**changesui.yml: Deploys UI service onui/**changes
- Each uses the
azure/webapps-deploy@v3GitHub Action with deployment secrets:INKSYNC_API_PUBLISH_PROFILEINKSYNC_UI_PUBLISH_PROFILE
- Secrets contain raw publish profile XML downloaded from Azure → App Service → Deployment Center → Manage publish profile.
- Two workflows created in
-
Environment Variables Setup
- Automatically handled:
PORTis injected by Azure and used in both services viaprocess.env.PORT
- Manually added to
InkSync-UIApp Service:- Key:
API_URL - Value:
https://inksync-api.azurewebsites.net
- Key:
- Automatically handled:
-
Lockfile Warning Resolution
- Initial deployments raised a
Dependencies lock file is not foundwarning. - Resolved by running:
npm install && npm i --package-lock-only
- Initial deployments raised a
-
Workflow Trigger Note
- GitHub Actions workflows are configured with
paths: [api/**]orpaths: [ui/**] - Changes to files outside these directories (e.g., README.md) will not trigger deployment
- Manual trigger can be used from the Actions tab → Select workflow → “Run workflow”
- GitHub Actions workflows are configured with
-
Troubleshooting Learnings
-
Deployment Stalling: Occurs if App Service is restarted or modified during workflow deployment.
-
Fix:
- Manually restart both App Services from Azure Portal.
- Wait ~1–2 minutes for SCM to stabilize.
- Re-run the GitHub workflow job from the Actions tab.
-
In-Memory Persistence: Posts remain live until App Service is manually restarted or redeployed (cold start or crash will also reset them).
-
Note: A detailed document DepoloymentChallenges.md is added to the repository documenting all the Challenges and Learnings in trying to deploy this app.
-
- GitHub = primary CI/CD (actions, secrets, workflows)
- Azure Repos = secondary source control (no pipelines active)
- Azure App Services = deployment targets (manual config for runtime, env, and start script)
- Publish profile authentication = used for secure deployment
Note: Blog data is not persisted. Posts are stored in a server memory array and:
- Will survive page refreshes
- Will persist until App Service is restarted or redeployed
- Are wiped on manual restart or redeployment
🔒 Security Note: There is no authentication. Anyone with frontend access can read/write/delete posts. For production:
- Implement authentication (JWT/OAuth)
- Use a real database (e.g. MongoDB, PostgreSQL)
- Add RBAC for post management
-
Includes:
- All endpoints with
GET,POST,PATCH, andDELETE - Parameters, schemas, status codes, and example payloads
- Models for
PostandPostInput
- All endpoints with
- CI/CD with GitHub Actions and App Services.
- Managing secrets and workflows per subfolder.
- Debugging Azure SCM stalls and cold starts.
- Hybrid version control setup using GitHub + Azure Repos.
- Real-world monorepo challenges with multi-app deployment.
- Managing modular Node.js apps and routing independently
- Using EJS to dynamically display post content
- How to properly separate frontend and API responsibilities
- Building Swagger/OpenAPI 3.0 schemas from scratch
This project was built as a portfolio/demo API. Feel free to fork it, explore, remix, or suggest improvements!
This project is open-source and free to use for personal or educational purposes.
Built by Junaid Arif. Inspired by real-world web application architecture and designed as a scalable demo of full-stack app architecture and CI/CD in the cloud.