appconfig-system

Expert guidance for working with the AppConfig runtime configuration system in squareone. Use this skill when implementing configuration loading, working with YAML config files, setting up new pages that need configuration, troubleshooting config hydration issues, or migrating from next/config patterns. Covers server-side loadAppConfig(), client-side useAppConfig(), MDX content loading, Sentry configuration injection, and Kubernetes ConfigMap patterns.

16 stars

Best use case

appconfig-system is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Expert guidance for working with the AppConfig runtime configuration system in squareone. Use this skill when implementing configuration loading, working with YAML config files, setting up new pages that need configuration, troubleshooting config hydration issues, or migrating from next/config patterns. Covers server-side loadAppConfig(), client-side useAppConfig(), MDX content loading, Sentry configuration injection, and Kubernetes ConfigMap patterns.

Teams using appconfig-system should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/appconfig-system/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/development/appconfig-system/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/appconfig-system/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How appconfig-system Compares

Feature / Agentappconfig-systemStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Expert guidance for working with the AppConfig runtime configuration system in squareone. Use this skill when implementing configuration loading, working with YAML config files, setting up new pages that need configuration, troubleshooting config hydration issues, or migrating from next/config patterns. Covers server-side loadAppConfig(), client-side useAppConfig(), MDX content loading, Sentry configuration injection, and Kubernetes ConfigMap patterns.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# AppConfig System

The squareone app uses a filesystem-based configuration system that replaces `next/config` for runtime configuration.

## Critical Rules

**NEVER use `next/config` or `getConfig()`** - The app has been migrated away from this pattern. Always use the AppConfig system instead.

## Configuration Architecture

### Configuration Files

- **`squareone.config.yaml`** - Public runtime configuration (accessible client-side)
- **`squareone.serverconfig.yaml`** - Server-only configuration (secrets, etc.)
- **`squareone.config.schema.json`** - JSON schema for public config validation
- **`squareone.serverconfig.schema.json`** - JSON schema for server config validation

See [reference/config-reference.md](reference/config-reference.md) for complete schema documentation.

### Key Modules

- **`src/lib/config/loader.ts`** - Server-side configuration and MDX loading
- **`src/contexts/AppConfigContext.tsx`** - React context for client-side access

## Server-Side Configuration Loading

### In getServerSideProps

Use `loadAppConfig()` to load configuration in `getServerSideProps`:

```typescript
import type { GetServerSideProps } from 'next';
import { loadAppConfig } from '../lib/config/loader';

export const getServerSideProps: GetServerSideProps = async () => {
  try {
    // Load app configuration
    const appConfig = await loadAppConfig();

    return {
      props: {
        appConfig, // Passed to page component and extracted by _app.tsx
      },
    };
  } catch (error) {
    throw error;
  }
};
```

See [templates/page-with-config.tsx](templates/page-with-config.tsx) for a complete example.

### Loading MDX Content

For pages that render MDX content, use `loadConfigAndMdx()`:

```typescript
import { loadConfigAndMdx } from '../lib/config/loader';
import { serialize } from 'next-mdx-remote/serialize';

export const getServerSideProps: GetServerSideProps = async () => {
  try {
    // Load both config and raw MDX content
    const { config: appConfig, mdxContent } = await loadConfigAndMdx('docs.mdx');

    // Serialize MDX for rendering
    const mdxSource = await serialize(mdxContent);

    return {
      props: {
        appConfig,
        mdxSource,
      },
    };
  } catch (error) {
    throw error;
  }
};
```

### MDX Directory Configuration

- **Development**: MDX files in `src/content/pages/` (relative path in config)
- **Production**: Configurable via `mdxDir` in YAML (absolute path for Kubernetes ConfigMaps)
- **Path resolution**: Automatic handling of relative vs absolute paths in loader

## Client-Side Configuration Access

### Using the useAppConfig Hook

Components access configuration via the `useAppConfig()` hook:

```typescript
import { useAppConfig } from '../contexts/AppConfigContext';

function MyComponent() {
  const config = useAppConfig();

  return (
    <div>
      <h1>{config.siteName}</h1>
      <p>Environment: {config.environmentName}</p>
      <a href={config.docsBaseUrl}>Documentation</a>
    </div>
  );
}
```

See [templates/component-with-config.tsx](templates/component-with-config.tsx) for a complete example.

### Requirements

- Component must be within `<AppConfigProvider>` (automatically set up in `_app.tsx`)
- Page must implement `getServerSideProps` to pass `appConfig` prop
- Hook throws error if used outside provider

