Skip to main content

Release v1.0.1: CI/CD Simplification

· 7 min read
Eduardez
MoLOS Lead Developer

We're excited to announce MoLOS v1.0.1, a maintenance release focused on simplifying our CI/CD workflows, improving manual release processes, and enhancing production Docker builds. This release makes it easier to maintain and deploy MoLOS while maintaining all the stability of v1.0.0.

What's New in v1.0.1

CI/CD Simplification

We've simplified our CI/CD workflows by removing unnecessary pipelines:

# .github/workflows/ci.yml
name: CI

on:
push:
branches: [develop, main]
pull_request:
branches: [develop, main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Install dependencies
run: pnpm install

- name: Build
run: pnpm build

- name: Type check
run: pnpm typecheck

Removed Workflows

The following workflows have been removed to simplify operations:

  • .github/workflows/release.yml - Automated releases
  • .github/workflows/test.yml - Separate test pipeline

These have been consolidated into the main CI workflow and manual release process.

Manual Release Workflow

We've moved to a manual release workflow for better control:

# Create a release
npm run release

# This will:
# 1. Run all tests
# 2. Update version numbers
# 3. Generate changelog
# 4. Create git tag
# 5. Push to GitHub
# 6. Create GitHub release

Release Script

The release script automates the manual process:

// scripts/release.ts
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

async function release() {
console.log('Starting release process...');

// Run tests
console.log('Running tests...');
await execAsync('pnpm test');

// Build project
console.log('Building project...');
await execAsync('pnpm build');

// Type check
console.log('Type checking...');
await execAsync('pnpm typecheck');

// Get current version
const { version } = JSON.parse(
await fs.readFile('package.json', 'utf-8')
);

// Create git tag
console.log(`Creating tag v${version}...`);
await execAsync(`git tag -a v${version} -m "Release v${version}"`);

// Push tag
console.log('Pushing tag...');
await execAsync('git push origin v${version}');

// Create GitHub release
console.log('Creating GitHub release...');
await execAsync(`gh release create v${version} --notes "Release v${version}"`);

console.log(`✓ Release v${version} complete!`);
}

release().catch(console.error);

Production Docker Build Improvements

Multi-Stage Build Optimization

We've optimized the production Docker build with better layer caching:

FROM node:20-alpine AS base

# Install build dependencies
RUN apk add --no-cache \
ca-certificates \
dumb-init \
gosu

WORKDIR /app

# Copy dependency files
COPY package.json pnpm-lock.yaml ./
RUN corepack enable pnpm && \
pnpm install --frozen-lockfile

FROM base AS build

# Copy source code
COPY . .

# Build application
RUN pnpm build

FROM node:20-alpine AS production

# Install runtime dependencies only
RUN apk add --no-cache \
ca-certificates \
dumb-init \
gosu

# Create non-root user
RUN addgroup -g 1001 -S molos && \
adduser -S -u 1001 -G molos molos

WORKDIR /app

# Copy built application
COPY --from=build --chown=molos:molos /app/dist ./dist
COPY --from=build --chown=molos:molos /app/node_modules ./node_modules
COPY --from=build --chown=molos:molos /app/package.json ./package.json

# Copy entrypoint
COPY --chown=molos:molos docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

# Switch to non-root user
USER molos

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

# Expose port
EXPOSE 3000

# Set environment
ENV NODE_ENV=production

# Use dumb-init for proper signal handling
ENTRYPOINT ["dumb-init", "--"]
CMD ["docker-entrypoint.sh", "node", "dist/index.js"]

Docker Compose Configuration

Enhanced Docker Compose for production:

version: '3.8'

services:
molos:
image: molos-app:v1.0.1
container_name: molos
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- ORIGIN=${ORIGIN:-https://molos.example.com}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- DATABASE_URL=/data/molos.db
volumes:
- molos-data:/data
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

volumes:
molos-data:
driver: local

Module Improvements

Module Version Bump

We've bumped active module versions:

// modules.config.ts
export const modulesConfig = {
production: {
modules: [
{
id: 'molos-tasks',
repository: 'https://github.com/MoLOS-App/Modules/MoLOS-Tasks',
tag: 'v1.0.3', // Updated from v1.0.2
enabled: true
},
{
id: 'molos-notes',
repository: 'https://github.com/MoLOS-App/Modules/MoLOS-Notes',
tag: 'v1.0.1', // Updated from v1.0.0
enabled: true
}
]
}
};

Module Loading Refinements

Improved module loading and scoping logic:

// server/modules/loader.ts
export async function loadModule(moduleConfig: ModuleConfig) {
// Validate module configuration
const validation = await validateModule(moduleConfig);
if (!validation.valid) {
throw new ModuleLoadError(
`Module ${moduleConfig.id} is invalid: ${validation.errors.join(', ')}`
);
}

// Load module metadata
const metadata = await getModuleMetadata(moduleConfig);

// Initialize module
const module = await initializeModule(metadata);

// Apply module scoping
await applyModuleScoping(module);

console.log(`✓ Loaded module: ${metadata.name} v${metadata.version}`);

return module;
}

MCP Refinements

Auth Key Renaming

We renamed API keys to auth keys for clarity:

// Renamed from apiKey to authKey
export interface MCPAuthKey {
id: string;
name: string;
authKeyHash: string; // Previously apiKeyHash
scopes: string[];
expiresAt: Date | null;
createdAt: Date;
}

MCP Configuration UI

Enhanced MCP configuration in admin settings:

<!-- src/routes/admin/mcp/+page.svelte -->
<script lang="ts">
import MCPSettings from './MCPSettings.svelte';
import AuthKeys from './AuthKeys.svelte'; // Previously APIKeys

let activeTab = 'settings';
</script>

<div class="mcp-admin">
<nav class="tabs">
<button
class="tab {activeTab === 'settings' ? 'active' : ''}"
onclick={() => activeTab = 'settings'}
>
Settings
</button>
<button
class="tab {activeTab === 'keys' ? 'active' : ''}"
onclick={() => activeTab = 'keys'}
>
Auth Keys
</button>
</nav>

{#if activeTab === 'settings'}
<MCPSettings />
{:else if activeTab === 'keys'}
<AuthKeys />
{/if}
</div>

Admin Settings Refactoring

We extracted admin settings into modular components:

<!-- src/routes/admin/+page.svelte -->
<script lang="ts">
import GeneralSettings from './components/GeneralSettings.svelte';
import AuthSettings from './components/AuthSettings.svelte';
import ModuleSettings from './components/ModuleSettings.svelte';
import MCPSettings from './components/MCPSettings.svelte';

let activeSection = 'general';

const sections = [
{ id: 'general', label: 'General', component: GeneralSettings },
{ id: 'auth', label: 'Authentication', component: AuthSettings },
{ id: 'modules', label: 'Modules', component: ModuleSettings },
{ id: 'mcp', label: 'MCP', component: MCPSettings }
];
</script>

<div class="admin-page">
<aside class="sidebar">
<nav>
{#each sections as section}
<button
class="nav-item {activeSection === section.id ? 'active' : ''}"
onclick={() => activeSection = section.id}
>
{section.label}
</button>
{/each}
</nav>
</aside>

<main class="content">
{#each sections as section}
{#if activeSection === section.id}
<svelte:component this={section.component} />
{/if}
{/each}
</main>
</div>

Documentation Updates

Release Notes

We've added comprehensive release notes for v1.0.0:

# Release v1.0.0

## What's New

- First stable production release
- Production-ready Docker images with security hardening
- All core modules verified and tested
- Comprehensive API documentation

## Migration Guide

See [Migration Guide](/docs/migration-v1-0-0) for upgrading from previous versions.

## Breaking Changes

None from v0.5.0-alpha.

## Known Issues

See [Known Issues](https://github.com/MoLOS-App/MoLOS/issues) for current issues.

Changelog Updates

Updated changelog to reflect all changes:

# Changelog

## [1.0.1] - 2026-03-18

### Added
- Manual release workflow script
- Enhanced production Docker builds
- Modular admin settings components

### Changed
- Renamed API keys to auth keys (MCP)
- Bumped module versions
- Simplified CI/CD workflows

### Removed
- Automated release workflow
- Separate test pipeline

## [1.0.0] - 2026-03-13

### Added
- First stable production release
- Production Docker images
- All core modules

See full changelog for details.

What's Changed Since v1.0.0

Bug Fixes

  • Fixed authentication issues for HTTP deployments
  • Improved module loading and scoping

Improvements

  • Simplified CI/CD workflows
  • Enhanced production Docker builds
  • Improved admin settings UI
  • Better module version management

Documentation

  • Added v1.0.0 release notes
  • Added migration guide
  • Updated changelog

Upgrading from v1.0.0

Quick Upgrade

# Pull latest changes
git fetch origin
git checkout v1.0.1

# Update dependencies
pnpm install

# Restart application
docker-compose down
docker-compose pull
docker-compose up -d

Manual Upgrade

# Update dependencies
pnpm install

# No migrations needed

# Build
pnpm build

# Restart
pnpm start

Key Commits

What's Next

The v1.0.1 release improves operational simplicity. Our focus for v1.1.0 includes:

  • PostgreSQL support
  • Performance optimizations
  • Enhanced mobile experience
  • Advanced analytics
  • Real-time collaboration features

The v1.0.1 release simplifies operations while maintaining all the stability and features of v1.0.0.