---
name: project-initialization
description: >
  Scaffold a new wcz-layout project from the template. Covers placeholder
  replacement across three naming conventions (kebab-case, Title Case,
  snake_case), .env and .env.local configuration, VITE_ENTRA_CLIENT_ID,
  VITE_APP_TITLE, VITE_MUI_LICENSE_KEY, favicon generation via favicon.io,
  and viteWczLayout() Vite plugin registration. Activate when starting a
  new internal project or configuring environment variables.
type: lifecycle
library: wcz-layout
library_version: "7.6.1"
sources:
  - "wcz-layout:src/env.ts"
  - "wcz-layout:src/lib/vite-plugin.ts"
  - "wcz-layout:vite.config.ts"
  - "wcz-layout:.env"
---

# Project Initialization

## Setup

After cloning the template repository, initialize the project in this order:

### 1. Replace all template placeholders

Use your editor's replace-all (across all files) for each naming convention:

| Find           | Replace with | Used in                                          |
| -------------- | ------------ | ------------------------------------------------ |
| `project-name` | `app-store`  | package.json name, URLs, CSS classes             |
| `Project Name` | `App Store`  | VITE_APP_TITLE, display strings, docs            |
| `my_app`       | `app_store`  | Database names, env vars, snake_case identifiers |

### 2. Configure environment variables

```sh
# .env — committed to repo, shared across team
VITE_ENTRA_CLIENT_ID=your-entra-client-id
VITE_ENTRA_TENANT_ID=your-tenant-id
VITE_APP_TITLE=App Store
VITE_MUI_LICENSE_KEY=your-mui-license-key
```

Create `.env.local` (gitignored) for local secret overrides:

```sh
# .env.local — never committed
VITE_ENTRA_CLIENT_ID=your-dev-client-id
ENTRA_CLIENT_ID=your-server-client-id
ENTRA_TENANT_ID=your-server-tenant-id
ENTRA_CLIENT_SECRET=your-client-secret
```

### 3. Generate favicon

Go to https://favicon.io/favicon-converter/, upload your logo, and place the generated files in `public/`.

### 4. Verify Vite plugin registration

```typescript
// vite.config.ts
import { viteWczLayout } from "wcz-layout/vite";

export default defineConfig({
  plugins: [
    tanstackStart(),
    nitro(),
    viteReact(),
    babel(reactCompilerPreset()),
    checker({ typescript: true }),
    viteWczLayout(),
  ],
});
```

## Core Patterns

### Environment validation with createEnv

```typescript
// src/env.ts
import { createEnv } from "wcz-layout/utils";
import { z } from "zod";

export const clientEnv = createEnv({
  clientPrefix: "VITE_",
  client: {
    VITE_ENTRA_CLIENT_ID: z.string(),
    VITE_ENTRA_TENANT_ID: z.string(),
    VITE_APP_TITLE: z.string(),
    VITE_MUI_LICENSE_KEY: z.string(),
  },
  runtimeEnv: import.meta.env,
  emptyStringAsUndefined: true,
});

export const serverEnv = createEnv({
  server: {
    ENTRA_CLIENT_ID: z.string(),
    ENTRA_TENANT_ID: z.string(),
    ENTRA_CLIENT_SECRET: z.string(),
  },
  runtimeEnv: process.env,
  emptyStringAsUndefined: true,
});
```

### Vault secrets for local development

The `viteWczLayout()` plugin automatically loads secrets from HashiCorp Vault during `vite dev` if `VAULT_ADDRESS`, `VAULT_USERNAME`, `VAULT_PASSWORD`, and `VAULT_SECRET_PATH` are set in `.env`. Vault-loaded secrets only populate `process.env` keys that are not already set.

## Common Mistakes

### CRITICAL Missing viteWczLayout() in Vite config

Wrong:

```typescript
// vite.config.ts
export default defineConfig({
  plugins: [tanstackStart(), viteReact()],
});
```

Correct:

```typescript
// vite.config.ts
import { viteWczLayout } from "wcz-layout/vite";
export default defineConfig({
  plugins: [tanstackStart(), viteReact(), viteWczLayout()],
});
```

Without `viteWczLayout()`, the `virtual:wcz-layout` module won't resolve, breaking i18n resources, permissions, and scopes at build time.

Source: wcz-layout:src/lib/vite-plugin.ts

### HIGH Forgetting .env.local for local secrets

`.env` is committed to the repo and shared across the team. Local overrides (Entra client IDs, secrets) must go in `.env.local` which is gitignored. Committing secrets to `.env` exposes them in the repository.

Source: maintainer interview

### HIGH Not replacing all naming conventions

The template uses three naming conventions. Use replace-all across the entire project for each one. Missing any convention leaves stale references in package.json, env files, or source imports.

Source: maintainer interview

### MEDIUM Empty string env vars pass silently

Wrong:

```sh
# .env
VITE_APP_TITLE=
```

Correct:

```sh
# .env
VITE_APP_TITLE=My Application
```

`createEnv` uses `emptyStringAsUndefined: true`, so empty strings become `undefined` and fail Zod validation at runtime, not build time.

Source: wcz-layout:src/env.ts

### HIGH Tension: Simplicity vs. full-stack rigor

This skill's simple setup conflicts with production readiness from api-routes. Agents scaffolding a quick prototype may skip authorizationMiddleware and validationMiddleware, producing code that works locally but is insecure in production. Always include middleware from the start.

See also: skills/api-routes/SKILL.md § Common Mistakes

---

See also: skills/project-structure/SKILL.md — After init, understand where to place new code.
