Techadamia Backend - Codebase Structure
Complete directory structure guide with file descriptions and organization.
Tip
Looking for where something lives? The directory tree below is the fast path. For what each function does, see CODE_DOCUMENTATION.md; for how it all fits together, see ARCHITECTURE.md.
Directory Tree
techadamia-backend/
├── cmd/ # Command-line entry point
│ └── main.go # Startup, config validation, server, shutdown
│
├── internal/ # Internal packages (not importable externally)
│ ├── api/ # HTTP API layer
│ │ ├── routes.go # Route definitions, middleware wiring, limiters
│ │ ├── handlers.go # Core handlers (health, feed, posts, auth, admin, media)
│ │ ├── profile.go # /me, /me/posts, profile edit, password change, public profiles
│ │ ├── social.go # Comments, likes, follows, search handlers
│ │ ├── notifications.go # Notification inbox + the SSE /events stream
│ │ ├── messages.go # Direct-message handlers
│ │ ├── authflows.go # Password reset + email verification endpoints
│ │ ├── responses.go # Response DTOs / row-to-response mapping
│ │ ├── validator.go # Request validation logic
│ │ ├── main_test.go # Test harness / shared setup
│ │ ├── admin_test.go # Admin endpoint tests
│ │ ├── auth_test.go # Auth/login/CSRF tests
│ │ ├── accountflows_test.go # Password reset, verification, SSE tests
│ │ ├── feed_test.go # Feed author/filter/search tests
│ │ ├── media_test.go # Media upload tests
│ │ ├── messages_test.go # Messaging tests
│ │ ├── posts_test.go # Post endpoint tests
│ │ ├── profile_test.go # Profile + reader-role tests
│ │ └── social_test.go # Comment/like/follow/notification tests
│ │
│ ├── service/ # Business logic layer
│ │ ├── services.go # Service struct, constructor, Notifier wiring
│ │ ├── auth.go # Login, bootstrap, sessions, password hashing
│ │ ├── users.go # User management service
│ │ ├── profile.go # Own profile, public profiles, password change
│ │ ├── tokens.go # Password-reset + email-verification tokens
│ │ ├── posts.go # Post management + feed filters + search
│ │ ├── comments.go # Comment lifecycle + reply notifications
│ │ ├── social.go # Likes and follows
│ │ ├── notifications.go # Notification rows + SSE fan-out
│ │ ├── messages.go # Direct messages
│ │ ├── categories.go # Category management service
│ │ ├── media.go # Media handling service
│ │ └── service_test.go # Service-layer tests
│ │
│ ├── middleware/ # HTTP middleware
│ │ ├── middleware.go # CORS, rate limit (in-memory), body cap,
│ │ │ # security headers, CSRF, auth/role gates
│ │ │ # (incl. OptionalAuth for personalization)
│ │ └── ratelimit_redis.go # Redis-backed rate limiter (Lua INCR/PEXPIRE)
│ │
│ ├── realtime/ # In-process SSE hub
│ │ └── hub.go # Per-user subscriber channels, non-blocking publish
│ │
│ ├── mail/ # Transactional email
│ │ └── mail.go # SMTP mailer (587 STARTTLS / 465 TLS; dev log mode)
│ │
│ ├── sql/ # Database layer (mostly SQLC generated)
│ │ ├── db.go # Generated DB interface (sqlc)
│ │ ├── models.go # Generated models + enums (sqlc)
│ │ ├── query.sql # Hand-written query source
│ │ ├── query.sql.go # Generated type-safe query functions (sqlc)
│ │ └── schema.sql # Schema reference for sqlc codegen
│ │
│ ├── utils/ # Utility functions
│ │ ├── utils.go # CSV parse, rate-limit spec parse, slug, etc.
│ │ ├── config.go # Config parsing helpers
│ │ ├── request_id.go # Request ID context + slog handler
│ │ └── security.go # CSRF token generation, cookie/header names
│ │
│ └── migrate/ # Migration runner
│ ├── migrate.go # Embeds and applies migrations (advisory lock)
│ └── migrations/ # Embedded SQL migration files
│ ├── 000_initial_schema.sql
│ ├── 001_add_deleted_status.sql
│ ├── 002_fix_post_automation_trigger.sql
│ ├── 003_streamline_post_trigger.sql
│ ├── 004_add_reader_role.sql
│ ├── 005_profiles_and_auth_tokens.sql
│ ├── 006_social.sql
│ ├── 007_messages.sql
│ └── 008_post_search.sql
│
├── pkg/ # Public packages (currently only .gitkeep)
│ └── .gitkeep
│
├── docker-compose.yaml # Docker Compose configuration
├── Dockerfile # Docker image definition
├── .dockerignore # Docker build ignore rules
├── Taskfile.yml # Task automation (Taskfile)
├── sqlc.yaml # SQLC configuration
├── go.mod # Go module definition
├── go.sum # Go module checksums
├── .env.example # Environment variables template
├── .gitignore # Git ignore rules
│
├── README.md # Project overview and quick start
├── ARCHITECTURE.md # System design and architecture
├── API_REFERENCE.md # API endpoint documentation
├── SECURITY.md # Security implementation guide
├── DEPLOYMENT.md # Deployment instructions
├── DEVELOPMENT.md # Development guide
├── CODE_DOCUMENTATION.md # Code reference
├── CODEBASE_STRUCTURE.md # This document
├── CONTRIBUTING.md # Contributing guidelines
├── REVIEW_CHECKLIST.md # Code review checklist
├── IMPLEMENTATION_SUMMARY.md # Implementation summary
├── DOCUMENTATION_INDEX.md # Documentation index
│
└── uploads/ # User media uploads (created at runtime)
└── [user uploaded files]
Note: generated SQLC files (
db.go,models.go,query.sql.go) should not be edited by hand - changequery.sql/schema.sqland re-runsqlc generate.internal/sql/also contains diagram images and a test-data SQL helper.
Core Packages
cmd/ - Application Entry Point
main.go
- Application startup logic
- Configuration loading
- Database connection setup
- Server initialization
- Graceful shutdown handling
internal/api/ - HTTP Layer
routes.go
- Route registration with Gin
- Middleware setup
- Route grouping (public, protected, admin)
- CORS configuration loading
handlers.go
- Core endpoint handlers (health, feed, posts, register/login, admin, media)
- Cookie / CSRF token issuance, media upload validation
- Error handling and PostgreSQL error normalization at the HTTP level
profile.go / social.go / notifications.go / messages.go / authflows.go
- Feature-grouped handlers: own profile + public profiles; comments, likes,
follows, search; notification inbox + the
GET /eventsSSE stream; direct messages; password reset + email verification flows
responses.go
- Response DTO structs (posts with author/categories/counts, profiles, comments, notifications, conversations, messages, pagination)
- Mapping from SQLC rows to API response shapes
validator.go
- Request body validation (register, post, category, comments, messages, profile fields)
- Field rules (password 8-72, URL-safe username 3-50, 10-digit phone, comment ≤5000 / message ≤2000 chars)
- Error message generation
internal/service/ - Business Logic
services.go
- Service struct definitions with dependencies
- Common service interface patterns
- Dependency injection setup
auth.go - Authentication Service
- Login (bcrypt verify, single-session rotation, last_login_at), with a dummy-bcrypt timing mitigation for unknown emails
- Admin bootstrap (transactional, refuses once an admin exists)
- Session creation/validation, expired-session cleanup
- Password hashing with bcrypt (no JWT, no refresh tokens)
users.go - User Service
- User registration
- Listing users (all, with post counts) and pending users
- Status changes, soft delete, and the last-active-admin guard
posts.go - Post Service
- Post CRUD (transactional create/update with ownership checks; soft delete; archive)
- Recent feed and fetch-by-slug
- Category and media association (with validation)
profile.go / tokens.go - Accounts
- Own profile (
GetMe), public profiles, partial profile updates, password change with session rotation - Password-reset and email-verification tokens (random 32 bytes; SHA-256 hashes stored; single-use; enumeration-safe resolution)
comments.go / social.go / notifications.go / messages.go - Social layer
- Comment lifecycle (threading, edit/delete, admin hide) with owner + reply notifications
- Idempotent likes and follows with notifications
- Notification rows + fan-outs (new post → followers, pending author →
admins, activation → user) pushed over the SSE hub via
service.Notifier - Direct messages with live push to the recipient
categories.go - Category Service
- List categories (flat: name + slug)
- Add a category
media.go - Media Service
- Persist uploaded-media metadata (
storage_key,mime_type, owner) - Orphan-media garbage collection (
DeleteOrphanMedia, run bystartMediaGC; avatars are exempt)
internal/middleware/ - Cross-Cutting Concerns
All middleware lives in two files (there are no separate cors/auth/logging files):
middleware.go
- CORS allowlist (
LoadCORSConfigFromEnv,CORSMiddleware) - In-memory fixed-window rate limiter and
RateLimitMiddleware MaxBodyBytesMiddleware(global body size cap,/mediaexempt)SecurityHeadersMiddleware(nosniff, DENY, Referrer/Permissions, optional HSTS/CSP)CSRFMiddleware(double-submit cookie, constant-time compare)RequestIDMiddleware,AccessLogMiddleware- Auth/role gates:
RequireAuthMiddleware,RequireAuthorMiddleware,RequireAdminMiddleware
ratelimit_redis.go
- Redis-backed fixed-window limiter using a Lua
INCR+PEXPIREscript - Selected automatically when
RATE_LIMIT_REDIS_URLis set
internal/sql/ - Data Access Layer
db.go, models.go, and query.sql.go are generated by SQLC; do not edit
them by hand. Change query.sql / schema.sql and re-run sqlc generate.
query.sql (source)
- Hand-written SQL queries that SQLC compiles into typed Go functions
schema.sql (source)
- Table/enum definitions SQLC reads to type the generated code
db.go (SQLC generated)
- Querier interface,
New,WithTx, and the DBTX abstraction
models.go (SQLC generated)
- User, Post, Category, Media, Session structs
- Enum types:
UserRoleEnum(admin/author),UserStatusEnum(pending/active/suspended/deleted),PostStatusEnum(draft/published/archived)
query.sql.go (SQLC generated)
- Type-safe query functions for all entities (sessions, users, posts, categories, media)
internal/utils/ - Utility Functions
utils.go
- CSV parsing (CORS origins, trusted proxies), rate-limit spec parsing, slug generation, and shared helpers
config.go
- Configuration parsing helpers
request_id.go
- Request ID context propagation and the slog handler that stamps it on logs
security.go
GenerateCSRFToken(32 random bytes, base64url)- CSRF cookie/header name constants (
csrf_token,X-CSRF-Token)
internal/migrate/ - Migration Runner
Migrations live in internal/migrate/migrations/ and are embedded into the
binary (//go:embed). On startup the runner takes a pg_advisory_lock, ensures
a schema_migrations tracking table, and applies any unapplied files in name
order inside a transaction (files marked -- +no-transaction run outside one).
There is no down/rollback support.
Current migration files:
000_initial_schema.sql- initial schema (users, posts, categories, media, sessions, join tables)001_add_deleted_status.sql- adds thedeleteduser status002_fix_post_automation_trigger.sql- fixes a post automation trigger
migrate.go
- Embeds the migration files, acquires the advisory lock, tracks applied versions, and applies pending migrations in order
File Naming Conventions
Go Files
service_type.go # Service implementations (auth.go, users.go)
handler_type.go # Handler implementations (if needed)
middleware_type.go # Middleware implementations
_test.go # Test files (parallel structure)
SQL Files
NNN_description.sql # Numbered migrations (000_, 001_, 002_, ... applied in order)
query.sql # SQLC query definitions
schema.sql # Schema reference for SQLC codegen
Configuration Files
.env # Environment variables (gitignored)
.env.example # Template for environment variables
docker-compose.yaml # Local development container config
Dockerfile # Production container image
sqlc.yaml # SQLC code generation config
Documentation Files
README.md # Project overview
ARCHITECTURE.md # System design
API_REFERENCE.md # API documentation
CODEBASE_STRUCTURE.md # This file
CODE_DOCUMENTATION.md # Code reference
DEVELOPMENT.md # Development guide
SECURITY.md # Security guidelines
DEPLOYMENT.md # Deployment guide
CONTRIBUTING.md # Contributing guidelines
REVIEW_CHECKLIST.md # Code review checklist
IMPLEMENTATION_SUMMARY.md # Implementation overview
DOCUMENTATION_INDEX.md # Documentation index
Code Organization Principles
1. Package by Feature (Not by Layer)
❌ Avoid:
handlers/
user_handler.go
post_handler.go
services/
user_service.go
post_service.go
✅ Prefer:
internal/
service/
users.go # User service
posts.go # Post service
middleware/
auth.go
2. Internal vs Public
- internal/ - Private packages (not importable from outside)
- pkg/ - Public packages (can be imported as a library)
- cmd/ - Executable entry points
3. Dependency Direction
api/ (handlers)
↓ depends on
service/ (business logic)
↓ depends on
sql/ (data access)
↓ depends on
Database
Higher layers depend on lower layers, never the reverse.
4. Test Placement
Tests live in the same package as the code they cover. The API tests are split by feature, and the service layer has a single test file:
internal/api/main_test.go # Shared test harness / setup
internal/api/auth_test.go # Auth, login, CSRF
internal/api/admin_test.go # Admin endpoints
internal/api/media_test.go # Media upload
internal/api/posts_test.go # Post endpoints
internal/service/service_test.go # Service-layer tests
Common File Sizes
| File | Expected Size | Notes |
|---|---|---|
| handlers.go | 500-1000 LOC | All HTTP handlers |
| services.go | 200-400 LOC | Service structs |
| auth.go | 300-500 LOC | Auth service logic |
| users.go | 400-600 LOC | User service logic |
| posts.go | 600-800 LOC | Post service logic |
| routes.go | 200-300 LOC | Route definitions |
| query.sql.go | Auto-generated | Variable size |
| models.go | 500-700 LOC | Model definitions |
Database Connection Flow
main.go
├─ Load configuration
├─ Connect to PostgreSQL
├─ Run migrations
├─ Create pgxpool (connection pool)
├─ Initialize services with pool
├─ Register routes
└─ Start HTTP server
Requests
├─ Handler receives request
├─ Passes to service
├─ Service calls database
├─ Gets connection from pool
├─ Executes query
├─ Returns connection to pool
└─ Returns data to handler
Environment Configuration
Configuration Loading Order:
- Load defaults (in code)
- Load .env file (if exists)
- Load environment variables (override .env)
- Validate required config
- Set up logging based on ENV
Configuration Locations:
- .env - Local development (gitignored)
- docker-compose.yaml - Docker environment
- CI/CD secrets - Production configuration
- Environment variables - Runtime override
Key Data Structures
User
type User struct {
ID pgtype.UUID
Email string
Username string
Role UserRole
Status UserStatus
}
Post
type Post struct {
ID pgtype.UUID
UserID pgtype.UUID
Title string
Slug string
Content string
Status PostStatus
CreatedAt time.Time
}
Session (SQLC generated, simplified)
type Session struct {
SessionID pgtype.UUID // the session id is itself a UUID v4
UserID pgtype.UUID
CreatedAt pgtype.Timestamptz
ExpiresAt pgtype.Timestamptz
}
Media (Medium, SQLC generated, simplified)
type Medium struct {
MediaID pgtype.UUID
UserID pgtype.UUID
StorageKey string // relative filename, not an absolute path
MimeType pgtype.Text
CreatedAt pgtype.Timestamptz
}
Special Directories
uploads/
- User-uploaded media files
- Created on first file upload
- Organized by user ID or date
- Should be in .gitignore
Dependency Management
All dependencies managed through:
- go.mod - Module definition
- go.sum - Module checksums
Key dependencies:
github.com/gin-gonic/gin - Web framework
github.com/jackc/pgx/v5 - PostgreSQL driver
github.com/redis/go-redis - Redis client
github.com/joho/godotenv - .env loading
github.com/google/uuid - UUID generation
github.com/gosimple/slug - Slug generation
Build Artifacts
Generated during build:
- Binary executable (in $GOPATH/bin)
- Docker image
- No additional artifacts in repo
Cleanup and Maintenance
Regular Cleanup
- Remove old log files
- Clear old session data (handled by cleanup job)
- Archive old media (future feature)
Code Quality Checks
go fmt ./... # Format code
go vet ./... # Check for errors
go test ./... # Run tests
go mod tidy # Clean dependencies
Document Version: 1.0 Last Updated: 2026-07-01 Structure Last Reviewed: 2026-05-27