7.2 KiB
Project
Environment
You are working inside a VCH cloud development environment.
- OS: Debian-based LXC container
- Editor: code-server (VS Code in browser) on port 8080
- CLI: Claude Code is available as
claudein terminal - Git: Pre-configured. Gitea integration available through VCH.
- Preview: Start a dev server on any port — VCH detects listening ports automatically and provides preview URLs with SSL.
- Publishing: Assign a public subdomain to any port via the VCH Publish page (automatic SSL).
- User:
vchuserwith home at/home/vchuser
Preview Access (IMPORTANT)
Apps are accessed through a reverse proxy, not directly. There are two modes:
- Subdomain proxy (preferred):
https://lxc{VMID}-{PORT}.dev.example.com/— your app is at the domain root, everything works normally. - Path-based proxy (fallback):
https://host/proxy/{INSTANCE}/p/{PORT}/— your app is behind a path prefix.
Rules for portable apps that work in both modes:
- ALWAYS use relative paths for assets, API calls, and links:
css/style.css✅ — NOT/css/style.css❌api/users✅ — NOT/api/users❌fetch('api/data')✅ — NOTfetch('/api/data')❌
- Static file serving: Configure your server to serve from the request path, not the filesystem root.
<base>tag: If you must use absolute paths, add<base href="./">in<head>.
Framework-specific configuration:
- Express:
app.use(express.static('public'))works — just ensure HTML references are relative. - Vite: Set
base: './'invite.config.ts. - Next.js: Set
basePathinnext.config.jsif using path-based proxy, or leave default for subdomain proxy. - Create React App: Set
"homepage": "."inpackage.json.
Development Conventions
- Write clear, descriptive commit messages (imperative mood: "Add feature", not "Added feature")
- Prefer small, focused commits over large ones
- Run linters and formatters before committing
- Write tests for critical business logic
- Keep dependencies minimal — use native browser/Node APIs where possible
README Requirement (MANDATORY)
Every project MUST have a meaningful README.md in the project root. This is enforced by the VCH audit system — projects without a proper README cannot be published.
Your README must include at minimum:
- Project description — what the project does (not just the template placeholder)
- Installation instructions — how to install dependencies
- Development instructions — how to start the dev server
- Tech stack — what technologies are used
Update the README whenever you add features, change setup steps, or modify the tech stack. The audit will reject READMEs that are still just the default template.
Project Description (MANDATORY)
Every project has a .vch-description file in the project root. Keep this file up to date with a clear, non-technical description of your project:
- What the project does
- What problem it solves or what it's used for
- Who it's for
Do NOT include technical details (tech stack, dependencies, setup instructions) — those belong in the README. The .vch-description content is shown in the VCH Showcase and is synced automatically when an audit runs.
Update .vch-description whenever the project's purpose or scope changes significantly.
Web Best Practices
- Use semantic HTML elements (
nav,main,article,section, etc.) - Mobile-first responsive design
- Follow accessibility guidelines (ARIA labels, keyboard navigation, color contrast)
- Optimize images and assets for performance
- Use environment variables for configuration — never hardcode secrets
Commands
Fill in project-specific commands below:
- Install dependencies:
npm install - Start dev server:
npm run dev - Run tests:
npm test - Build for production:
npm run build - Lint:
npm run lint
Deploy preparation
If this project should be deployed and reads environment variables from process.env (or equivalent), create .env.example at the repo root. List every variable the app reads, one per line: KEY=example-value. Example values are hints only — they are not used in production. If the project needs no env vars, no file is required.
Vibecoders' tip: when in doubt, run grep -RhoE "process\.env\.[A-Z_]+" src/ | sort -u and put every result into .env.example.
Listen on PORT (IMPORTANT). VCH assigns every deployed app its own host port automatically — you never pick or coordinate ports, and two projects on the same machine never clash. Your app MUST bind the port from the PORT environment variable, not a hardcoded one:
- Node/Express:
app.listen(process.env.PORT || 3000) - Next.js:
next starthonoursPORTautomatically - Vite preview / other servers: pass
--port "$PORT"(or readprocess.env.PORT)
A hardcoded port works locally but fails the production health-check (VCH checks the assigned port, which usually isn't 3000). For Docker, set port: below to the port your app listens on inside the container — VCH maps the auto-assigned host port to it for you.
Containerized projects (Docker). If your project has a Dockerfile (or a compose.yaml/docker-compose.yml), add a .vch/deploy.yaml at the repo root so VCH deploys it correctly:
runtime: docker
port: 3000 # the port your app LISTENS ON inside the container
health: / # a path that returns 2xx/3xx when the app is up
- VCH builds your image, runs the container with
--restart=always, injects production env vars via--env-fileat runtime, and health-checksport. - Build-time variables: only variables prefixed
NEXT_PUBLIC_,VITE_, orPUBLIC_are passed to the build as--build-arg(they are client-visible by convention). Secrets are runtime-only and are never baked into the image — declare matchingARGlines in your Dockerfile for the public ones. - Compose: the app service MUST publish its port as
ports: ["${VCH_PORT}:<internal>"]. VCH setsVCH_PORTso it can run an isolated candidate stack during audits without touching your live stack. Addenv_file: [.env]to any service that needs production env vars — VCH writes your production variables to a.envfile next to your compose file. - VCH runs exactly ONE compose file — no
-foverride chains. VCH auto-discovers a single compose file (compose.yaml/compose.yml/docker-compose.yaml/docker-compose.yml) at the repo root or in a subfolder (e.g.docker/) and runs only that file. A separate override such asdocker-compose.ports.ymlor*.override.ymlis ignored — put the${VCH_PORT}port mapping in the main compose file, not in an override. If several matching compose files exist, choose one explicitly withcompose: <path>in.vch/deploy.yaml. - The whole compose starts. VCH brings up the entire compose project, so DB/cache/auth services your compose defines itself (Postgres, Redis, etc.) start automatically — you do not also need a separate managed database for them. (Services behind a compose
profiles:key stay off unless you activate the profile.) - If you omit
.vch/deploy.yaml, VCH falls back to the DockerfileEXPOSEport (or3000).