FaasJS
Home
  • Guide
  • Documents
  • Templates
  • Changelog
  • Ecosystem

    • Docker Images
  • Github
  • Contributing
  • Sponsor
  • Security
Home
  • Guide
  • Documents
  • Templates
  • Changelog
  • Ecosystem

    • Docker Images
  • Github
  • Contributing
  • Sponsor
  • Security
  • Curated Stack Guide
  • Application Slices Guide
  • Project Config Guide
  • File Conventions
  • Code Comments Guide
  • defineApi Guide
  • Jobs Guide
  • Testing Guide
  • React Guide
  • React Data Fetching Guide
  • React Testing Guide
  • Ant Design Guide
  • Node Utils Guide
  • Logger Guide
  • Utils Guide
  • PG Query Builder and Raw SQL Guide
  • PG Table Types Guide
  • PG Schema and Migrations Guide
  • PG Testing Guide
  • CLI and Tooling Guide
  • CRUD Patterns Guide
  • faas.yaml Configuration Specification
  • Getting Started Guide
  • HTTP Plugin Guide
  • HTTP Protocol Specification
  • JSON Guide
  • Middleware Guide
  • Naming Convention
  • Plugin Specification
  • Plugins Guide
  • Routing Mapping Specification
  • Validation Guide
  • YAML Guide

Application Slices Guide

Use this guide when adding a business feature to a FaasJS app or asking an AI coding agent to build one.

A FaasJS application slice is a small, complete vertical feature that keeps UI, API, validation, database changes, CLI tools, jobs, types, and tests easy to find and review together. Slices replace generator-heavy workflows by giving humans and agents stable conventions to follow directly.

What A Slice Includes

A database-driven business slice usually includes:

  • a feature folder under src/features/<feature>/
  • an optional React entry such as src/features/<feature>/index.tsx
  • components, hooks, services, schemas, CLI tools, or jobs owned by that feature
  • one or more .api.ts files under the feature's api/ directory when the feature exposes backend actions
  • inline defineApi schemas for boundary validation
  • PostgreSQL migrations under src/db/migrations/** when data shape changes
  • @faasjs/pg table declarations under src/db/tables/**
  • API tests near the API files
  • PG assertions when database behavior matters
  • React tests when UI request flow, loading, errors, or user interaction matters

Keep the slice small enough that a reviewer can understand the behavior without jumping through unrelated framework layers.

Recommended Layout

The admin starter generated by create-faas-app includes a copyable users slice. For a users slice, prefer a feature-based layout like:

src/db/migrations/20250101000000-create-users.ts
src/db/tables/users.ts
src/features/users/index.tsx
src/features/users/components/UserTable.tsx
src/features/users/hooks/useUserItems.ts
src/features/users/api/list.api.ts
src/features/users/api/create.api.ts
src/features/users/api/__tests__/list.test.ts
src/features/users/api/__tests__/create.test.ts

For nested capabilities, keep them under the owning feature instead of moving them to a detached route, API, or tools tree:

src/features/settings/users/index.tsx
src/features/settings/users/api/list.api.ts
src/features/settings/users/api/update-role.api.ts
src/features/settings/users/api/__tests__/update-role.test.ts

Use short relative imports inside the slice unless an existing TypeScript alias is already configured. Remember that .api.ts and .job.ts paths are externally visible: src/features/users/api/list.api.ts maps to /features/users/api/list, and src/features/users/jobs/sync.job.ts maps to features/users/jobs/sync.

Do not centralize tests in a catch-all package-level src/__tests__ folder. This includes src/__tests__/<feature> sub folders: the feature folder itself should own __tests__. Each feature, slice, API folder, job folder, helper folder, or component folder should own its own __tests__ folder so tests stay attached to the behavior they protect.

When a slice would otherwise be a single business file, turn that file into a folder module and keep its tests under that folder's __tests__:

# Avoid
src/useBilling.ts
src/__tests__/useBilling.test.ts
src/__tests__/useBilling/useBilling.test.ts

# Prefer
src/features/billing/index.ts
src/features/billing/__tests__/billing.test.ts

API, Validation, And Security

Use defineApi for every API entrypoint.

Keep schemas close to the handler unless they are reused across multiple APIs or form a real boundary. Prefer explicit params, explicit returning columns, and narrow response shapes so UI code and tests stay type-aware.

Before reading or mutating data, check whether the slice needs current-user, tenant, organization, project, role, or permission scoping. Put cross-cutting business context in project plugins, then type the injected fields so handlers stay explicit.

Use explicit HTTP status codes for expected business, auth, permission, missing-resource, and conflict failures. Reserve plain unexpected failures for real internal errors.

Avoid generic helpers that hide validation, authorization, database access, or response contracts. A little repetition is acceptable when it makes the slice easier for agents and reviewers to understand.

Database Changes

When a slice changes data shape:

  • add a timestamped migration under src/db/migrations/**
  • update @faasjs/pg table declarations under src/db/tables/<table_name>.ts
  • keep table row types concrete
  • test important database behavior with @faasjs/pg-dev

Do not rely on broad Record<string, any> row shapes for business tables.

UI Changes

Use React and the FaasJS Ant Design path for business UI.

Prefer @faasjs/ant-design wrappers such as Form, Table, Description, Title, Tabs, Loading, and ErrorBoundary when they cover the scenario. Drop to raw Ant Design components only when the wrapper does not fit or the custom UI is clearer.

Keep feature UI state and request flow readable. After create, update, or delete flows, intentionally refresh, close, or invalidate the affected surface and show user feedback. Extract components, hooks, or helpers only when they are reused, create a real boundary, or simplify a large block.

Tests

Put API tests under the API folder's __tests__.

For non-API tests, use the same feature-local layout principle: place React, job, CLI, helper, or integration tests in the __tests__ folder inside the feature, job, utility, or slice folder they cover instead of centralizing them under a detached package-level test tree.

Test the behavior that defines the slice:

  • valid input and expected output
  • validation failures and important error paths
  • database writes, reads, ordering, and counts when relevant
  • permission, tenant, or current-user behavior when a plugin or scoped query affects the API
  • UI request flow when the page contains meaningful interaction

Avoid wide mocks that bypass FaasJS plugins, validation, or database behavior unless the test is intentionally unit-scoped.

Agent Workflow

When asking an AI coding agent to add or change a feature, describe the slice instead of asking for a generator command.

Good prompt shape:

Add a users feature with a list UI, create API, PostgreSQL migration, table types, and API tests. Follow the FaasJS curated stack and keep files under src/features/users.

The agent should:

  • inspect nearby slices and guides first
  • create or update all files needed for the vertical behavior
  • include auth, tenant, and permission scope when the data is user- or organization-specific
  • keep business-specific concerns in app code or plugins
  • run the smallest meaningful tests
  • avoid unrelated refactors

Why Not Rails-style Generators

Rails generators help humans create repetitive structure. FaasJS assumes AI coding agents can write that structure directly when conventions, examples, schemas, and tests are clear.

Invest in better slices, examples, and docs before adding generator commands. Add a generator only when it clearly improves the curated path and cannot be replaced by better conventions or examples.