~/wiki / osnovy-vibe-design / slug-kak-zapustit-servis-samomu-vibecoding

How to start the service yourself: everything that is given on courses on vibcoding - in one article

Main chat

A chat for vibe coders: news, guides, live cases, marketplace, and finding executors.

$ cd section/ $ join vibe dev
How to start the service yourself: everything that is given on courses on vibcoding - in one article - обложка

What do you need

Инструмент Зачем Стоимость
Claude Code Агент, пишет и запускает код Pro $20/мес (токены отдельно) или Max $100/мес
Codex CLI Альтернативный агент от OpenAI ChatGPT Plus/Pro/Team включён
VS Code Редактор, где хранится проект бесплатно
Supabase База данных и авторизация бесплатно до лимита
VPS Сервер для деплоя от $6/мес
OpenRouter API для AI-функций в сервисе от $10 пополнение
GitHub Хранение кода и деплой бесплатно

Claude Code and Codex are interchangeable. The logic of the work is the same, only the installation commands and the name of the file with instructions (CLAUDE.md or AGENTS.md) differ. The text will indicate where they differ.


Block 1. Tools

Identify an agent

Claude Code:

bash
npm install -g @anthropic-ai/claude-code
claude # will launch browser authorization

Codex CLI:

bash
npm install -g @openai/codex # @openai/codex, not just codex
codex auth # browser authorization via ChatGPT

@openai/ is an unrelated project from 2012. It will be established without mistakes, but it will do nothing useful.

After installation, run the agent in any folder:

bash
claude   # для Claude Code
codex    # для Codex

The agent sees all files in the current folder, can create, edit and run commands in the terminal.


How does VS Code + Agent work

VS Code is an editor. It stores the code and you can see what's going on. The agent runs in the built-in terminal (Ctrl+ на Windows/Linux, Cmd+ on the Mac).

The work cycle looks like this:

  1. Open the project folder in VS Code
  2. Opened the terminal, launched claude or codex
  3. Written the task in text
  4. The agent suggested changes - you checked and confirmed
  5. Opened the browser on localhost:3000 - checked the result
  6. Written the following task

By default, Claude Code asks for permission before each file change. Codex works similarly. If you want the agent to work without constant confirmation – in Claude Code it is the --dangerously-skip-permissions flag, in Codex – the --full-auto mode. For training, it is better to leave confirmations on, so you better understand what is happening.


Block 2. Speck and float

Speck is a text file with a description of the service. The main lesson of vibcoding: the more accurately the task is described, the fewer iterations are needed. Don’t make an application form, but a full description of who is using what is doing and what is happening in each state.

Ask the agent to help write a dialog speculation:

plaintext
I want to make a form for collecting applications with a simple admin.
Ask me questions one by one, I'll answer.
Write everything down to SPEC.md.
When you collect enough information, show the final file.

The agent's gonna get details. Answer specifically. At the end of the day, you will have a file as the basis for all the work.


What should be in the mix

Here's a template that works. This is not a formal document, just answers to specific questions:

markdown
#SPEC. md

# What is it?
Form for accepting applications for consultation.
Guest fills out form → application is saved
The owner sees all applications in a closed admin.

## Users
- Guest - fills out the form, does not register
Admin – logs in, sees all applications, changes status

#Flow guest
1. Opens the page and sees the form
2. Enter name, email, query text → click “Send”
3. Sees gratitude screen: "Contact during the day"

#Flow admin
1. Opens /admin → redirect to /admin/login if not login
2. Enters email and password in the list of applications
3. Sees applications: name, email, text, date, status (new / in work / closed)
4. Click on the application may change the status

## Screens and states

### Form (/):
Condition: ordinary - the form is partially filled or empty
- Status: Sending - button is inactive, shows "Send..."
Status: Validation error - highlight unfilled fields, error text
Status: Server error – “Something went wrong, try it later”
Status: Success - hide the form, show the message

