diff --git a/skill/erika/SKILL.md b/skill/erika/SKILL.md
index e69de29..1a19875 100644
--- a/skill/erika/SKILL.md
+++ b/skill/erika/SKILL.md
@@ -0,0 +1,277 @@
+---
+name: erika-project
+description: Project-specific rules, conventions, and file reference for the Erika website (linktree + custom form system).
+---
+
+## 1. Think Before Coding
+
+**Don't assume. Don't hide confusion. Surface tradeoffs.**
+
+Before implementing:
+- State your assumptions explicitly. If uncertain, ask.
+- If multiple interpretations exist, present them - don't pick silently.
+- If a simpler approach exists, say so. Push back when warranted.
+- If something is unclear, stop. Name what's confusing. Ask.
+
+## 2. Simplicity First
+
+**Minimum code that solves the problem. Nothing speculative.**
+
+- No features beyond what was asked.
+- No abstractions for single-use code.
+- No "flexibility" or "configurability" that wasn't requested.
+- No error handling for impossible scenarios.
+- If you write 200 lines and it could be 50, rewrite it.
+
+Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
+
+## 3. Surgical Changes
+
+**Touch only what you must. Clean up only your own mess.**
+
+When editing existing code:
+- Don't "improve" adjacent code, comments, or formatting.
+- Don't refactor things that aren't broken.
+- Match existing style, even if you'd do it differently.
+- If you notice unrelated dead code, mention it - don't delete it.
+
+When your changes create orphans:
+- Remove imports/variables/functions that YOUR changes made unused.
+- Don't remove pre-existing dead code unless asked.
+
+The test: Every changed line should trace directly to the user's request.
+
+## 4. Goal-Driven Execution
+
+**Define success criteria. Loop until verified.**
+
+Transform tasks into verifiable goals:
+- "Add validation" → "Write tests for invalid inputs, then make them pass"
+- "Fix the bug" → "Write a test that reproduces it, then make it pass"
+- "Refactor X" → "Ensure tests pass before and after"
+
+For multi-step tasks, state a brief plan:
+```
+1. [Step] → verify: [check]
+2. [Step] → verify: [check]
+3. [Step] → verify: [check]
+```
+
+Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
+
+## 5. UI and Design
+
+**Leverage existing design systems. Avoid custom CSS.**
+
+- Build all UI exclusively using ShadCN components.
+- Rely on the built-in component styling; it's already well-designed.
+- Do not add custom CSS or excessive utility classes unless absolutely necessary.
+- Avoid excessive inline styles on HTML elements (e.g., `
`). Keep styling clean and minimal to prevent an "AI slop" appearance.
+
+## 6. Type Checking
+
+**Use lightweight tools for validation. Avoid full builds.**
+
+- Do not run `bun build` or `npm run build` solely to check for type errors.
+- Use `npx tsc --noEmit` instead for fast and focused type validation.
+
+## 7. Docker Compose
+
+**Standardize on Docker Compose. Avoid standalone Docker commands.**
+
+- Use Docker Compose exclusively for container management.
+- Map external ports explicitly to the internal application port `3000` (e.g., `"8710:3000"`).
+- Keep the `docker-compose.yml` file clean and well-organized.
+
+## 8. Commands
+
+**Avoid inline code execution.**
+
+- Do not pass code strings directly to execution tools (e.g., `bun -e 'console.log("hello world")'`).
+- Always write scripts to dedicated files before executing them.
+
+## 9. Database
+
+**Use standard tools for external databases.**
+
+- Assume the use of an external database for persistent storage.
+- Use Drizzle ORM exclusively for database interactions.
+
+## 10. Explicit Approval for Plans
+
+**Achieve alignment before execution.**
+
+- Ensure the implementation plan is completely clear and mutually understood.
+- Do not begin executing the plan until explicit approval (e.g., "let's do it") is given by the user.
+
+## 11. Communication Style
+
+**Be concise and professional. No fluff.**
+
+- Keep responses short, direct, and straightforward.
+- Do not use emojis, unnecessary pleasantries, or filler words.
+- Maintain a clean and simple text format.
+
+---
+
+## Project Overview
+
+Erika is a Next.js website for the content creator "Erika!". It has two main features:
+
+1. **Linktree** (`/`) — A landing page showing profile info, social links, and live follower counts from YouTube, Roblox, Discord, and TikTok.
+2. **Custom Form System** (`/form`, `/admin/form`) — A full form builder where admins create forms with various question types, and users submit responses via Discord OAuth login.
+
+### Tech Stack
+
+- **Runtime**: Bun
+- **Framework**: Next.js (App Router)
+- **Database**: PostgreSQL via Drizzle ORM
+- **Cache**: Redis (Bun's built-in `RedisClient`)
+- **Auth**: NextAuth.js with Discord OAuth provider
+- **UI**: ShadCN components + Tailwind CSS
+- **Fonts**: Anuphan (Thai), Geist Sans (Latin)
+- **Deployment**: Docker Compose + Nginx reverse proxy
+
+---
+
+## Environment Variables (`.env`)
+
+| Variable | Purpose |
+|---|---|
+| `DATABASE_URL` | PostgreSQL connection string |
+| `NEXTAUTH_SECRET` | Secret for signing NextAuth sessions |
+| `NEXTAUTH_URL` | Canonical URL of the site (e.g. `https://erika.sudloh.com`) |
+| `REDIS_URL` | Redis connection string, used for caching follower counts and tracking unique visitors |
+| `BASE_URL` | Public base URL, used in metadata/SEO |
+| `DISCORD_CLIENT_ID` / `DISCORD_CLIENT_SECRET` | Discord OAuth app credentials for user login |
+| `ADMIN_DISCORD_IDS` | **Comma-separated list of Discord user IDs that have admin access.** These users can access `/admin/form` to create, edit, and delete forms. Any Discord user NOT in this list is treated as a regular user. |
+| `DISCORD_BOT_TOKEN` | Bot token used to fetch Discord server member count |
+| `DISCORD_GUILD_ID` | Discord server ID to fetch member count from |
+| `YOUTUBE_API_KEY` / `YOUTUBE_CHANNEL_ID` | YouTube Data API credentials to fetch subscriber count |
+| `ROBLOX_USER_ID` | Roblox user ID to fetch follower count |
+| `TIKTOK_CLIENT_KEY` / `TIKTOK_CLIENT_SECRET` | TikTok Official API credentials |
+| `TIKTOK_ACCESS_TOKEN` / `TIKTOK_REFRESH_TOKEN` / `TIKTOK_OPEN_ID` | TikTok OAuth tokens (obtained via one-time flow at `/api/auth/tiktok`) |
+
+---
+
+## File & Directory Reference
+
+### `lib/` — Shared Libraries
+
+| File | Purpose |
+|---|---|
+| `lib/config.ts` | **Linktree configuration for the root page (`/`).** Defines the profile (name, description, avatar) and the list of social links (Roblox, Discord, TikTok, YouTube) displayed on the landing page. Also defines `config_p2` which adds the Form link. This does NOT configure the form system. |
+| `lib/icons.tsx` | SVG icon components for social platforms (Roblox, Discord, TikTok, YouTube, Form) |
+| `lib/redis.ts` | Redis client singleton using Bun's built-in `RedisClient`. Used for caching follower counts (1hr TTL) and tracking unique visitors. |
+| `lib/utils.ts` | Utility functions (e.g. `cn()` for className merging) |
+
+### `lib/followers/` — Follower Count Fetchers
+
+| File | Purpose |
+|---|---|
+| `lib/followers/index.ts` | Aggregates all platform follower counts with Redis caching (1hr TTL). Exports `getFollowerCounts()` used by the root page. |
+| `lib/followers/discord.ts` | Fetches Discord server member count via bot API |
+| `lib/followers/youtube.ts` | Fetches YouTube subscriber count via YouTube Data API |
+| `lib/followers/roblox.ts` | Fetches Roblox follower count via public API |
+| `lib/followers/tiktok.ts` | Fetches TikTok follower count and profile via TikTok Official API. Auto-refreshes expired tokens. |
+
+### `db/` — Database Layer
+
+| File | Purpose |
+|---|---|
+| `db/index.ts` | Drizzle ORM client initialization, exports `db` |
+| `db/schema.ts` | Barrel file re-exporting all schemas |
+| `db/schema/account.ts` | NextAuth account tables (`user`, `account`, `session`, `verificationToken`) in the `account` PostgreSQL schema. Users have a `discordId` field. |
+| `db/schema/form.ts` | Form system tables in the `form` PostgreSQL schema: `forms` (form metadata, webhook config), `questions` (question definitions with types: text/textarea/radio/checkbox), `submissions` (user submissions with edit history), `answers` (individual answers) |
+
+### `app/` — Routes
+
+#### Root & Global
+
+| File | Purpose |
+|---|---|
+| `app/layout.tsx` | Root layout. Sets up fonts (Anuphan + Geist), theme provider, tooltip provider, toaster, page progress bar, and SEO metadata. |
+| `app/page.tsx` | **Linktree landing page (`/`).** Displays profile avatar (from TikTok API or fallback), social links with live follower counts, unique visitor counter, and a video background. |
+| `app/globals.css` | Global CSS styles |
+
+#### `/form` — Public Form System (user-facing)
+
+| File | Purpose |
+|---|---|
+| `app/form/page.tsx` | Lists all **open** forms for users to fill out |
+| `app/form/layout.tsx` | Form section layout with header, login state, and theme toggle. Shows a login dialog if the user is not authenticated. |
+| `app/form/client.tsx` | Client-side form components (user avatar dropdown, sign out, etc.) |
+| `app/form/[id]/page.tsx` | Individual form submission page where users answer questions |
+| `app/form/[id]/layout.tsx` | Layout for individual form pages |
+
+#### `/admin/form` — Admin Form Management (admin-only)
+
+| File | Purpose |
+|---|---|
+| `app/admin/form/page.tsx` | **Admin form list.** Shows all forms (open and closed) with create/edit/delete actions. Protected by admin auth check — redirects non-admins to `/`. |
+| `app/admin/form/[id]/layout.tsx` | **Admin form editor layout.** Contains the admin auth guard (checks `getServerSession` against `ADMIN_DISCORD_IDS`). Redirects non-admins to `/form`. Includes sidebar navigation. |
+| `app/admin/form/[id]/page.tsx` | Admin form editor page |
+| `app/admin/form/[id]/client.tsx` | Client-side admin form editor components (question builder, drag-and-drop, settings) |
+| `app/admin/form/[id]/result/` | Admin view of form submission results |
+| `app/admin/form/[id]/extra/` | Additional admin form settings |
+
+#### `/discord` — Discord Redirect
+
+| File | Purpose |
+|---|---|
+| `app/discord/page.tsx` | Simple redirect to the Discord server invite link |
+
+#### `/api` — API Routes
+
+| File | Purpose |
+|---|---|
+| `app/api/auth/[...nextauth]/route.ts` | NextAuth.js configuration with Discord OAuth provider. Exports `authOptions`. |
+| `app/api/auth/tiktok/route.ts` | Initiates TikTok OAuth flow (one-time setup to get tokens) |
+| `app/api/auth/tiktok/callback/route.ts` | TikTok OAuth callback handler |
+| `app/api/upload/route.ts` | File upload endpoint (admin-only, checks `ADMIN_DISCORD_IDS`) |
+
+#### `app/actions/` — Server Actions
+
+| File | Purpose |
+|---|---|
+| `app/actions/form.ts` | Server actions for form CRUD (create, update settings, delete). All protected by admin auth check. |
+| `app/actions/questions.ts` | Server actions for question CRUD within a form. Admin-protected. |
+| `app/actions/submissions.ts` | Server actions for form submissions (submit, edit, view results). |
+
+### `components/` — UI Components
+
+| File | Purpose |
+|---|---|
+| `components/LinkCard.tsx` | Social link card component with follower count badges |
+| `components/ShaderBackground.tsx` | WebGL shader background effect |
+| `components/login-dialog.tsx` | Discord OAuth login dialog |
+| `components/rich-text-editor.tsx` | Rich text editor for form descriptions |
+| `components/page-progress.tsx` | Page navigation progress bar |
+| `components/theme-toggle.tsx` | Light/dark theme toggle |
+| `components/theme-provider.tsx` | next-themes provider wrapper |
+| `components/ui/` | ShadCN component library (button, card, table, badge, sidebar, etc.) |
+
+### Config & Infrastructure
+
+| File | Purpose |
+|---|---|
+| `drizzle.config.ts` | Drizzle Kit config — points to schema, outputs to `drizzle/`, uses schemas: `public`, `account`, `form` |
+| `docker-compose.yml` | Runs the app + Nginx reverse proxy via Docker Compose with `network_mode: host` |
+| `proxy.ts` | Replaces `middleware.ts` in modern Next.js. Currently a pass-through for `/form/:path*` routes — auth is handled via dialog in the layout, not here. |
+| `nginx.conf` | Nginx config for reverse proxying to the Next.js app |
+| `next.config.ts` | Next.js configuration |
+| `Dockerfile` | Container build config |
+
+---
+
+## Auth Model
+
+1. **User login**: Discord OAuth via NextAuth.js. Users log in at `/form` to submit forms.
+2. **Admin check**: Server-side only. Compares the logged-in user's `discordId` (from session) against the comma-separated `ADMIN_DISCORD_IDS` env var. This pattern is repeated in:
+ - `app/admin/form/page.tsx` (form list)
+ - `app/admin/form/[id]/layout.tsx` (form editor)
+ - `app/actions/form.ts` (form CRUD actions)
+ - `app/actions/questions.ts` (question CRUD actions)
+ - `app/api/upload/route.ts` (file uploads)
+3. **No middleware.ts**: Modern Next.js replaces `middleware.ts` with `proxy.ts`. The project has a `proxy.ts` that matches `/form/:path*` but currently just passes through. Auth checks are done per-page/per-action in server components and server actions.
+