Project structure
Learn where routes, business workflows, adapters, content, and configuration belong.
VibeAny uses Next.js App Router with explicit boundaries between presentation, application workflows, domain logic, and infrastructure. Knowing those boundaries makes customization faster and keeps provider-specific code from spreading through the application.
Top-level layout
src/
app/ Next.js pages, layouts, route handlers, and global CSS
proxy.ts Locale handling, auth redirects, and API rate limits
interfaces/ HTTP, CLI, MCP, cron, and webhook adapters
features/ Presentation-facing UI and API wrappers
application/ Use cases, ports, actor context, policies, and orchestration
entities/ Pure domain models, types, and algorithms
infrastructure/ Database and provider adapters implementing application ports
shared/ Shared UI, providers, hooks, stores, types, and helpers
lib/ Low-level integration and configuration modules
i18n/ Locale messages, loaders, schemas, and validation scripts
content/blog/ Localized MDX blog content
drizzle/ Reviewed SQL migrations and Drizzle metadata
scripts/ Setup, preflight, release, and maintenance commands
tests/unit/ Fast Vitest tests
tests/integration/ Database-backed integration tests
tests/e2e/ Playwright browser testsRouting
Application routes live under src/app. Locale-aware pages use the src/app/[locale] segment, so their public URLs begin with /en, /zh, or /es.
Route groups in parentheses organize files without adding a URL segment:
| Source file | Public route |
|---|---|
src/app/[locale]/(marketing)/page.tsx | /en |
src/app/[locale]/(marketing)/pricing/page.tsx | /en/pricing |
src/app/[locale]/(auth)/signup/page.tsx | /en/signup |
src/app/[locale]/(auth)/login/page.tsx | /en/login |
src/app/[locale]/dashboard/page.tsx | /en/dashboard |
src/app/api/(billing)/payments/webhook/route.ts | /api/payments/webhook |
src/app/api/auth/[...all]/route.ts | /api/auth/* |
The root src/app/page.tsx redirects / to the configured default locale. src/proxy.ts handles locale routing, protects /dashboard and /account, and applies API rate limits.
Keep route files thin. Parse transport input and return a transport response there, but put business decisions in application use cases.
Application boundaries
entities/
Use this layer for pure business rules that do not access the network, database, filesystem, or framework APIs. Credit allocation and subscription state types are examples.
application/
Use cases coordinate a user or system action. Ports describe the capabilities a use case needs without selecting Stripe, Creem, PostgreSQL, Resend, or another concrete provider.
infrastructure/
Adapters implement application ports. Database repositories, payment gateways, email delivery, storage, and model providers belong here. Provider SDK objects should not leak into pages or domain entities.
features/
Feature folders own presentation-facing components, hooks, schemas, and thin API wrappers. They may invoke application behavior, but should not become a second domain or persistence layer.
shared/
Reusable UI and framework helpers live here. The shadcn-compatible UI components are in src/shared/ui, and components.json maps the shadcn ui alias to that directory.
lib/
This directory contains low-level integration and configuration surfaces that are still used broadly, including authentication, database setup, SEO, and the product catalog. New business orchestration should still prefer application ports and use cases.
Common customization map
| Task | Primary location |
|---|---|
| Change product identity, domain, or support addresses | src/lib/config/brand.ts |
| Rewrite landing, SEO, and legal copy | src/i18n/locales/*/marketing.json and legal.json |
| Rearrange landing sections | src/features/marketing/ui/home-content.tsx |
| Change plans, credit packages, and provider IDs | src/lib/config/products.ts and environment variables |
| Change colors and theme tokens | src/app/globals.css |
| Replace the logo and browser icon | public/logo.svg and public/icon.svg |
| Add a localized marketing page | src/app/[locale]/(marketing)/<slug>/page.tsx |
| Add shared UI | src/shared/ui |
| Change database tables | src/lib/db/schema.ts, followed by a generated migration |
| Add a provider | An application port plus an infrastructure adapter and composition wiring |
A typical request path
For a payment checkout, the public route validates HTTP input, a presentation wrapper invokes an application use case, and infrastructure selects the configured payment gateway. The provider webhook returns through the same adapter boundary before application code records provider-neutral billing state.
Next.js route
-> feature or interface adapter
-> application use case and port
-> infrastructure provider adapter
-> external provider or PostgreSQLThis separation is why the active payment provider can change without rewriting the checkout UI or the subscription domain model.
Before adding code
- Decide whether the change is presentation, orchestration, a pure domain rule, or an external side effect.
- Put it in the owning layer rather than the nearest existing file.
- Reuse an existing application port before importing a provider SDK elsewhere.
- Add focused tests at the same boundary.
- Run the relevant tests, then
npm run typecheck:allandnpm run buildbefore release.
Continue with Environment configuration or Branding and internationalization.