### List of applications (/admin):
- Status: loading - row skeleton
- Status: empty - "No applications yet"
Status: List - table sorted by date (new at the top)

What is NOT included in the first version
- Notifications by email on a new application
Search and filter applications
- Several admins.
- Deletion of applications

##Stack
Next.js App Router, TypeScript, Tailwind CSS, Supabase

The “what is not included” section is one of the most important. Without it, the agent begins to add features that you did not ask for, and you lose time to check them.


Description of screen states – the power of the designer

The average developer will write in the prompt “make a form” and will not think about empty state, validation error and boot state. The designer thinks this way - with screens and states. That's your advantage.

The more detailed the states in the speck are described, the less edits will be made after. The agent implements exactly what is written.


Block 3. Interface

Create a project

Ask the agent:

plaintext
Create a new Next.js project in the request-form folder.
Stack: TypeScript strict mode, Tailwind CSS, App Router.
Start the dev server and make sure that localhost:3000 opens.

Or yourself:

bash
npx create-next-app@latest request-form --typescript --tailwind --app
cd request-form
npm run dev

Create a file with instructions for the agent

It’s the equivalent of a brief – an agent reads it at the beginning of each session. For Claude Code it is CLAUDE.md, for Codex it is AGENTS.md. The structure is the same:

markdown
#agents.md (or claude). md)

#Context
Read SPEC.md before starting any task.
If something is not described in SPEC.md – ask, do not invent.

##Stack
Next.js App Router, TypeScript strict mode
Tailwind CSS – No arbitrary hex values, only Tailwind classes
- Supabase - auth and database via @supabase/ssr

#
Each screen in a separate component
All states from SPEC.md are required: download, error, empty
After the changes, run npm run build - make sure TypeScript doesn't swear
- Don't add features that aren't in SPEC. md

## Structure
src/
app/ - route
components/
lib/ - utility, supabase client

Collect the interface on one screen

Don’t try to “assemble the entire interface at once.” It is better to use one screen, so it is easier to check each result.

** Form challenge:**

plaintext
Read SPEC.md.

Create the main page src/app/page.tsx with the application form.
Fields: Name (mandatory), Email (mandatory, format validation),
The text of the request (mandatory, at least 10 characters).
Send button.

Button states: Normal/Send... with disabled at the time of request.
Form states: empty → validation → success (hide form, show text)
server error (toast or text under the button).

While using console.log instead of a real query, we will add the real one later.
Adaptive: mobile and desktop.

Once the shape looks right, check it out. Not "something's wrong," but an accurate description:

plaintext
The send button on mobile is too small – less than 44px in height.
The validation error message appears only after pressing the button.
It is necessary if you lose focus (onBlur) on each field.

A challenge to the success page:

plaintext
After sending the form, cut it and show the block with the text:
Thank you! We will contact you during the day.”
And the "Send Another Application" link that returns the form.

** Admin task:**

plaintext
Create src/app/admin/page.tsx.
Table of applications: columns - Name, Email, Date, Status, Action.
Status: three options - "New", "In work", "Closed".
Sorting: new ones on top.

Conditions: download (skeleton for 5 lines), empty ("No Applications yet"), list.
While using wet data - an array of 3 objects.
We will connect real data when we configure Supabase.

Block 4. Deploy - at once, not at the end

Deploy as soon as there is the first working screen. Don't wait until everything is ready. Early Deploy shows real behavior on the server and helps catch problems that are not visible locally.

Vercel - one team

bash
npm install -g vercel
vercel

Vercel will ask you a few questions and ask you. Free for personal projects. Every push in GitHub is automatically a new version.


VPS - The agent does it himself

Buy VPS: DigitalOcean from $6 / month, Timeweb from 200 rubles / month, Selectel. Ubuntu 22/24.

Task for the agent:

plaintext
This next.js project is on my VPS.
IP: [address]
User: root
Password: [password]