## Sentry Configuration

### Server-Side (sentry.server.config.js)

Sentry configuration is loaded from environment variables and injected into AppConfig:

```javascript
// In loadAppConfig():
const sentryDsn = process.env.SENTRY_DSN;

const config = {
  ...publicConfig,
  ...serverConfig,
} as AppConfig;

// Only add sentryDsn if it's defined
if (sentryDsn) {
  config.sentryDsn = sentryDsn;
}
```

### Client-Side (instrumentation-client.js)

Sentry configuration is injected into the browser via `window.__SENTRY_CONFIG__` in `_document.tsx`.

**Critical requirement**: Pages MUST implement `getServerSideProps` to enable configuration injection. Statically rendered pages get the default configuration which disables client-side Sentry reporting.

## Configuration Schema and Validation

### Ajv-Based Validation

Configuration is validated using Ajv with:
- **Default values** - Schema defaults are applied automatically
- **Additional property removal** - Unknown properties are stripped
- **Type validation** - Ensures correct types for all fields

```typescript
const ajv = new Ajv({ useDefaults: true, removeAdditional: true });
const validate = ajv.compile(schema);

// Validation modifies the configuration data
const isValid = validate(data);

if (!isValid && validate.errors) {
  throw new Error(
    `Configuration validation failed: ${ajv.errorsText(validate.errors)}`
  );
}
```

### Environment Variable Override

Some configurations can be overridden via environment variables:

- `SQUAREONE_CONFIG_PATH` - Override public config file path
- `SQUAREONE_SERVER_CONFIG_PATH` - Override server config file path
- `SENTRY_DSN` - Sentry Data Source Name (injected at runtime)
- `SQUAREONE_ENABLE_CACHING` - Force caching in development

## Caching Behavior

### Production Caching

In production (`NODE_ENV === 'production'`), configuration and MDX content are cached:
- Config loaded once and cached module-level
- MDX content cached per-file
- Improves performance by avoiding repeated filesystem reads

### Development Mode

In development, caching is disabled by default:
- Allows editing config and MDX files without restart
- Can be enabled via `SQUAREONE_ENABLE_CACHING=true` for testing

## Kubernetes Deployment Pattern

### ConfigMap Mounting

Configuration files can be mounted as Kubernetes ConfigMaps:

```yaml
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: squareone-config
data:
  squareone.config.yaml: |
    siteName: 'Production Site'
    baseUrl: 'https://example.com'
    mdxDir: '/config/mdx'  # Absolute path to mounted MDX content
    # ... rest of config
```

```yaml
# Deployment
volumeMounts:
  - name: config
    mountPath: /app/squareone.config.yaml
    subPath: squareone.config.yaml
  - name: mdx-content
    mountPath: /config/mdx
```

### Path Handling

The loader automatically handles path resolution:
- **Relative path** (development): Resolved from `process.cwd()`
- **Absolute path** (production): Used as-is for ConfigMap mounts

## Key Benefits

- **Kubernetes-ready**: Configuration via ConfigMaps at runtime
- **No hydration issues**: No `next/config` or `getInitialProps` dependencies
- **Type-safe**: Full TypeScript support with `AppConfig` interface
- **Environment-agnostic**: Same system works in development and production
- **Content management**: MDX files separate from configuration, easier to edit

## Migration from next/config

If you encounter code using `next/config`:

**Old pattern (DO NOT USE):**
```typescript
import getConfig from 'next/config';

const { publicRuntimeConfig } = getConfig();
const siteName = publicRuntimeConfig.siteName;
```

**New pattern (USE THIS):**
```typescript
// In getServerSideProps
import { loadAppConfig } from '../lib/config/loader';
const appConfig = await loadAppConfig();

// In components
import { useAppConfig } from '../contexts/AppConfigContext';
const config = useAppConfig();
const siteName = config.siteName;
```

## Troubleshooting

### Error: "useAppConfig must be used within an AppConfigProvider"

**Cause**: Component is not wrapped in `AppConfigProvider` or page didn't implement `getServerSideProps`.

**Solution**:
1. Ensure page implements `getServerSideProps` with `loadAppConfig()`
2. Return `appConfig` in props
3. `_app.tsx` automatically wraps pages with `AppConfigProvider`

### Error: "Configuration validation failed"

**Cause**: YAML configuration doesn't match JSON schema.

**Solution**: Check schema in `squareone.config.schema.json` and ensure all required fields are present with correct types.

### MDX file not found error

