Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/LMendoza70/SSA/llms.txt

Use this file to discover all available pages before exploring further.

A codebase designed to survive 10 years and multiple contributor rotations cannot rely on tribal knowledge. Conventions are the written contract that lets a developer who joins the project in year five read code written in year one and immediately understand its intent, its location, and its role in the system. Every rule in this document exists to reduce cognitive load, prevent ambiguity, and make the correct pattern easier to find than an incorrect one. When in doubt, consistency with the existing codebase is more valuable than a locally “better” solution.

TypeScript

Strict TypeScript is non-negotiable. The tsconfig.json in both the frontend and backend projects has "strict": true enabled with no overrides or suppressions. This catches entire classes of bugs at compile time that would otherwise surface only in production.
  • strict: true is enabled in tsconfig.json — no exceptions
  • Never use any — use unknown and narrow with type guards instead
  • Prefer interfaces over type aliases for object shapes
  • Prefer interfaces over classes for data structures (unless NestJS requires a class for decorators)
// ❌ Avoid
const process = (data: any) => { ... };

// ✅ Correct
const process = (data: ContentCreateDto): Promise<Content> => { ... };
The only acceptable use of any is in test mocks where a third-party library type is impossible to satisfy. It must be accompanied by an inline comment explaining why.

Naming Conventions

Consistent naming is the fastest way to find code. Follow these conventions without exception across both frontend and backend:
ItemConventionExample
Fileskebab-casecontent-service.ts
React ComponentsPascalCaseContentCard.tsx
VariablescamelCasecontentList
ConstantsUPPER_SNAKE_CASEMAX_FILE_SIZE
InterfacesPascalCase (no I prefix unless conflict)ContentService
EnumsPascalCaseContentStatus
Database tablessnake_casecontent_embeddings
When an interface and a class share the same name (e.g. a NestJS service both implements an interface and is itself a class), prefix the interface with I to resolve the conflict: IContentService vs ContentService.

File Organization

Both projects follow a predictable directory layout. If you know the module and the layer, you know exactly where the file lives.

Backend

Each module is a self-contained vertical slice. No module reaches directly into another module’s internals — all cross-module communication goes through public service interfaces.
src/
  modules/
    cms/
      controllers/
        content.controller.ts
      services/
        content.service.ts
      repositories/
        content.repository.ts
      dto/
        create-content.dto.ts
        update-content.dto.ts
      entities/
        content.entity.ts
      validators/
      tests/
    auth/
    multimedia/
    ...
  shared/
    interfaces/
    constants/
    utils/
  main.ts

Frontend

src/
  pages/         # Route-level components
  components/    # Reusable UI components
  hooks/         # Custom React hooks
  services/      # API call functions
  stores/        # Global state (if needed)
  schemas/       # Zod schemas
  types/         # TypeScript interfaces
  utils/         # Pure utility functions
  constants/
  assets/
  App.tsx
  main.tsx
Test files live alongside the code they test, not in a separate top-level __tests__ directory. See the Testing page for details.

NestJS Layer Rules

NestJS’s three-layer model is enforced strictly. Mixing responsibilities across layers is the most common source of code that is hard to test and hard to change.
1

Controllers handle requests and responses only

A controller method validates authentication, extracts data from the request, calls a service method, and returns the result. It contains no business logic, no database calls, and no conditional branching beyond HTTP-level concerns.
2

Services contain all business logic

Every rule, calculation, workflow, and decision lives in a service. Services are the most-tested layer — every public method must have at least one unit test.
3

Repositories handle all data access

Direct Prisma calls live only in repository classes. Services never call Prisma directly. This boundary makes it trivial to swap the persistence layer or mock data access in tests.
4

Dependencies are injected, never instantiated

Use NestJS constructor injection for every dependency. Never call new MyService() manually inside another class. This is what makes unit testing with mocks possible.

React Component Rules

  • Use only functional components — class components are not permitted
  • Extract reusable logic into custom hooks in src/hooks/
  • Keep components focused: a component that manages data fetching and renders a complex layout should be split into a container and a presentational component
  • Never fetch data directly inside a component with raw useEffect — use TanStack Query hooks instead

Git Commit Format

All commits follow the Conventional Commits specification. This enables automated changelog generation and makes git log readable as a project history.
type(scope): description

feat(cms): add content scheduling
fix(auth): correct refresh token expiry
refactor(multimedia): extract hash computation
docs(readme): update setup instructions
test(timeline): add unit tests for event filtering
chore(deps): update prisma to 5.8
Permitted types:
TypeWhen to use
featA new feature visible to users or API consumers
fixA bug fix
refactorCode change that neither adds a feature nor fixes a bug
docsDocumentation only
testAdding or correcting tests
perfPerformance improvement
choreTooling, dependencies, configuration
Do not use generic messages like fix: various changes or chore: updates. Every commit message must describe what changed and why it changed, not just that something changed.

Code Quality Rules

These rules are enforced during code review. A pull request that violates them will not be merged regardless of whether the tests pass.

No dead code

Remove commented-out code blocks and unused imports before opening a PR. Version control exists for history — there is no reason to keep dead code in the working tree.

DRY — no duplicate logic

If the same logic appears in two places, it belongs in a shared utility or a base class. Duplication is a debt that compounds — every future change to that logic must be made in multiple places.

Single Responsibility

Functions and classes do one thing. A function longer than ~30 lines is a signal to decompose. A service that handles authentication, file uploads, and email sending is three services.

No magic numbers

Every numeric or string literal that carries business meaning must be extracted to a named constant in src/shared/constants/ (backend) or src/constants/ (frontend). MAX_FILE_SIZE_MB = 10 is self-documenting; 10 is not.

Security Baseline

Every endpoint — without exception — must enforce the following chain before any business logic runs:
  1. Authentication — Is the caller who they claim to be? (JWT guard)
  2. Authorization — Does the caller have permission for this action? (role guard)
  3. DTO validation — Does the request body conform to the expected shape? (class-validator pipe)
  4. Sanitization — Is user-supplied input free of injection payloads?
Never trust data sent by the client. Validate and sanitize everything server-side, even if the frontend already validates the same data.

Tech Stack

Library choices, versions, and rationale.

Testing Strategy

Unit and integration testing patterns for each layer.

API Conventions

REST endpoint naming, versioning, and error response formats.

Architecture Overview

Modular monolith structure and Clean Architecture layers.

Build docs developers (and LLMs) love