Skip to content

Feature: Configuration Presets for Common Use Cases #97

Description

@melvincarvalho

Summary

Add configuration presets that bundle sensible defaults for common deployment scenarios. This is a low-effort, high-impact improvement that reduces friction for new users while maintaining full customization flexibility.

Difficulty: 15/100
Estimated Effort: 1-2 days
Dependencies: None


Problem

Currently, users face 30+ configuration options without guidance on which combinations make sense for their use case. New users must:

  1. Read documentation to understand each option
  2. Decide which features they need
  3. Manually configure each setting
  4. Hope they didn't miss important combinations

This creates unnecessary friction, especially for common scenarios that have well-known "best" configurations.


Proposed Solution

Usage

# CLI flag
jss start --preset personal
jss start --preset community
jss start --preset federation

# With overrides (preset applies first, then overrides)
jss start --preset personal --port 8443 --notifications

# Config file
{
  "preset": "personal",
  "port": 8443  // overrides preset value
}

# Environment variable
JSS_PRESET=personal

Preset Definitions

minimal - Development & Testing

Quick local development, CI/CD testing, demos.

{
  "port": 3000,
  "host": "localhost",
  "multiuser": false,
  "singleUser": true,
  "singleUserName": "dev",
  "conneg": false,
  "notifications": false,
  "idp": false,
  "mashlib": false,
  "git": false,
  "nostr": false,
  "activitypub": false
}
Setting Rationale
localhost only Security for dev environment
Single user No registration complexity
Features off Fastest startup, minimal dependencies

personal - Single-User Production

Personal data pod, self-hosted for one person.

{
  "port": 443,
  "host": "0.0.0.0",
  "multiuser": false,
  "singleUser": true,
  "singleUserName": "me",
  "conneg": true,
  "notifications": true,
  "idp": true,
  "mashlib": true,
  "mashlibCdn": false,
  "git": false,
  "nostr": false,
  "activitypub": false,
  "defaultQuota": "10GB"
}
Setting Rationale
Port 443 Production HTTPS
IdP enabled Proper authentication
Conneg + Notifications Full Solid spec compliance
Mashlib Data browser for file management
Large quota Personal use, generous storage

community - Multi-User Open Registration

Community server with open registration.

{
  "port": 443,
  "host": "0.0.0.0",
  "multiuser": true,
  "singleUser": false,
  "conneg": true,
  "notifications": true,
  "idp": true,
  "inviteOnly": false,
  "mashlib": true,
  "mashlibCdn": true,
  "git": false,
  "nostr": false,
  "activitypub": false,
  "defaultQuota": "100MB"
}
Setting Rationale
Open registration Community growth
Mashlib CDN Reduce server bandwidth
100MB quota Reasonable default for shared hosting

private - Multi-User Invite-Only

Organization or private group server.

{
  "port": 443,
  "host": "0.0.0.0",
  "multiuser": true,
  "singleUser": false,
  "conneg": true,
  "notifications": true,
  "idp": true,
  "inviteOnly": true,
  "mashlib": true,
  "mashlibCdn": false,
  "git": false,
  "nostr": false,
  "activitypub": false,
  "defaultQuota": "1GB"
}
Setting Rationale
Invite-only Controlled membership
Local mashlib Privacy, no CDN dependencies
1GB quota Trusted users, more storage

federation - Federated Social Server

Full federation with ActivityPub and Nostr.

{
  "port": 443,
  "host": "0.0.0.0",
  "multiuser": true,
  "singleUser": false,
  "conneg": true,
  "notifications": true,
  "idp": true,
  "inviteOnly": false,
  "mashlib": true,
  "mashlibCdn": true,
  "git": false,
  "nostr": true,
  "nostrPath": "/relay",
  "nostrMaxEvents": 5000,
  "activitypub": true,
  "defaultQuota": "500MB"
}
Setting Rationale
ActivityPub + Nostr Full federation support
Higher event limit Social features need more storage
Open registration Federation requires discoverability

developer - Full Features for Testing

All features enabled for development/testing.

{
  "port": 3000,
  "host": "0.0.0.0",
  "multiuser": true,
  "singleUser": false,
  "conneg": true,
  "notifications": true,
  "idp": true,
  "inviteOnly": false,
  "mashlib": true,
  "mashlibCdn": false,
  "git": true,
  "nostr": true,
  "activitypub": true,
  "webidTls": true,
  "defaultQuota": "1GB"
}
Setting Rationale
All features on Test all functionality
Port 3000 Dev-friendly, no sudo needed
Local mashlib Debug without CDN caching issues

Implementation Details

Config Loading Changes

// src/config.js

const PRESETS = {
  minimal: { /* ... */ },
  personal: { /* ... */ },
  community: { /* ... */ },
  private: { /* ... */ },
  federation: { /* ... */ },
  developer: { /* ... */ }
};

