Appearance
Repository
Discover how to structure and organize project repositories, including naming conventions, monorepo architecture, package management, and initial setup.
Naming
Repository names should be all lowercase and match the project name exactly, with each project prefixed by the partner name.
zsh
# ✅ Correct
develit-sdk
# ❌ Incorrect
Develit-SDK
DEVELIT-SDK
Develit-sdk
DEVELIT-sdk
develit-SDKStructure
Each project uses a monorepo architecture, containing all related packages in a single repository. Packages are organized into three main directories based on their architectural role and responsibility.
zsh
project-name
├── apps
│ ├── frontend
│ ├── gateway
│ ├── queue-bus
│ └── ...
├── packages
│ ├── sdk
│ ├── shared
│ └── ...
└── services
├── auth
├── notification
├── rbac
└── ...Apps
Software that either provides a user interface for end users or coordinates communication and routes requests across services, handling both synchronous and asynchronous operations.
Examples
- API gateway
- Web application
- Queue bus
Packages
Shared code used across apps, services, and for external integrations.
Examples
- Public SDK
- Shared types
Services
Standalone software responsible for specific domains, managing their own data and operations.
Examples
- Auth service
- Notification service
- RBAC service
Package Manager
All packages and their dependencies are managed by the Bun package manager.
- Use
bunxinstead ofnpxto run packages without installing - Use
buninstead ofnpm,pnpm, oryarnto execute commands
BUN CLI NATIVE COMMANDS
Be careful when executing commands like test or build. These are Bun CLI native commands, which will result in calling Bun's native test runner and bundler.
Calling commands specified in package.json require adding run after bun.
zsh
# ✅ Correct
bun run test # Runs `test` command in `package.json`
bun run build # Runs `build` command in `package.json`
# ❌ Incorrect
bun test # Runs Bun test runner
bun build # Runs Bun bundlerWorkspaces
Bun fully supports npm's native workspaces feature. Each previously outlined group is represented as a workspace.
json
{
"workspaces": [
"apps/*",
"packages/*",
"services/*"
]
}This is later leveraged by Nx, which works seamlessly with Bun workspaces.
Scaffolding
Create a directory called
{project-name}that will serve as the repository root.Create
README.mdfile based on the following pattern:
md
# {project-name}- Create a
package.jsonfile based on the following pattern:
json
{
"name": "{project-name}",
"version": "0.0.0",
"author": "Develit.io s.r.o.",
"private": true,
"type": "module",
"workspaces": [
"apps/*",
"packages/*",
"services/*"
],
"scripts": {
"postinstall": "lefthook install",
"reset": "rm -rf $(find . -name node_modules -o -name .wrangler -o -name dist -o -name tsbuild -o -name bun.lock)",
"dev": "wrangler dev --persist-to ./.wrangler/state",
"deps:graph": "nx graph",
"types": "nx run-many -t types",
"typecheck": "nx run-many -t typecheck",
"lint": "biome check",
"lint:fix": "biome check --fix",
"test": "vitest",
"testcov": "vitest run --coverage",
"test:unit": "vitest unit fixtures",
"test:int": "vitest integration",
},
"devDependencies": {
"@biomejs/biome": "^2.3.9",
"@cloudflare/vitest-pool-workers": "^0.12.3",
"@commitlint/cli": "^20.2.0",
"@commitlint/config-conventional": "^20.2.0",
"@nx/js": "^22.3.3",
"@vitest/coverage-istanbul": "~3.2.4",
"alchemy": "^0.83.1",
"lefthook": "^2.0.15",
"lint-staged": "^16.2.7",
"nx": "^22.3.3",
"typescript": "^5.9.3",
"vite-tsconfig-paths": "^6.0.4",
"vitest": "~3.2.4",
"wrangler": "^4.59.3",
"zod": "^4.2.1"
}
}- Create a
bunfig.tomlfile based on the following pattern:
toml
[install]
linker = "isolated"- Create an
nx.jsonfile based on the following pattern:
json
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"tui": {
"enabled": false
},
"plugins": [
{
"plugin": "@nx/js/typescript",
"options": {
"typecheck": {
"targetName": "typecheck"
},
"build": false
}
}
]
}- Create a
tsconfig.base.jsonfile based on the following pattern:
json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"erasableSyntaxOnly": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"isolatedModules": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"paths": {},
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "ESNext",
}
}- Create a
tsconfig.jsonfile based on the following pattern:
json
{
"extends": "./tsconfig.base.json",
"files": [],
"references": []
}- Create an
alchemy.run.tsfile based on the following pattern:
ts
import type { Project } from '@develit-io/platform-sdk'
import {
Deployment,
composeStateStoreName,
detectEnvironment,
} from '@develit-io/platform-sdk'
import alchemy from 'alchemy'
import { CloudflareStateStore } from 'alchemy/state'
const PROJECT_NAME: Project = '{project-name}'
const app = await alchemy(PROJECT_NAME, {
stateStore: (scope) => {
return new CloudflareStateStore(scope, {
scriptName: composeStateStoreName({ projectName: PROJECT_NAME }),
})
},
stage: detectEnvironment(),
})
const deployment = new Deployment({ project: PROJECT_NAME })
await app.finalize()- Create a
.github/dependabot.yamlfile based on the following pattern:
yaml
version: 2
updates:
- package-ecosystem: github-actions
rebase-strategy: disabled
schedule:
interval: weekly
day: monday
time: '00:00'
directory: /
allow:
- dependency-type: direct
commit-message:
include: scope
prefix: 'chore'
labels:
- Dependencies- Create an
biome.jsoncfile based on the following pattern:
jsonc
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": true,
"includes": [
"**",
"!**/.wrangler",
"!**/dist",
"!**/worker-configuration.d.ts",
"!**/migrations/**/*",
"!**/.output",
"!**/.alchemy/**/*",
"!**/coverage",
"!apps/fe-client/**/*",
"!bun.lock",
"!**/tsbuild"
],
"maxSize": 2000000
},
"formatter": {
"enabled": true,
"indentStyle": "space"
},
"assist": { "actions": { "source": { "organizeImports": "off" } } },
"linter": {
"enabled": true,
"rules": {
"recommended": false,
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": "error"
},
"style": {
"noNonNullAssertion": "off",
"useImportType": "error"
},
"suspicious": {
"noExplicitAny": "error",
"noUnsafeDeclarationMerging": "error"
}
},
"includes": ["**", "!apps/fe-client/assets/css/**"]
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "asNeeded"
}
}
}- Create a
.gitignorefile based on the following pattern:
zsh
# Operating System
.DS_Store
Thumbs.dll
# Environment
.env
.env*.local
next-env.d.ts
# Dependencies
node_modules
# Wrangler
.wrangler
# Vitest
coverage
# IDE
.idea
.vscode
# Alchemy
.alchemy
# Nuxt
.nuxt
# Next
.next
.open-next
# Build
dist
**/.vitepress/cache
# Nx
.nx
# TypeScript
tsbuild
tsconfig.tsbuildinfo- Create a
.envfile based on the following pattern:
zsh
ENVIRONMENT=
CLOUDFLARE_ACCOUNT_ID=
CLOUDFLARE_API_TOKEN=
ALCHEMY_STATE_TOKEN=Create
apps,packages, andservicesdirectories.Execute
bun installcommand at the root.