40 KiB
id, aliases, tags
| id | aliases | tags |
|---|---|---|
| The Holy Code Bible |
"Bestowed upon the Devs by the Eternal Syntax, to bring order to the chaos of code."
1. The Law of Variables and Functions
"Name with purpose, type with faith, validate without doubt."
| Realm | Naming Form | Divine Guidance |
|---|---|---|
| Go | camelCase |
Exported → PascalCase (UserService), unexported → camelCase (userService) |
| TypeScript | camelCase |
Strict types everywhere. No any. Prefer interface over type for objects. |
| Constants | PascalCase (Go), UPPER_CASE (TS) |
Go: constants are PascalCase if exported. TS: UPPER_CASE for module-level constants. |
Go Edicts
- Exported identifiers are PascalCase. Unexported are camelCase.
- Acronyms are all-caps:
HTTPHandler,UserID,parseJSON. - No
snake_casein Go identifiers. Ever. - Use short variable names for short scopes (
i,n,err). - Prefer
varfor zero-value declarations,:=for initialization. - Always handle errors. No silent discards.
TypeScript Edicts
- Prefer
constoverlet. Novar. - Never use
any. Useunknownif type is truly unknown. - Use
strict: truein tsconfig. No exceptions. - Never use
==, always===. - Use
interfacefor object shapes,typefor unions/primitives. - Use
as constfor literal types and enums. - Validate input at function boundaries with Zod or similar.
2. The Law of Structure (HTML, CSS, Tailwind)
"Let your style be clean and your markup semantic."
| Type | Style | Notes |
|---|---|---|
| HTML classes | kebab-case | Matches query selectors |
| IDs | kebab-case | Reserved for unique elements |
| File names | kebab-case | Components, pages, layouts |
| Tailwind | utility classes | No custom CSS if Tailwind utility exists |
Sacred Guidelines
- Class names must be semantic and reusable.
- IDs reserved for unique elements and anchor targets.
- No inline styles within templates — Tailwind utilities only.
- Custom CSS lives in
assets/css/with kebab-case filenames. - Tailwind theme is centralized in
tailwind.config.ts. No arbitrary values ([color]) in templates unless absolutely necessary. - Prefer Tailwind's
@applyin component classes only for repeated patterns. - Responsive design first: mobile-first with Tailwind breakpoints.
3. The Law of Files and Folders
"Order in structure is order in mind; chaos begins at the root."
Go Backend Layout
service-name/
├── cmd/
│ └── server/
│ └── main.go # Entrypoint only
├── internal/
│ ├── handler/ # HTTP handlers (1 file per resource)
│ ├── service/ # Business logic
│ ├── repository/ # Database access
│ ├── middleware/ # Auth, logging, CORS, rate limiting
│ ├── dto/ # Request/response types
│ ├── model/ # Domain models
│ └── config/ # Config struct + loader
├── migrations/ # SQL migration files
├── pkg/ # Shared library (if re-usable outside)
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── Makefile
└── README.md
Nuxt/Vue Frontend Layout
frontend/
├── app.vue # Root component
├── nuxt.config.ts
├── tailwind.config.ts
├── pages/ # File-based routing
│ ├── index.vue
│ ├── video/
│ │ ├── index.vue
│ │ └── [id].vue
│ └── blog/
├── components/
│ ├── shared/ # Reusable: Button, Input, Modal
│ └── <domain>/ # Page-specific: video/Player.vue
├── composables/ # useApi, useAuth, usePagination
├── stores/ # Pinia stores: useAuthStore
├── types/ # TypeScript interfaces
├── assets/
│ ├── css/ # Custom CSS files
│ └── images/
├── public/
├── server/ # API routes or middleware (Nuxt server)
├── .env.example
└── README.md
Library Package Layout (e.g., video player, blog editor)
package-name/
├── src/
│ ├── index.ts # Public API
│ ├── components/
│ ├── types/
│ └── utils/
├── dist/ # Built output
├── package.json
├── tsconfig.json
├── vite.config.ts # or tsup.config.ts
├── README.md
└── LICENSE
4. The Immutable Rules of Naming
"A name unspoken in truth shall summon bugs."
| Context | Style | Example |
|---|---|---|
| Go variables/functions (unexported) | camelCase | getUser, parseToken |
| Go functions/types (exported) | PascalCase | GetUser, UserService |
| Go acronyms | ALL CAPS | HTTPHandler, UserID, parseJSON |
| Go files | snake_case | user_handler.go, auth_middleware.go |
| Go tests | snake_case | user_handler_test.go |
| TypeScript variables/functions | camelCase | getUser, parseToken |
| TypeScript types/interfaces | PascalCase | UserResponse, AuthPayload |
| Component files | PascalCase | VideoPlayer.vue, BlogEditor.vue |
| Component names | PascalCase | <VideoPlayer />, <BlogEditor /> |
| CSS classes / IDs | kebab-case | video-container, main-header |
| CSS/Tailwind files | kebab-case | custom-styles.css |
| Constants (Go exported) | PascalCase | MaxRetryCount |
| Constants (Go unexported) | camelCase | maxRetryCount |
| Constants (TS) | UPPER_CASE | MAX_RETRY_COUNT |
| Enums (TS) | PascalCase members | Status.Active, Role.Admin |
| DB tables/columns | snake_case | users, video_id, created_at |
| JSON fields | camelCase | "userId", "videoUrl" |
| Environment variables | UPPER_SNAKE_CASE | DATABASE_URL, REDIS_HOST |
| Docker image tags | lowercase | auth-service:1.0.0 |
| Git branches | kebab-case | feat/video-transcoding, fix/auth-timeout |
| Git commits | Conventional Commits | feat: add video upload endpoint |
| Repository names | kebab-case | video-service, nuxt-commons |
One naming style per context, no deviation. Filenames must mirror their contents exactly. No spaces or special characters.
5. The Scroll of Static Typing
"Types are truth — doubt them and runtime will punish thee."
Go
package user
import "time"
type User struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
CreatedAt time.Time `json:"createdAt"`
}
// GetUser returns a user by ID.
// Returns ErrNotFound if the user does not exist.
func GetUser(id string) (*User, error) {
// ...
}
- Every function returns
errorwhen it can fail. - Use
errorinterface, not custom exception types. - Wrap errors:
fmt.Errorf("get user %s: %w", id, err). - Use
errors.Is()anderrors.As()for error inspection. - Define sentinel errors:
var ErrNotFound = errors.New("user not found").
TypeScript
interface User {
id: string;
email: string;
name: string;
createdAt: string; // ISO 8601
}
// Use Zod for runtime validation
import { z } from "zod";
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
});
type CreateUserInput = z.infer<typeof CreateUserSchema>;
async function createUser(input: CreateUserInput): Promise<User> {
const validated = CreateUserSchema.parse(input);
// validated is fully typed
}
strict: truein tsconfig at all times.- No
any. Useunknown+ type narrowing. - Prefer
interfaceovertypefor object types. - Use
typefor unions, intersections, and primitives. - All API responses have a corresponding TypeScript type in
~/types/. - Use Zod for runtime validation of API inputs and env vars.
6. The Ten Commandments of Clean Code
"Clean code is the only code that survives the test of time."
- One responsibility per function, per type, per file.
- Comment only to explain why, never what.
- No silent errors — handle or propagate every error.
- Always validate and sanitize all input at the boundary.
- No global state — use dependency injection.
- Never push secrets, configs, or build artifacts.
- Consistency outranks cleverness — write boring code.
- Fail fast, log properly, recover gracefully.
- No unused code, no dead branches, no commented-out blocks.
- Every public API must have a meaningful comment explaining what it does.
7. The Standard of the File Header
"Every file must declare its origin before it speaks."
Go
// Package handler provides HTTP handlers for the auth service.
package handler
import (
"net/http"
)
Go files need only the package comment at the top. No author/date boilerplate — Git already has that.
TypeScript/Vue
/**
* File: VideoPlayer.vue
* Purpose: Hand-written video player with HLS.js and WebRTC/WHEP support.
* See: https://git.db123.ir/db/VP
*/
TypeScript/Vue files benefit from a brief purpose comment if the purpose isn't obvious from the name.
8. The Law of Comments
"Explain not the obvious, but the reason behind the mystery."
// GOOD: explains why
// Refresh the token 5 minutes before expiry to avoid race conditions.
if time.Until(token.ExpiresAt) < 5*time.Minute {
token, err = refreshToken(token)
}
// BAD: restates the obvious
// Check if token is about to expire
if time.Until(token.ExpiresAt) < 5*time.Minute {
Same rule applies to TypeScript, Vue, CSS, and all languages:
- Explain intent and context, not syntax.
- No comments for self-documenting code.
- TODO comments must include a ticket/issue reference:
// TODO(db123): handle pagination limits (PROJ-42).
9. The Law of Strictness (Go)
"Without strictness, your logic shall wander."
package main
import (
"log/slog"
)
func main() {
slog.SetLogLoggerLevel(slog.LevelDebug)
// ...
}
- Run
go vet ./...before every commit. - Use
golangci-lintin CI with strict configuration. CGO_ENABLED=0for production builds.- No
panicoutside ofmainand initialization. - Use
errgrouporsync.WaitGroupfor goroutine management. Never usetime.Sleepfor synchronization. - Always set
-racein tests and CI.
10. The Law of Strictness (TypeScript)
"An untyped variable is a vessel for chaos."
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
},
}
- ESLint with
@typescript-eslint/strictconfig. - Prettier for formatting — run
prettier --checkin CI. - TypeScript 5.x+ with
--strictmode. No// @ts-ignoreor// @ts-expect-errorwithout a comment explaining why. - Use
satisfiesoperator for type-safe expressions without widening.
11. The Law of Security
"Trust no input, for deceit lives in every form field."
General
- Never trust user input. Validate and sanitize at every boundary.
- Always use prepared statements for SQL. Never concatenate query strings.
- Escape all HTML output. Use template engines that auto-escape.
- Validate on both client and server.
- Rate limit all public endpoints.
- Disable error display in production. Log instead.
- Never expose
.env, secrets, or stack traces to the client. - Use TLS everywhere. Auto-renew via Let's Encrypt.
Go Specific
- Use
httputilfor reverse proxy security. - Set
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Content-Security-Policyheaders. - Use
bcryptorargon2for password hashing. Never SHA/MD5. - Validate UUIDs with
uuid.Parse()before DB queries.
TypeScript Specific
- Sanitize user input before rendering with
DOMPurify. - Never use
innerHTMLwith user content. UsetextContentor Vue's template binding. - For Nuxt: validate API responses with Zod on the client side.
12. The Law of Git
"Commits are confessions — be honest, be precise."
- Commit atomic changes only.
- Branch names → kebab-case.
- One purpose per branch (feature, fix, etc).
- Commit format:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types:
feat:— New featurefix:— Bug fixdocs:— Documentation onlystyle:— Formatting, no logic changerefactor:— Restructure without behavior changeperf:— Performance improvementtest:— Add or fix testsbuild:— Build system or dependency changesci:— CI config or script changeschore:— Other changes not in src/testrevert:— Revert a previous commit
Scope: Service or package name (e.g., feat(auth):, fix(video-player):).
Footer (optional):
fixes #123breaking change: ...
13. The Law of Configuration
"Keep your secrets sacred and your configs pure."
- All configuration via environment variables. No config files in the repository (except
.env.example). - Every service has a
.env.examplewith all expected vars and sensible defaults. - Config is loaded at startup and immutable after boot.
- Never commit
.env, secrets, or local overrides.
Go Config Pattern
type Config struct {
Port string `env:"PORT" envDefault:":8080"`
DatabaseURL string `env:"DATABASE_URL,required"`
RedisURL string `env:"REDIS_URL"`
JWTSecret string `env:"JWT_SECRET,required"`
}
Nuxt Config Pattern
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBaseUrl: process.env.API_BASE_URL || "http://localhost:8080",
},
},
});
14. The Law of Performance
"Do not make the machine work in vain."
- No unnecessary allocations in hot paths. Pre-allocate slices:
make([]T, 0, n). - Cache expensive queries with Redis. Set TTL appropriate to the data.
- Use connection pooling (DB, Redis, HTTP clients).
- Lazy load Nuxt pages and components.
- Minify assets for production. Nuxt does this by default.
- Use streaming for large responses (video, file downloads).
- Avoid N+1 queries. Use eager loading or batch queries.
- Profile before optimizing. Don't guess.
15. The Law of Naming (Final Recap)
"Every form of name has its place — and none shall trespass."
camelCase -> Go vars (unexported), Go file names, TS vars/functions, JSON fields
PascalCase -> Go exported types/funcs, TS types/interfaces, Vue components
snake_case -> DB tables, DB columns, migration files
kebab-case -> HTML classes, CSS files, Git branches, repo names
UPPER_CASE -> TS constants, env vars (UPPER_SNAKE_CASE)
ALL CAPS -> Go acronyms in identifiers
16. The Law of Environment
"The env is the covenant — never share it, never expose it."
.env.examplechecked into every repository..envin.gitignorefor every repository.- All secrets (DB passwords, API keys, JWT secrets) are environment variables.
- Docker Compose files reference
${VARIABLE}with.envfile. - Production secrets injected via Docker secrets or the orchestrator, never in the image.
17. The Law of Testing
"Faith without tests is blind."
Go
- Unit tests alongside code:
handler_test.go,service_test.go. - Use
testingstdlib +testify/assertortestify/require. - Integration tests in
tests/— use Testcontainers for PostgreSQL/Redis. - Run
go test -race ./...before every push. - Aim for 80%+ coverage on business logic. Critical paths (auth, payments) 90%+.
TypeScript/Vue/Nuxt
- Vitest for unit tests. Test composables, stores, and utility functions.
- Playwright or Vitest browser mode for E2E tests.
- Component tests with
@vue/test-utils+ Vitest. - Run
vitest runbefore every push. - Test API calls in composables by mocking
$fetch.
General
- All logic must be verifiable by tests.
- Unit tests for functions, integration tests for systems.
- Run tests before every merge and deployment.
- Never rely on manual testing alone.
18. The Law of Documentation
"Unwritten knowledge is forgotten truth."
- Every repository requires a
README.mdwith: purpose, local setup steps, env vars, API endpoints. - Every major module or package has a short summary comment.
- Architecture diagrams in
/docs/architecture.md. - Deployment steps in
/docs/deployment.md. - Update docs immediately after code changes.
- Use Markdown and simple language.
19. The Law of Dependencies
"Rely not on that which you do not control."
- Only install what is truly needed.
- Lock dependency versions.
- Remove unused or outdated packages.
- Never commit
vendor/,node_modules/, or build artifacts. - Keep dependency files clean and ordered.
- Pin exact versions in Dockerfiles for base images.
- Regularly audit for vulnerabilities (
govulncheck,npm audit).
20. The Law of Error Handling
"An error unhandled is chaos unleashed."
Go
if err != nil {
return fmt.Errorf("create user %s: %w", email, err)
}
- Always check errors. No
_ =error discards. - Wrap errors with context.
- Define typed sentinel errors for expected failures.
- Use
errors.Is()anderrors.As()for inspection. - Log errors at the boundary (handler), not deep in business logic.
TypeScript
try {
const user = await createUser(input);
} catch (error) {
if (error instanceof ValidationError) {
// handle validation error
}
throw error;
}
- Use typed error classes or Zod validation errors.
- Never catch and swallow without logging or re-throwing.
- In Nuxt: use
useErroror error pages for user-facing errors.
General
- Define global error and exception handlers in every service.
- Never expose raw errors to users — return structured error responses.
- Always fail gracefully with clear internal logs.
21. The Law of Review
"Only through scrutiny does code ascend."
- All significant merges must be reviewed.
- No code enters
mainwithout a second pair of eyes. - Review for: correctness, readability, security, consistency, test coverage.
- A review is protection, not criticism.
- CI must pass before merge (lint, type check, test, build).
22. The Law of Architecture
"Without structure, even perfect code collapses."
- Use layered architecture: Handler → Service → Repository. No skipping layers.
- Each package must be self-contained and dependency-injected.
- Shared code lives in
/internal/or/pkg/— never copied. - Define clear boundaries between layers (API, Business Logic, Data).
- Avoid circular dependencies — they are heresy.
- Services communicate only through defined APIs (REST or events).
23. The Law of Modularity (Services)
"Divide to conquer, integrate to rule."
- Each microservice owns its data. No direct database access across services.
- Services communicate via REST APIs (synchronous) or RabbitMQ events (asynchronous).
- Every service has its own PostgreSQL database and Redis instance.
- API versioning via URL prefix:
/v1/,/v2/. - Event contracts are documented and versioned. Breaking changes = new event type.
- No cross-service shortcuts or "temporary hacks."
24. The Law of API Design
"An API is a contract — break it and integrations shall crumble."
| Rule | Standard |
|---|---|
| Base URL | https://api.db123.ir/v1/{resource} |
| Methods | GET (list/read), POST (create), PUT (replace), PATCH (partial), DELETE (remove) |
| Success response | {"data": ..., "meta": {...}} |
| Error response | {"error": {"code": "ERR_CODE", "message": "...", "details": {...}}} |
| Pagination | ?page=1&per_page=20 → {"page": 1, "per_page": 20, "total": 100, "total_pages": 5} |
| IDs | UUID v7 for all resource IDs |
| Timestamps | RFC 3339 (ISO 8601) in UTC |
| Sorting | ?sort=field:asc,field2:desc |
| Filtering | ?filter[field]=value |
| Status codes | 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable, 429 Too Many, 500 Internal |
Error Codes (Consistent Across All Services)
ERR_VALIDATION — Input validation failed
ERR_NOT_FOUND — Resource not found
ERR_UNAUTHORIZED — Missing or invalid authentication
ERR_FORBIDDEN — Authenticated but insufficient permissions
ERR_CONFLICT — Duplicate resource or state conflict
ERR_INTERNAL — Unexpected server error
ERR_RATE_LIMITED — Too many requests
Every error payload includes a details field with specific field-level errors when applicable.
25. The Law of Database
"Guard thy data as thou guardest thy secrets."
- Each service owns its own PostgreSQL database. No cross-service DB access.
- Migration files in
migrations/, SQL only. Tool:golang-migrate/migrate. - File naming:
YYYYMMDDHHMMSS_description.up.sql/.down.sql. - Connection pool configured via env vars: max open, max idle, max lifetime.
- Table names: plural snake_case (
users,video_metadata). - Column names: snake_case (
created_at,updated_at,video_id). - Primary keys: UUID v7. Never auto-increment integers for public IDs.
- Every table has
created_atandupdated_atcolumns (TIMESTAMPTZ). - Soft deletes:
deleted_at TIMESTAMPTZ NULLfor recoverable data. - Indexes on foreign keys and frequently queried columns.
- Use
EXPLAIN ANALYZEbefore shipping new queries.
26. The Law of Docker
"Build once, run anywhere — but build it right."
Dockerfile Standards
- Multi-stage builds: builder stage + distroless/alpine runtime stage.
CGO_ENABLED=0for Go builds.- Distroless base image for production (
gcr.io/distroless/static-debian12oralpine:3.23). - Non-root user in runtime stage.
- No unnecessary packages in final image.
- Label images:
org.opencontainers.image.source,org.opencontainers.image.version. - Pin base image version digests in CI.
Docker Compose Standards
- One
docker-compose.ymlper service for local development. - Root
docker-compose.ymlat the monorepo root (if any) or a sharedinfra/repo for orchestrating all services locally. - Service names match the repository name.
- Volume mounts for live reload in development.
- Default networks:
internal(service-to-service),external(API gateway).
27. The Law of Observability
"Thou shalt not fly blind."
Logging
- Structured JSON logs via
log/slog(Go) orpino/consola(Nuxt). - Every log line includes:
level,msg,service,request_id,duration,error. - Log levels:
debug(development),info(normal ops),warn(expected issues),error(unexpected failures). - No sensitive data in logs (passwords, tokens, PII).
Metrics
- Every service exposes Prometheus metrics at
GET /metrics. - Standard metrics: request count, request duration (histogram), error count, active connections.
- Business metrics: registered users, videos uploaded, orders placed (per service).
Tracing
- OpenTelemetry with trace ID propagated via
x-trace-idheader. - Trace ID generated at the API gateway if not present.
- Traces across service boundaries via HTTP headers or RabbitMQ message headers.
Health
GET /health— Returns 200 with{"status": "ok"}. Indicates the process is alive.GET /ready— Returns 200 when DB, Redis, and critical dependencies are reachable. 503 otherwise.
28. The Law of Resilience
"Expect failure. Design for it."
- Every outbound HTTP call has a timeout. No infinite waits.
- Use circuit breakers for calls to other services. Return cached or degraded response on failure.
- Retry transient failures with exponential backoff + jitter. Max 3 retries.
- Idempotency keys for mutation endpoints (POST/PATCH) — reject duplicate requests.
- Graceful shutdown: Listen for SIGTERM/SIGINT, drain active connections, finish in-flight requests, then exit.
- Rate limit all public endpoints. Return 429 with
Retry-Afterheader. - Queue-based load leveling: incoming work goes to RabbitMQ, workers consume at their own pace.
29. The Law of Events (RabbitMQ)
"An event is a promise — deliver it or die trying."
- Events for cross-service communication (profile updates, video processed, order placed).
- One exchange per event type, one queue per consumer per service.
- Event payload includes:
event_type,event_id(UUID v7),timestamp,data,version. - Events are durable (persistent delivery). Queues are durable.
- Configure dead letter exchanges for every queue. Messages that fail after 3 retries land in the DLQ.
- Monitor DLQ size. Periodically inspect and manually replay corrected messages.
- Consumers are idempotent — processing the same event twice produces the same result.
- For job priority, use separate queues per priority level. Workers drain high-priority queues first.
- Document every event contract:
docs/events/with schema examples.
30. The Law of Caching (Redis)
"Cache with purpose, expire with discipline."
- Redis is a cache, not a primary data store. Data loss must be acceptable.
- Every cache key has a TTL. No infinite caches.
- Key naming:
service:entity:id(e.g.,auth:user:550e8400). - Use cache-aside pattern: check Redis → miss → query DB → store in Redis with TTL → return.
- Cache invalidation strategies (choose by data type):
- TTL: Let data expire naturally. Good for slightly-staleable data.
- Explicit invalidation: Delete/update cache keys when source data changes. Requires discipline.
- Tag-based: Assign tags to related cache entries and delete by tag on updates. Complex but powerful.
- Use Redis for: session data, rate limiting counters, job queues (via RabbitMQ if async needed), hot data with low TTL.
- Do NOT store large objects in Redis. Use S3 for blobs, Redis for metadata.
- Connection pooling with timeout. Handle Redis failures gracefully — fall back to DB.
31. The Law of Continuous Integration
"Let machines judge first, lest chaos reach production."
CI Pipeline (.gitea/workflows/build.yml)
- Lint (
golangci-lint/eslint) - Type check (
go vet/tsc --noEmit) - Unit tests + integration tests (with
-raceflag for Go) - Vulnerability scanning:
govulncheck(Go),npm audit(TS), Trivy (Docker image CVEs) - Build Docker image (multi-stage, distroless, non-root)
- Push to registry (tagged
:latest,:{{sha}}, and semver tag) - Deploy to dev environment
- Health check after deploy
Requirements
- CI runs on every push to any branch.
- No merge allowed on failed pipelines.
- Staging mirrors production environment.
- Production deploys only from
mainvia CI/CD. - Tag releases semantically:
v1.2.0,v1.2.1.
32. The Law of Deployment
"Release with reverence, rollback with readiness."
- Blue-green deployments via Docker Compose (different project names:
-p auth-blue,-p auth-green). - Health check passes before traffic switches.
- Rollback by switching back to the previous stack.
- Database migrations run before the new version starts.
- Migrations must be backward-compatible (add columns/drop columns in separate releases).
- Never deploy on Friday unless you enjoy weekend debugging.
33. The Law of Version Control Discipline
"Branches are parallel worlds — merge only when peace is achieved."
mainis stable and deployable at all times.- Feature branches from
main. Squash merge with conventional commit message. - PR description includes: what changed, why, how to test, screenshots (if UI).
- No direct pushes to
main. Only merge requests. - Keep a
CHANGELOG.mdper service for every release.
34. The Law of Cross-Cutting Concerns
"Some truths apply everywhere — code them once."
| Concern | Standard |
|---|---|
| Health checks | GET /health (alive), GET /ready (dependencies) |
| Metrics | GET /metrics (Prometheus format) |
| Tracing | x-trace-id header propagated. OpenTelemetry spans. |
| Graceful shutdown | SIGTERM → drain → shutdown (max 30s) |
| Rate limiting | Per-IP, per-route configurable. 429 with Retry-After. |
| CORS | Whitelist *.db123.ir origins. No wildcard in production. |
| Auth | JWT bearer token. Validated in middleware. Forward user info via context. |
35. The Law of the API Gateway
"The gateway is the gatekeeper — let nothing pass untested."
Tool
- Start with Nginx. Migrate to Traefik when you need dynamic service discovery (Traefik reads container labels and auto-configures routes).
Standards
- Route by path prefix:
api.db123.ir/v1/auth/*→ auth service,api.db123.ir/v1/video/*→ video service. - SSL termination with Let's Encrypt auto-renewal (Certbot or Traefik automatic).
- Rate limiting per IP at the gateway level. Return
429withRetry-Afterheader. - Inject
X-Request-Idif missing. Forward to upstream services. - Enable HTTP/2 for better client performance.
- Set security headers:
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Content-Security-Policy. - Strip the version prefix when proxying to services (configurable per service).
- CORS headers for allowed origins. Whitelist
*.db123.ir. - Serve static assets (CDN) with appropriate cache headers and far-future expiry.
36. The Law of the Frontend (Nuxt)
"The frontend is the face of thy platform — make it consistent and swift."
- Shared Tailwind theme in
tailwind.config.tswith brand colors, spacing, typography. - No inline arbitrary Tailwind values. All values in the theme config.
- Centralized API client in
~/composables/useApi.tswith auth header injection, error normalization, request/response logging. - Pinia stores per domain:
useAuthStore,useVideoStore,useBlogStore. - Every domain page uses its own layout in
~/layouts/. - Shared UI components (Button, Input, Modal, Card) in
~/components/shared/. - Import the video player and blog editor as npm packages from the local Gitea registry.
- TypeScript types for every API response in
~/types/. - Use
useAsyncDataoruseFetchwith proper keys for cache deduplication. - No inline styles. No
styletag withoutscopedand only when Tailwind can't express it.
37. The Law of Tailwind
"Utility classes are the atoms of your design — combine them with discipline."
- Customize the default theme via
tailwind.config.ts. Never override base styles with custom CSS unless absolutely necessary. - Use
@applyin component classes only for patterns that appear in 5+ places. - Responsive design: use Tailwind breakpoints (
sm:,md:,lg:,xl:,2xl:). Mobile-first. - Dark mode via
classstrategy. Toggle with a JS class on<html>. - No inline
styleattributes. No<style>tags withoutscoped. - Colors, fonts, spacing all come from
theme.extendin config. - Use
groupandpeervariants for state-based styling. - Animations: use Tailwind's built-in
animate-or define custom keyframes intheme.extend.animation.
38. The Law of File Storage (Minio / S3)
"Blobs belong in buckets, not in databases."
- Use Minio (S3-compatible) for all file storage: user uploads, images, documents, video assets.
- Pre-signed URLs: Instead of routing file uploads through your backend, generate pre-signed URLs. Clients upload directly to Minio, then notify the backend to process the file.
- Buckets are private by default. Use pre-signed URLs for controlled access.
- For public assets, put a CDN (e.g. Cloudflare) in front of Minio.
- Configure lifecycle policies to automatically expire old or temporary objects.
- Enable versioning and object locking for protection against accidental deletion.
- Mirror buckets to remote storage for disaster recovery.
39. The Law of Reliable Messaging (Outbox Pattern)
"Publish not without protection, lest thy message be lost to the void."
- In the same database transaction as your business data, insert a record into an
outboxtable containing the serialised message. - A separate relay process (outbox relay) polls the outbox table and publishes messages to RabbitMQ.
- After successful publication, mark the outbox record as sent or delete it.
- This guarantees at-least-once delivery — the message survives service crashes.
- Consumers must be idempotent: include a unique
message_idand skip already-processed messages.
40. The Law of Sagas (Distributed Transactions)
"A transaction spanning services is a journey — prepare for detours."
When a business process spans multiple services (e.g. Place Order → Reserve Inventory → Process Payment → Ship):
- Choreography: Each service listens to events, performs its local transaction, then emits the next event. Simple flows only.
- Orchestration: A central saga coordinator sends commands to each service and handles compensation (rollback) if a step fails. Use for complex flows.
- Every saga step must be idempotent.
- Design compensating transactions for every mutating step.
41. The Law of Schema Management
"Contracts between services are sacred — version them or break them."
- Define event and API schemas in a shared repository or registry.
- Use JSON Schema for simple JSON payloads, Protobuf or Avro for compact binary formats.
- Version every schema:
order.v1.Event,order.v2.Event. - Never change a schema without versioning — old consumers must not break.
- Run contract tests in CI to verify producers and consumers agree on the schema.
42. The Law of the BFF (Backend For Frontend)
"The frontend shall not chase a dozen services — one gate, one answer."
- Introduce a thin BFF service specifically for the Nuxt.js app.
- The BFF aggregates data from multiple microservices into a single response.
- It handles authentication, forwards user context, and hides internal service layout.
- Implement as a dedicated Go service or use the API gateway for basic aggregation.
- Direct file uploads: client requests a pre-signed URL, uploads directly to Minio, then notifies the BFF via API to process the file.
43. The Law of Alerting
"A silent failure is a failure twice over."
- Configure Prometheus Alertmanager with rules for:
- High HTTP error rate (5xx > 1% of traffic)
- RabbitMQ queue depth exceeding threshold
- Disk space running low (< 20%)
- Service unavailable (health probe fails)
- Route alerts to a notification channel (Telegram, Slack, email).
- Set up on-call rotation for production incidents.
- Every alert must be actionable — no alert fatigue.
44. The Law of Feature Flags
"Deploy is not release — separate the act from the unveiling."
- Decouple deploying code from releasing features using configuration-driven flags.
- Use environment variables or a lightweight feature-flag service.
- Enable features for a percentage of users for gradual rollout.
- Instantly disable broken features without redeploying.
- Perform A/B testing by routing different user cohorts to different flag values.
- Remove flags once the feature is fully rolled out and stable.
45. The Law of Backup and Disaster Recovery
"A backup untested is a prayer unanswered."
- PostgreSQL: Schedule automated
pg_dumpor use WAL archiving for Point-In-Time Recovery. Store off-site. - Redis: Configure RDB snapshots (if used for persistence) and backup those files.
- Minio: Mirror buckets to remote storage using
mc mirroror bucket replication. - Elasticsearch: Take snapshots to a shared repository (S3/Minio).
- Test restores regularly — if you haven't tested it, it's not a backup.
- Document the disaster recovery runbook and practice it.
46. The Law of Infrastructure as Code
"Servers built by hand are cattle without brands — untracked, unversioned, unrepeatable."
- Define all infrastructure (servers, networks, databases, DNS) using Terraform or Pulumi.
- Store IaC configurations in Git. Review changes via merge requests.
- Replicate environments (dev, staging, production) from the same codebase.
- Never SSH into servers to make manual changes — if it's not in code, it doesn't exist.
47. The Law of Cost Management
"Thou shalt not waste compute on idle thoughts."
- Set Kubernetes resource requests and limits on every container.
- Right-size database instances — monitor and adjust.
- Define retention policies on logs, metrics, and cached data.
- Monitor cloud/electricity bills and set budget alerts.
- Use spot/preemptible instances for non-critical workloads.
- Remove unused resources: orphaned volumes, stale load balancers, idle instances.
"Code shall read like scripture: strict, clean, and unambiguous. Cleverness is temptation; clarity is salvation." — db123
Thus ends the Holy Code Bible. Follow it, or face undefined behavior.