function loadConfig(cliOptions, configPath) {
  // 1. Start with defaults
  let config = { ...DEFAULTS };
  
  // 2. Apply preset if specified (NEW)
  const presetName = cliOptions.preset || process.env.JSS_PRESET;
  if (presetName) {
    if (!PRESETS[presetName]) {
      throw new Error(`Unknown preset: ${presetName}. Available: ${Object.keys(PRESETS).join(', ')}`);
    }
    config = { ...config, ...PRESETS[presetName] };
  }
  
  // 3. Apply config file
  if (configPath) {
    const fileConfig = JSON.parse(fs.readFileSync(configPath));
    // Handle preset in config file too
    if (fileConfig.preset && PRESETS[fileConfig.preset]) {
      config = { ...config, ...PRESETS[fileConfig.preset] };
    }
    config = { ...config, ...fileConfig };
  }
  
  // 4. Apply environment variables
  config = applyEnvOverrides(config);
  
  // 5. Apply CLI arguments (highest priority)
  config = { ...config, ...cliOptions };
  
  return config;
}

CLI Addition

// bin/jss.js

program
  .command('start')
  .option('--preset <name>', 'Configuration preset (minimal, personal, community, private, federation, developer)')
  // ... existing options

List Presets Command

program
  .command('presets')
  .description('List available configuration presets')
  .action(() => {
    console.log('\nAvailable presets:\n');
    console.log('  minimal     Development & testing (single user, no features)');
    console.log('  personal    Single-user production server');
    console.log('  community   Multi-user with open registration');
    console.log('  private     Multi-user with invite-only registration');
    console.log('  federation  Full ActivityPub + Nostr federation');
    console.log('  developer   All features enabled for testing');
    console.log('\nUsage: jss start --preset <name>');
    console.log('\nView preset details: jss presets --show <name>');
  });

Show Preset Details

$ jss presets --show personal

Preset: personal
Description: Single-user production server

Configuration:
  port: 443
  host: 0.0.0.0
  singleUser: true
  singleUserName: me
  conneg: true
  notifications: true
  idp: true
  mashlib: true
  defaultQuota: 10GB

Usage: jss start --preset personal

Enhanced jss init Integration

Update jss init to offer preset selection:

$ jss init

  JavaScript Solid Server Setup

? Choose a starting point:
  ❯ Personal server (single user, simple setup)
    Community server (multi-user, open registration)
    Private server (multi-user, invite-only)
    Federation server (ActivityPub + Nostr)
    Minimal (development/testing)
    Developer (all features enabled)
    Custom (configure everything manually)

Using preset: personal

? Port (443): 
? Data directory (./data): 
? Domain name: example.com

Configuration saved to: ./config.json

Industry Comparison

Software Preset System
Community Solid Server @css:config/file.json, @css:config/memory.json, @css:config/default.json - predefined config files
Nextcloud None - uses installation wizard
Mastodon None - single config model
Docker Compose Profiles (--profile dev, --profile prod)
Vite Modes (--mode development, --mode production)
webpack Mode option with preset behaviors
ESLint Extends (extends: ['eslint:recommended'])
Prettier None - but common in ecosystem
TypeScript Extends in tsconfig (extends: '@tsconfig/node18/tsconfig.json')

The preset pattern is well-established in JavaScript tooling (Vite, webpack, ESLint, TypeScript) and aligns with CSS's approach of predefined configurations.


Preset Comparison Matrix

Feature minimal personal community private federation developer
Port 3000 443 443 443 443 3000
Single User
Multi User
Invite Only - -
IdP
Conneg
Notifications
Mashlib ✅ (CDN) ✅ (CDN)
ActivityPub
Nostr
Git
Default Quota 50MB 10GB 100MB 1GB 500MB 1GB

Documentation Updates

README.md Addition

## Quick Start with Presets

JSS provides presets for common deployment scenarios:

| Preset | Use Case |
|--------|----------|
| `minimal` | Local development and testing |
| `personal` | Single-user production server |
| `community` | Multi-user with open registration |
| `private` | Multi-user with invite-only access |
| `federation` | Full ActivityPub + Nostr support |
| `developer` | All features enabled for testing |

\`\`\`bash
# Start with a preset
jss start --preset personal

# Override specific settings
jss start --preset personal --port 8443

# List available presets
jss presets

# View preset details
jss presets --show federation
\`\`\`

Testing Plan

  1. Unit tests: Verify preset merging logic
  2. Integration tests: Start server with each preset, verify expected behavior
  3. Override tests: Ensure CLI/env/file overrides work correctly with presets
  4. Error handling: Unknown preset name, invalid combinations
// Example test
describe('presets', () => {
  it('should apply personal preset defaults', () => {
    const config = loadConfig({ preset: 'personal' });
    expect(config.singleUser).toBe(true);
    expect(config.idp).toBe(true);
    expect(config.port).toBe(443);
  });

  it('should allow overrides on top of preset', () => {
    const config = loadConfig({ preset: 'personal', port: 8443 });
    expect(config.port).toBe(8443);
    expect(config.singleUser).toBe(true); // from preset
  });

  it('should reject unknown preset', () => {
    expect(() => loadConfig({ preset: 'invalid' })).toThrow(/Unknown preset/);
  });
});

Related Issues


Open Questions

  1. Should presets be extensible (allow users to define custom presets in config)?
  2. Should there be a --print-preset <name> to output preset as JSON for piping?
  3. Should presets warn about missing requirements (e.g., SSL certs for port 443)?
  4. Should jss start with no arguments suggest using a preset?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions