This document provides essential information for AI coding agents working on the Everato event management platform. Everato is a full-stack application with a Go backend API and React TypeScript frontend.
Stack: Go 1.24+ backend, PostgreSQL 15+, React + TypeScript frontend (Vite), TailwindCSS, SQLC for type-safe queries, JWT auth
Structure:
internal/- Go backend (handlers, services, db, middlewares, utils)www/src/- React frontend (components, pages, lib, hooks)pkg/- Public shared libraries (logger, jwt, templates)internal/db/queries/- SQL queries (SQLC generates type-safe Go code)internal/db/migrations/- Database migrations
make build # Production build (embeds static assets)
make dev # Development with hot reload (Air)
make test # Run all tests
go test ./internal/handlers/v1/api/... -v # Test specific package
go test ./internal/services/event/... -run TestName -v # Run single test
go test ./... -v -race -cover -coverprofile=coverage.out # Coverage
make fmt # Format code
make lint # Run golangci-lintcd www
pnpm install # Install dependencies
pnpm dev # Development server
pnpm build # Production build
pnpm lint # ESLint
tsc -b # Type checkmake db # Start PostgreSQL (Docker)
make migrate-up # Apply migrations
make migrate-down # Rollback last migration
make migrate-new # Create new migration (prompts for name)
make sqlc-gen # Generate Go code from SQL queries
make seed # Seed database with test dataStandard library → blank line → third-party → blank line → local imports. Alphabetical within groups.
import (
"context"
"net/http"
"github.com/gorilla/mux"
"github.com/jackc/pgx/v5"
"github.com/dtg-lucifer/everato/internal/db/repository"
"github.com/dtg-lucifer/everato/pkg"
)- Packages: lowercase, single word (e.g.,
event,user,mailer) - Files: snake_case (e.g.,
event_create.go,dashboard_handler.go) - Types/Structs: PascalCase (e.g.,
DashboardHandler,CreateEventDTO) - Functions: PascalCase (exported), camelCase (private)
- Variables: camelCase (e.g.,
eventDTO,userCount) - Constants: PascalCase or UPPER_SNAKE_CASE
All handlers implement Handler interface with RegisterRoutes(router *mux.Router). Structure:
type DashboardHandler struct {
Repo *repository.Queries
Conn *pgx.Conn
BasePath string
Config *config.Config
}
func NewDashboardHandler(cfg *config.Config) *DashboardHandler {
// Initialize logger, connect to DB, return instance
}
func (h *DashboardHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix(h.BasePath).Subrouter()
r.HandleFunc("/stats", h.Stats).Methods(http.MethodGet)
}Always check errors. Use pgx.ErrNoRows for missing records. Log with context. Return appropriate HTTP status codes.
event, err := repo.GetEventBySlug(ctx, slug)
if err != nil {
if err == pgx.ErrNoRows {
wr.Status(404).Json(utils.M{"error": "Event not found"})
return
}
logger.Error("Failed to get event", "error", err)
wr.Status(500).Json(utils.M{"error": "Database error"})
return
}- Write SQL in
internal/db/queries/*.sqlwith SQLC annotations - Run
make sqlc-gento generate type-safe Go code ininternal/db/repository/ - Use uppercase SQL keywords, proper indentation
-- name: GetEventBySlug :one
SELECT * FROM events
WHERE slug = $1 AND deleted_at IS NULL
LIMIT 1;Use pkg.NewLogger(), always defer logger.Close(). Structured logging with key-value pairs.
logger := pkg.NewLogger()
defer logger.Close()
logger.Info("Processing event", "slug", slug, "user_id", userId)
logger.Error("Failed operation", "error", err)- Package-level comments for all packages
- GoDoc format for exported functions/types (comment starts with name)
- Document complex functions with parameter descriptions
React → third-party → local (components, utils, types). Alphabetical within groups.
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { type Event, eventAPI } from "../lib/api";
import Layout from "../components/layout";Functional components with hooks. Interfaces at top. PascalCase names. Export default at bottom.
interface DashboardProps {
userId?: string;
}
export default function DashboardPage({ userId }: DashboardProps) {
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchData();
}, []);
return <Layout>{/* Component JSX */}</Layout>;
}interfacefor API responses and object shapestypefor unions and simple aliases- Export shared types, place in
lib/directory
Use centralized client from lib/api.ts. Handle errors with try-catch. Show loading states. Use async/await.
const fetchEvents = async () => {
try {
setLoading(true);
const response = await eventAPI.getAllEvents();
setEvents(response.data.data.events);
} catch (error) {
console.error("Error fetching events:", error);
} finally {
setLoading(false);
}
};TailwindCSS utility classes. Tab width: 4 spaces (.prettierrc.json). Mobile-first responsive design.
Follow conventional commits: type(scope): Short description
Types: feat, fix, docs, style, refactor, test, chore
feature/short-description- New featuresbugfix/issue-number-short-description- Bug fixesrefactor/component-name- Code refactoringdocs/what-changed- Documentationtest/what-tested- Tests
- Write table-driven tests for Go
- Test success and error cases
- Mock external dependencies
- Use descriptive test names
- Run tests before submitting PRs
- Environment variables in
.env(never commit) - Application config in
config.yaml - Use
utils.GetEnv()with defaults
- CORS (API endpoints)
- Request ID generation
- Logger
- Auth guard (protected routes)
- Timeout
- One handler per file in
internal/handlers/v1/api/ - Group services by domain in
internal/services/{domain}/ - DTOs close to handlers
- Handlers route requests, services contain business logic
- Database queries only in
internal/db/queries/SQL files