system-design — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited system-design (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill provides the knowledge base for designing and reviewing fullstack applications built with Go (backend) and React (frontend) with PostgreSQL as the data layer. It covers two operating modes:
Endpoint Naming Conventions:
/api/v1/users, /api/v1/projects/api/v1/users/{id}/api/v1/projects/{id}/tasks?status=active&sort=created_at&order=desc&page=1&limit=20/api/v1/, /api/v2//api/v1/user-profilesHTTP Methods:
| Method | Purpose | Idempotent | Request Body | Success Code |
|---|---|---|---|---|
| GET | Retrieve resource(s) | Yes | No | 200 |
| POST | Create resource | No | Yes | 201 |
| PUT | Full replace | Yes | Yes | 200 |
| PATCH | Partial update | Yes | Yes | 200 |
| DELETE | Remove resource | Yes | No | 204 |
Standard Status Codes:
200 OK -- Successful GET, PUT, PATCH201 Created -- Successful POST (include Location header)204 No Content -- Successful DELETE400 Bad Request -- Validation errors, malformed input401 Unauthorized -- Missing or invalid authentication403 Forbidden -- Authenticated but not authorized404 Not Found -- Resource does not exist409 Conflict -- Duplicate resource, version conflict422 Unprocessable Entity -- Semantically invalid input500 Internal Server Error -- Unexpected server failureStandard Error Response Schema:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable description",
"details": [
{
"field": "email",
"message": "must be a valid email address"
}
]
}
}Pagination Response Envelope:
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 142,
"total_pages": 8
}
}Table Conventions:
users, project_tasks)created_at, user_id)id UUID PRIMARY KEY DEFAULT gen_random_uuid(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()deleted_at TIMESTAMPTZ column (nullable, NULL = active)ON DELETE clause (CASCADE, SET NULL, or RESTRICT)Migration Conventions:
001_create_users.up.sql, 001_create_users.down.sqlgolang-migrate/migrate or pressly/goose formatCommon Patterns:
-- Audit columns trigger
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Apply to every table
CREATE TRIGGER set_updated_at
BEFORE UPDATE ON {table_name}
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();
-- Soft delete index (only index active rows)
CREATE INDEX idx_{table}_active ON {table} (id) WHERE deleted_at IS NULL;Relationship Patterns:
user_id UUID REFERENCES users(id))user_roles with user_id + role_id)parent_id UUID REFERENCES categories(id))Component Hierarchy:
App
Layout
Header (auth state, navigation)
Sidebar (navigation menu)
Main
Page (route-level, fetches data)
Container (state logic, data transformation)
Presentational (UI rendering, props only)Component Classification:
pages/): Route entry points. Own data fetching via hooks. Pass data down.containers/): Business logic, state management, API calls. Minimal JSX.components/): Pure rendering. Props in, JSX out. No side effects.layouts/): Page structure (header, sidebar, footer). Render children.State Management Strategy:
useState / useReducer (form inputs, toggles, modals)Props Flow Rules:
children for composition over configuration.File Naming:
UserProfile.tsx, TaskList.tsx)use prefix (useAuth.ts, useTasks.ts)formatDate.ts, validators.ts)types.ts or User.types.ts)Standard Layout (handler -> service -> repository):
cmd/
server/
main.go # Entry point: config, DI, server startup
internal/
config/
config.go # Environment/config loading
handler/
user_handler.go # HTTP handlers (parse request, call service, write response)
user_handler_test.go
middleware.go # Auth, logging, CORS, recovery middleware
service/
user_service.go # Business logic (validation, orchestration, rules)
user_service_test.go
repository/
user_repository.go # Database access (queries, transactions)
user_repository_test.go
model/
user.go # Domain models (structs, enums, constants)
errors.go # Domain error types
dto/
user_dto.go # Request/response DTOs (separate from domain models)
validation.go # DTO validation rules
router/
router.go # Route definitions, middleware chaining
pkg/
response/
response.go # Standard JSON response helpers
pagination/
pagination.go # Pagination parsing and response
migrations/
001_create_users.up.sql
001_create_users.down.sql
api/
openapi.yaml # OpenAPI 3.0 specificationLayer Responsibilities:
| Layer | Does | Does NOT |
|---|---|---|
| Handler | Parse HTTP request, validate input, call service, write HTTP response | Contain business logic, access DB directly |
| Service | Business rules, validation, orchestrate repositories, error wrapping | Know about HTTP, parse requests, write responses |
| Repository | SQL queries, scan results into models, manage transactions | Contain business logic, know about HTTP |
| Model | Define domain types, constants, domain errors | Import from handler/service/repository |
| DTO | Define API request/response shapes, input validation | Contain business logic |
Dependency Direction:
handler -> service -> repository
| | |
v v v
dto model modelHandlers depend on services. Services depend on repositories. All depend on models. Never reverse this flow.
Interface Pattern (dependency injection):
// Define interface in the CONSUMER package (service defines what it needs from repo)
type UserRepository interface {
GetByID(ctx context.Context, id uuid.UUID) (*model.User, error)
Create(ctx context.Context, user *model.User) error
Update(ctx context.Context, user *model.User) error
Delete(ctx context.Context, id uuid.UUID) error
List(ctx context.Context, filter UserFilter) ([]model.User, int, error)
}
// Implement in the PROVIDER package
type userRepository struct {
db *sql.DB
}
func NewUserRepository(db *sql.DB) UserRepository {
return &userRepository{db: db}
}Error Handling:
model/errors.go// model/errors.go
var (
ErrNotFound = errors.New("resource not found")
ErrAlreadyExists = errors.New("resource already exists")
ErrForbidden = errors.New("access denied")
)Request/Response Type Rules:
id, no created_at)id, timestamps)omitempty on optional fields in Go structsGo DTO Patterns:
// CreateUserRequest -- POST /api/v1/users
type CreateUserRequest struct {
Email string `json:"email" validate:"required,email"`
Name string `json:"name" validate:"required,min=2,max=100"`
Password string `json:"password" validate:"required,min=8"`
}
// UserResponse -- returned by all user endpoints
type UserResponse struct {
ID uuid.UUID `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// ListResponse[T] -- generic paginated response
type ListResponse[T any] struct {
Data []T `json:"data"`
Pagination Pagination `json:"pagination"`
}TypeScript API Types (frontend mirror):
// types/api.ts
interface CreateUserRequest {
email: string;
name: string;
password: string;
}
interface UserResponse {
id: string;
email: string;
name: string;
created_at: string;
updated_at: string;
}
interface PaginatedResponse<T> {
data: T[];
pagination: {
page: number;
limit: number;
total: number;
total_pages: number;
};
}Conformance Checking (Design vs Implementation):
Anti-Pattern Detection:
| Anti-Pattern | What to Flag | Correct Pattern |
|---|---|---|
| Fat handler | Business logic in handler | Move to service layer |
| Anemic service | Service just passes through to repo | Add validation/rules to service |
| Direct DB in handler | sql.DB used in handler | Use repository interface |
| God component | React component > 200 lines | Split into container + presentational |
| Prop drilling | Props passed > 2 levels | Use Context or composition |
| Raw SQL strings | Unparameterized queries | Use parameterized queries ($1, $2) |
| Missing error handling | Unchecked err returns | Always check and handle errors |
| N+1 queries | Query in a loop | Use JOINs or batch queries |
| Hardcoded config | Connection strings in code | Use environment variables |
| Missing indexes | FK columns without indexes | Add indexes on FK columns |
Severity Levels:
net/http."strict": true in tsconfig.model/errors.go.context.Context as first parameter.TIMESTAMPTZ values stored and transmitted in UTC.snake_case in JSON (Go tags + TypeScript interfaces must match).references/. Changes to SKILL.md or scripts/ require user approval.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.