docs: add project-specific rules and file reference documentation

This commit is contained in:
2026-06-30 22:39:47 +07:00 Unverified
parent 19fde79fd0
commit 8c0c2ee3a1
+277
View File
@@ -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., `<div>`). 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.