**Cause**: `mdxDir` configuration doesn't point to correct location.

**Solution**:
- **Development**: Use relative path like `src/content/pages`
- **Production**: Use absolute path like `/config/mdx` (for ConfigMap mounts)

### Sentry not initializing on client

**Cause**: Page is statically rendered (no `getServerSideProps`).

**Solution**: Add `getServerSideProps` to the page to enable server-side rendering and configuration injection.

## API Routes

API routes can also access configuration:

```typescript
import type { NextApiRequest, NextApiResponse } from 'next';
import { loadAppConfig } from '../lib/config/loader';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const config = await loadAppConfig();

  // Use config...
  res.status(200).json({ siteName: config.siteName });
}
```

## Storybook Configuration

Storybook uses `AppConfigProvider` decorator with mock configuration:

```typescript
// .storybook/preview.tsx
import { AppConfigProvider } from '../src/contexts/AppConfigContext';

const mockConfig = {
  siteName: 'Storybook',
  // ... mock config values
};

export const decorators = [
  (Story) => (
    <AppConfigProvider config={mockConfig}>
      <Story />
    </AppConfigProvider>
  ),
];
```

This allows components using `useAppConfig()` to work in Storybook stories.

## Environment Variables Policy

**Avoid `NEXT_PUBLIC_` environment variables** for runtime config - use YAML files instead.

**Use environment variables only for**:
- Infrastructure concerns (Sentry DSN, database URLs)
- Build-time configuration
- Secrets that shouldn't be in version control

Runtime application configuration should be in YAML files so it can be managed via Kubernetes ConfigMaps without rebuilding the application.

Related Skills

azure-appconfiguration-ts

16
from diegosouzapw/awesome-omni-skill

Build applications using Azure App Configuration SDK for JavaScript (@azure/app-configuration). Use when working with configuration settings, feature flags, Key Vault references, dynamic refresh, o...

anysystem-design

16
from diegosouzapw/awesome-omni-skill

LLM Agent Skill for AnySystem Design React component library

anti-cheat-systems

16
from diegosouzapw/awesome-omni-skill

Guide for understanding anti-cheat systems and bypass techniques. Use this skill when researching game protection systems (EAC, BattlEye, Vanguard), anti-cheat architecture, detection methods, or bypass strategies.

analyze-system

16
from diegosouzapw/awesome-omni-skill

システム分析エージェント - ユビキタス言語、アクター、ロール、権限、ドメイン-コード対応表を抽出。/analyze-system [対象パス] で呼び出し。

advocacy-roster-system

16
from diegosouzapw/awesome-omni-skill

Scoring and governance framework for managing reference customers and advocacy cohorts.

Achievements System

16
from diegosouzapw/awesome-omni-skill

Rewarding players for completing specific goals through progress tracking, unlocking logic, rarity calculation, and achievement display for gamification and player engagement.

ui-ux-design-system

16
from diegosouzapw/awesome-omni-skill

Expert in building premium, accessible UI/UX design systems for SaaS apps. Covers design tokens, component architecture with shadcn/ui and Radix, dark mode, glassmorphism, micro-animations, responsive layouts, and accessibility. Use when: ui, ux, design system, shadcn, radix, tailwind, dark mode, animation, accessibility, components, figma to code.

tailwind-design-system

16
from diegosouzapw/awesome-omni-skill

Build scalable design systems with Tailwind CSS, design tokens, component libraries, and responsive patterns. Use when creating component libraries, implementing design systems, or standardizing UI...

setup-design-system

16
from diegosouzapw/awesome-omni-skill

Initialize the design system or create new UI components with accessibility, Tailwind/shadcn integration, and documentation. Use when setting up the initial design system, adding component categories, or creating complex UI components that need design review.

radix-ui-design-system

16
from diegosouzapw/awesome-omni-skill

Build accessible design systems with Radix UI primitives. Headless component customization, theming strategies, and compound component patterns for production-grade UI libraries.

lean-systems-design

16
from diegosouzapw/awesome-omni-skill

Apply Elon Musk-inspired system design thinking for research, engineering, and business workflows: rigorously challenge requirements, delete steps, simplify/optimize what remains, accelerate iteration, then automate. Use when designing or revising systems, processes, or products that need lean, high-velocity execution.

Design Undo/Redo Systems

16
from diegosouzapw/awesome-omni-skill

CREATE comprehensive undo/redo systems with Command Pattern. Design state management for complex applications with canvas interactions, multiple stores, and user actions. Use when building new undo/redo functionality from scratch.