What needs to be done:
Install Node.js 20, nginx, PM2
- Start the project in the new GitHub repository [link]
- Close to the server, run npm install and npm run build
- Launch via PM2 on port 3000
- Configure Nginx as reverse proxy: localhost:3000
Write an SSL certificate through Let’s Encrypt for the domain [domain]
PM2 in auto-run when the server is restarted

After each step, report the result.

The agent will do everything consistently. If a mistake falls on a step, he will describe it and offer a solution.


Block 5. Database and authorization

Connect to Supabase

Sign up for supabase.com and create a new project. In settings (Settings → API) copy Project URL and anon key.

Task agent:

plaintext
Connect Supabase to the project.
Project URL: [insert]
Anon key: [insert]

Need:
1. Install @supabase/ssr and @supabase/supabase-js
2. Create src/lib/supabase/client.ts – a browser client
3. Create a src/lib/supabase/server.ts server client for App Router
4. Add variables to .env.local:
NEXT PUBLIC SUPABASE URL
Next PUBLIC SUPABASE ANON KEY
5. Make sure .env.local is in .gitignore

Create tables

plaintext
Create a SQL migration for the requests table in Supabase.

Fields:
- id: uuid, primary key, default gen random uuid()
- name: text, not null
- email: text, not null
- message: text, not null
- status: text, not null, default 'new',
check (status in ('new', 'in progress', 'closed')
- created at: timestamptz, default now()

Enable Row Level Security (RLS):
Insert: Allow everyone (also anonymous)
Select: only to authorized users
Update: Authorized only

Give me SQL ready to run in Supabase Dashboard → SQL Editor.

Copy SQL, open Supabase Dashboard → SQL Editor → New query → paste and run.


Connect the authorization to the admin

plaintext
Add authorization for /admin via Supabase Auth.

Need:
1. Page /admin/login:
Form: email + password
- buttons "Enter" and "Register"
In case of error: show the text of the error under the form
If successful: redirect to /admin

2. Middleware (middleware.ts root):
- Any request /admin/* - check the session
If there is no session, redirect to /admin/login

3. The exit button on the /admin page
- When pressed: signOut → redirect to /admin/login

Then create a test user in Supabase Dashboard → Authentication → Users → Add user.


Replace wet data with real data

Form → real sending:

plaintext
The form on the homepage now makes console.log.
Replace it with a real shipment to Supabase.

Use Server Action (src/app/actions.ts file):
- Receives: name, email, message
Validates: all fields are mandatory, email is valid format
- Inserts in the request table
- Returns: { success: true } or { error: 'error text' }

In the form: in case of an error, show the text to the user.
When successful, switch to a state of success.

Adminka → real data:

plaintext
The /admin page now shows wet data.
Replace it with a download from Supabase.

The list of applications is a server component, a request through a server client.
Sorted: created at DESC.

Client Component with Server Action:
- Drop-down list: New / In work / Closed
- When changing: update the record in the database,
Reload data via revalidatePath('/admin')

Block 6: AI functions and integrations

OpenRouter – one API for all models

OpenRouter provides access to Claude, GPT, Gemini and dozens of other models through a single API. Convenient for AI functions in the service: you do not need to start multiple subscriptions.

Register on openrouter.ai, replenish the balance, copy the key.

plaintext
Add to .env.local:
Openrouter API KEY=sk-or-...

Create src/lib/openrouter.ts:

async function generateReply()
CustomerName: string,
CustomerMessage: string
): Promise<string >>

The function sends a request to OpenRouter.
Model: anthropic/claude-sonnet-4
System Prompt: “You are a customer service assistant.”
Write politely, in Russian, briefly - 2-3 sentences.
Custom prompt: “Write a draft response to the client [name].”
who wrote: [Message]

If the request error is to return null, do not throw an exception.

Add to the admin:

plaintext
In the application table, add the “Draft Answer” button next to each application.

Press:
- The button shows the spinner
- Calls generateReply with the name and text of the application
- Shows the result in the modal window with the buttons "Copy" and "Close"
The “Copy” button copies the text to the buffer, changes the text to “Copied ✓” for 2 seconds

Telegram notifications of new applications

Create a bot through @BotFather in Telegram, get a token. Find out your chat ID via @userinfobot.

plaintext
If you successfully insert an application in Supabase, send a notification to Telegram.

In Server Action after INSERT add:
fetch('https://api.telegram.org/bot[токен]/sendMessage',)
method: 'POST',
headers: { 'Content-type': 'application/json'},
body: JSON.stringify({{}
chat id: "[chat id],"
text: `Новая заявка от ${name}\nEmail: ${email}\n\n${message}`
}
}

Asynchronous request - does not wait, does not block the response to the user.
The sending error does not affect the preservation of the application.

Block 7. Tests

Tests are needed to know that a new change has not broken what is already working. This is especially important when the project is growing.

Unit tests via Vitest

plaintext
Install Vitest and write tests for basic features.

What to test:

1. Form validation (src/lib/validate.ts – create if not):
Empty name = Empty name / Enter name error
Error: Enter the correct email
Message shorter than 10 characters → error 'Too short message' -
All fields filled correctly → returns null (no errors)

2. generateReply from openrouter.ts:
- Shut the fetch.
A successful answer returns the line.
Network error returns null, does not throw an exception

After writing, run npx vitest run – all tests must pass.

E2E test via Playwright

plaintext
Set @playwright/test and write the e2e test:

1. Open the main page
2. Fill in the form: “Test”, email “test@example.com”,
Message "Test message for verification"
3. Press "Send"
4. Check to see if there is a “thank you” text.
5. Check that the shape is no longer visible

The test must use the test base (assign via env SUPABASE URL TEST)
Or wet Server Action.

Pre-commit hook - tests before each commit

plaintext
Set up a pre-commit hook via husky and lint-staged:

Before each committ:
1. npx vitest run - unit tests
2. npm run build – TypeScript check and builds

If something falls, the commit does not pass, it shows which test failed.

Unit 8. Portfolio and case

What to show

Service in production is already a case. But it’s important for a portfolio to show thinking, not just results.

The structure of the case for vibcoding:

markdown
##The challenge
What I wanted to do and why in one paragraph.

## How to describe the task
Show the first and final version of the Prompt for one feature.
What was specified, what was refused and why.

# What was unconventional
One or two moments where the agent failed the first time.
What was wrong and how the task was reformulated.

##The result
Link to live service.
Screenshot or short video.

The difference between a strong case and a weak case is in the “how to describe the task” section. Two similar services, but one shows the process of thinking - and that's the one that will be remembered.


Typical problems

An agent walks around with one mistake. ** Don't give it any more iterations with the same wording. Open a new session, describe only a specific error: text from the console, file, line. Without the context of the whole project.

After the change, it was broken. Launch npx vitest run. If there are no tests, ask the agent to write a test for the broken place, then fix it.

The agent adds features he didn't ask for. In AGENTS.md/CLAUDE.md, add a clear rule: “Do not add anything that is not in SPEC.md.” If you think you should, ask before you do.”.

Supabase issues a Row Level Security error. This means that the RLS policy does not allow the operation for the current user. Describe to the agent: what is the operation, whether the user is authorized, and the error text. The agent will fix the policy.

**Context is lost between sessions. ** SPEC.md and AGENTS.md/CLAUDE.md resolve this. At the beginning of a new session: “Read SPEC.md and AGENTS.md. In short, what has been done, what remains.”.


Outcome

Артефакт Где лежит
Описание сервиса SPEC.md
Правила для агента AGENTS.md или CLAUDE.md
Интерфейс src/app/ и src/components/
База данных и авторизация Supabase
AI-функции src/lib/openrouter.ts
Тесты Vitest + Playwright
Сервис в продакшене VPS или Vercel

The main change after the first service launched: you stop thinking “you need a developer” and start thinking “you need a speck”.

$ cd ../ ← back to Basics of VibeDesign