Minimal Blog

Click to zoom
Minimal Blog
A complete blog API backend with authentication, CRUD endpoints, and database integration using Habits bits.
Build a production-ready blog API in minutes with the Minimal Blog example. This showcases how Habits can create full backend applications with minimal code.
Features
- User Authentication: JWT-based login and registration
- Blog Posts CRUD: Create, read, update, and delete posts
- Database Integration: SQLite/PostgreSQL with automatic migrations
- API Documentation: Well-structured RESTful endpoints
Perfect for learning how to build API backends with Habits, or as a starter template for your own content management systems.
Run Your .habit File
Run on Mobile
- [ ] Download the Cortex App from store or the downloads page
- [ ] Open the Cortex App on your device
- [ ] Tap "Open Habit" or "+" button
- [ ] Select your
.habitfile from your device storage - [ ] The habit will be loaded and ready to run
Run on Desktop
- [ ] Download the Cortex App for your platform from the downloads page
- [ ] Install and open the Cortex App
- [ ] Click "Open Habit" or drag & drop your
.habitfile - [ ] The habit will be loaded and ready to run
- [ ] Optional: Place a
.envfile in the same directory as your.habitfile to override environment variables
Run on Server
Run your .habit file as a server using the Cortex CLI:
bash
# Install and run in one command
npx @ha-bits/cortex --config ./your-app.habit- [ ] Make sure Node.js 20+ is installed
- [ ] Run the command above with your
.habitfile path - [ ] Server will start on the specified port (default: 3000)
- [ ] Access the app at
http://localhost:3000 - [ ] Optional: Place a
.envfile next to your.habitfile - it will automatically override any embedded environment variables
Run Serverless
For serverless or containerized deployments, we recommend using Docker:
bash
# Using Docker (recommended for serverless)
docker run -p 3000:3000 -v $(pwd)/your-app.habit:/app/habit.habit \
node:20-alpine npx @ha-bits/cortex --config /app/habit.habit --host 0.0.0.0Or create a Dockerfile:
dockerfile
FROM node:20-alpine
WORKDIR /app
COPY your-app.habit ./
COPY .env ./ # Optional: include environment variables
RUN npm install -g @ha-bits/cortex
EXPOSE 3000
CMD ["cortex", "--config", "./your-app.habit", "--host", "0.0.0.0"]- [ ] Create a Dockerfile or use the Docker run command above
- [ ] Deploy to your preferred cloud provider (AWS, GCP, Azure, etc.)
- [ ] Configure environment variables via your cloud provider's secrets management
- [ ] Set up health checks at
/habits/base/apiendpoint
Workflow Visualization
Requirements
- Node.js 18+
Key Files
yaml
version: "1.0"
workflows:
- id: login
path: ./habits/login.yaml
enabled: true
- id: get-posts
path: ./habits/get-posts.yaml
enabled: true
- id: get-post
path: ./habits/get-post.yaml
enabled: true
- id: create-post
path: ./habits/create-post.yaml
enabled: true
- id: delete-post
path: ./habits/delete-post.yaml
enabled: true
- id: send-contact
path: ./habits/send-contact.yaml
enabled: true
server:
port: 13000
host: "0.0.0.0"
frontend: ./frontend
openapi: true
logging:
level: info
outputs: [console]
format: text
colorize: trueexample
# Minimal Blog Example Environment Variables
# Copy this file to .env and fill in your values
# SMTP configuration for contact form
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-smtp-username
SMTP_PASSWORD=your-smtp-password
SMTP_FROM=blog@example.com
CONTACT_EMAIL=contact@example.com
# Authentication
JWT_SECRET=your-jwt-secret-key-change-this-in-productionyaml
id: create-post
name: Create New Post
description: Create a new blog post (admin function - requires authentication)
input:
- id: title
type: string
required: true
- id: content
type: string
required: true
- id: status
type: string
required: false
nodes:
# Verify JWT from auth_token cookie
- id: verify-auth
type: bits
data:
framework: bits
source: npm
module: "@ha-bits/bit-auth"
operation: verify
params:
token: "{{habits.cookies.auth_token}}"
secret: "{{habits.env.JWT_SECRET}}"
- id: insert-post
type: bits
data:
framework: bits
source: npm
module: "@ha-bits/bit-database"
resource: insert
operation: insert
params:
collection: "posts"
document:
title: "{{habits.input.title}}"
content: "{{habits.input.content}}"
status: "published"
createdAt: "{{habits.now}}"
author: "{{verify-auth.payload.username}}"
edges:
- source: verify-auth
target: insert-post
output:
authorized: "{{verify-auth.valid}}"
success: "{{insert-post.success}}"
id: "{{insert-post.id}}"
post: "{{insert-post.document}}"
authError: "{{verify-auth.error}}"yaml
id: delete-post
name: Delete Post
description: Delete a blog post by ID (admin function - requires authentication)
input:
- id: postId
type: string
required: true
nodes:
# Verify JWT from auth_token cookie
- id: verify-auth
type: bits
data:
framework: bits
source: npm
module: "@ha-bits/bit-auth"
operation: verify
params:
token: "{{habits.cookies.auth_token}}"
secret: "{{habits.env.JWT_SECRET}}"
- id: remove-post
type: bits
data:
framework: bits
source: npm
module: "@ha-bits/bit-database"
resource: delete
operation: delete
params:
collection: "posts"
key: "{{habits.input.postId}}"
edges:
- source: verify-auth
target: remove-post
output:
authorized: "{{verify-auth.valid}}"
success: "{{remove-post.success}}"
deleted: "{{remove-post.deleted}}"
authError: "{{verify-auth.error}}"yaml
id: get-post
name: Get Single Post
description: Retrieve a single post by its ID
input:
- id: postId
type: string
required: true
nodes:
- id: fetch-post
type: bits
data:
framework: bits
source: npm
module: "@ha-bits/bit-database"
resource: get
operation: get
params:
collection: "posts"
key: "{{habits.input.postId}}"
edges: []
output:
found: "{{fetch-post.found}}"
post: "{{fetch-post.value}}"Quick Start
Run using the Habits CLI wrapper, recommended if you develop local Habits
# First, download the example files
npx habits@latest cortex --config ./minimal-blog/stack.yaml