Problem: Full-stack social networking platforms require complex real-time capabilities (WebSockets presence, typing channels, group events), pluggable databases, caching, message queues, and clean architecture boundaries, which monolithic codebases often bundle into tightly-coupled, non-portable, and untestable code.
Solution: A reference Go backend utilizing clean vertical-slice architecture where each package encapsulates its HTTP/WebSocket handlers, business queries/commands (CQRS), and data storage adapters. Features a modern glassmorphic Next.js frontend and configuration-driven pluggable infrastructure (SQLite β PostgreSQL, memory β Redis, memory β RabbitMQ).
To configure your local environment for development and testing, install the following runtimes and tools:
-
Go 1.25+: Install the standard library runtime from go.dev/dl.
-
Bun: The fast JavaScript package manager and runtime. Install via:
curl -fsSL https://bun.sh/install | bash -
Docker & Docker Compose: Essential for orchestrating backend/frontend services in a containerized environment.
-
Install All Project Dependencies: Run the single unified install command:
make install
This installs everything: Go modules, root JS tooling,
.envconfig, SSL certs, Go development tools (gofumpt,goimports,staticcheck,golangci-lint,govulncheck,gosec,go-arch-lint, lefthook), git hooks, and frontend dependencies.If you only need Go tools (without frontend/certs/env), use
make setup.
-
Configure Environment Variables
Create a.envfile at the root:SERVER_PORT=8080 CLIENT_PORT=3000 DATABASE_DRIVER=sqlite DATABASE_DSN=db/data/forum.db?_journal_mode=WAL&_busy_timeout=5000 DB_SEED_ON_START=true GITHUB_CLIENT_ID=your_github_client_id GITHUB_CLIENT_SECRET=your_github_client_secret GOOGLE_CLIENT_ID=your_google_client_id GOOGLE_CLIENT_SECRET=your_google_client_secret
-
Boot the Platform
Build and start both the backend API and Next.js frontend services:make docker-up
To run the development setup with code mounting and hot reload:
make docker-dev # Or use the alias: make dev -
Access points
- Frontend web App: http://localhost:3000
- Backend REST API: http://localhost:8080/api/v1
-
Shutdown and Clean
Stop the services:make docker-down
Purge volumes, cache, and DB files:
make docker-clean
Run the database migrations and boot the Go API Server:
# Run server (database is initialized automatically via migrations runner)
go run cmd/server/main.goThe local SQLite file is generated at db/data/forum.db (or as configured per DB_PATH in .env).
Install dependencies and run the Next.js development server:
cd frontend
bun install
bun run dev- Getting Started
- System Architecture
- Core Features (Finished Product)
- Core Design Decisions
- Project Structure
- Technology & Tooling
- Testing & Code Quality Gates
- Documentation Reading Order
- Agentic Workflows
- Contribution & Onboarding Workflow
- Related
- License
The application separates client presentation, server business rules, and pluggable infrastructure services:
graph TD
Client[Browser: Next.js + shadcn/ui] <-->|REST API / WebSockets| Backend[Go Backend: Port 8080]
Backend <-->|platform/database| SQLite[(SQLite: WAL Mode)]
Backend -.->|platform/eventbus| RabbitMQ[(RabbitMQ: Async Events)]
Backend -.->|platform/cache| Redis[(Redis: Session Cache)]
- Next.js App Router (Port 3000): Server-side and client-side rendering with shadcn/ui.
- Real-time Communication: Persistent WebSockets for chats and Server-Sent Events (SSE) for live notifications.
- Client Verification: Native Unicode emoji parsing, magic-byte image validation, and client-side file size and extension checks before transport.
- Vertical Slices with CQRS (Port 8080): Organized under
internal/<feature>/. Each slice wraps domain entities, CQRS commands/queries, HTTP/WebSocket transports, and SQLite storage implementations. - Cross-Cutting Core: Reusable utilities, session tracking, WebSocket hubs, and route routers live under
internal/core/.
- Infrastructure Adaptability: Databases, event brokers, and caches sit behind abstract interfaces in
internal/platform/. Changing the concrete implementation (e.g., swapping SQLite for PostgreSQL or in-memory events for RabbitMQ) requires zero modification to feature slices.
- Rich Registration: Custom flow requiring Email, Password, First Name, Last Name, and Date of Birth. Optional Avatar, Nickname, and About Me info.
- Secure Sessions: Persistent double-cookie auth (
access_tokenandrefresh_tokenrotation) behindHttpOnlyand secure flags. - OAuth Delegation: Built-in GitHub and Google authentication.
- Privacy Toggle: Seamlessly switch profiles between Public and Private via a confirmation overlay.
- Auto-follow / Request Flow: Public profiles accept follows instantly. Private profiles create a follow request, triggering a notification for the user to Accept or Decline.
- Image Support: Attach JPEG, PNG, and GIF files (magic-byte validated).
- Privacy Scopes:
public: Visible to everyone.almost_private: Restrained to current followers.private: Restricted to selected followers chosen via a user picker.
- Real-time Handshake: Secure WebSocket connections with session token checks on handshakes.
- Follower Validation: Direct messages are follow-gated (at least one user must follow the other).
- Rich Client UX: Unicode emoji support, typing indicators, active presence tracking, and message-read status.
- Group Chats: Automatic WebSocket rooms created for group members.
- Group Spaces: Create groups with title/description, invite followers, request to join, and publish group-exclusive posts.
- Event Planning: Schedule events with a title, description, date/time, and RSVP options (Going vs. Not Going). RSVPs sync in real-time.
- Dedicated panel (visually distinct from chat messages) showing instant alerts for:
- Follow requests received & accepted.
- Group invitations & join requests.
- Group event creation.
Every developer and sub-agent must adhere to these architectural guidelines:
- D1: Vertical Slices (Area: Vertical Slices) β All business logic for a feature lives in
internal/<feature>/. Commands (writes) and queries (reads) reside in separate files insidecommands/andqueries/. Stores and transports are thin, unified per-feature. - D2: Interface Strategy (Area: Interface Strategy) β Within a slice, commands/queries accept the full
Repositoryinterface from<feature>.go. Across slices, consumer features define narrow local interfaces satisfied implicitly via Go duck typing. - D3: Communication (Area: Communication) β Slice communication is ID-only for data references, narrow local interfaces for synchronous checks, and the Platform Event Bus for mutation side effects.
- D4: Database Access (Area: Database Access) β Feature stores accept
platform/database.DBinterfaces rather than raw*sql.DB. The connection factory switches between SQLite (WAL mode + busy timeout) and PostgreSQL dynamically. - D5: Boundary Rules (Area: Boundary Rules) β Feature logic and command/query packages must not import their own
transport/orstore/folders, nor can they import transport/store directories of other features. - D6: Dependency Graph (Area: Dependency Graph) β The import tree must remain strictly acyclic (e.g.,
userandsessionhave no dependencies on higher-level features,notificationis a pure subscriber with zero external feature imports).
.
βββ cmd/
β βββ server/
β β βββ main.go # Application entry point & configuration bootstrap
β βββ gates/
β β βββ main.go # CLI runner for verification gates
β βββ client/
β βββ main.go # CLI client for testing/ops
βββ db/
β βββ migrations/ # Sequential up/down SQL database migrations
βββ internal/
β # βββ Vertical Feature Slices βββ
β βββ user/ # Profiles, registration, privacy toggles
β βββ follow/ # Follow relationships & pending requests
β βββ topic/ # Posts, feed visibility, voting rules
β βββ comment/ # Image-supported comments
β βββ group/ # Communities, group posts, group chat
β βββ event/ # Group events & RSVP tracking
β βββ chat/ # Direct messages, presence, and chat history
β βββ notification/ # Event bus subscriber notifications
β βββ oauth/ # Github/Google authentication pipelines
β #
β # βββ Cross-Cutting Core βββ
β βββ core/
β β βββ middleware/ # Auth, CORS, logging, rate limiter
β β βββ realtime/ # WebSocket hub and connection routing
β β βββ server/ # HTTP engine & graceful shutdown
β β βββ session/ # Session lifecycle and token stores
β #
β # βββ Platform Abstractions βββ
β βββ platform/
β β βββ cache/ # Memory cache & Redis wrappers
β β βββ database/ # DB factory and migrations runner
β β βββ eventbus/ # Event publishing channels
β #
β # βββ Quality Gates βββ
β βββ gates/ # Deterministic verification gates (boundaries, DAG, security, coverage, TDD, etc.)
β #
β # βββ Bootstrap & Helpers βββ
β βββ bootstrap/ # Composition root & service wiring
β βββ config/ # Configuration loader
β βββ pkg/ # Shared helpers (bcrypt, uuid, validator, helpers, oauth, imgutil) β migrates to repo-root pkg/ in S5-BE-99
β
βββ frontend/ # Next.js Application Root (TypeScript + Bun)
- Backend: Go 1.25
- Frontend: TypeScript (Next.js App Router, Bun Runtime)
- Database: SQLite3 (Production: WAL mode enabled; Dev/Testing: In-Memory / Local DB)
- Containers: Docker & Docker Compose v5.1.1
- Backend Tools:
- Testing:
go test -race -coverprofileviaMakefile(make test) - Linting:
golangci-lint(v2.2.1) configured in.golangci.yml - Static Analysis:
staticcheckviaMakefile(make lint) - Formatting:
gofmt -s,gofumptviaMakefile(make format) - Vulnerability Checks:
govulncheckrun locally
- Testing:
- Frontend Tools:
- Package Manager / Runtime:
Bunconfigured inpackage.json - Formatting & Linting:
ESLint+Prettierconfigured ineslint.config.mjs+.prettierrc - Testing:
Vitest(planned) configured invitest.config.ts - E2E Testing:
Playwright(planned) configured inplaywright.config.ts
- Package Manager / Runtime:
We enforce strict validation pipelines to ensure codebase stability.
Run the automated check suite locally before pushing:
make gatesThis runs the decoupled PR quality gate suite:
go build ./...: Compiles all Go packages (legacy + new) for basic build safety.go run cmd/gates/main.go --all: Runs the custom Go verification gates.
Note: You can still run the legacy full-system check via make ci (runs blanket make be-ci + make fe-ci), which is informational and does not block PR gates.
To auto-format files in new directories:
PATH=<GOBIN>:$PATH gofumpt -w <dirs> && PATH=<GOBIN>:$PATH goimports -w -local social-network <dirs>
Deterministic Go-based gates catch architecture violations, security issues, and branch/convention regressions:
go run cmd/gates/main.go --allIndividual gates:
go run cmd/gates/main.go --gate=stack # Go version + module path
go run cmd/gates/main.go --gate=d1-layout # Directory structure (D1 layout)
go run cmd/gates/main.go --gate=d5-boundaries # D5 import boundary rules
go run cmd/gates/main.go --gate=d6-dag # D6 dependency graph acyclicity (supports go-arch-lint)
go run cmd/gates/main.go --gate=tdd # Test file presence
go run cmd/gates/main.go --gate=migrations # Migration naming/delimiter
go run cmd/gates/main.go --gate=security # gosec + govulncheck + custom AST checks (scoped to new code)
go run cmd/gates/main.go --gate=branch # branch naming convention (includes 'dev' scope)
go run cmd/gates/main.go --gate=coverage-delta # test coverage threshold
go run cmd/gates/main.go --gate=scope-drift # scope creep detection
go run cmd/gates/main.go --gate=format # code formatting (gofumpt / gofmt)
go run cmd/gates/main.go --gate=lint # code linting (golangci-lint / staticcheck / go vet)
go run cmd/gates/main.go --gate=go-test # Go unit tests
go run cmd/gates/main.go --gate=frontend # frontend CI checks (lint, format, tsc, test)Default output is human-readable text; use --json for JSON format. Exit code is 0 on success, 1 on failure. Gates are also run via make gates.
Quality hooks run automatically on staged files (pre-commit) and before push (pre-push):
# Install hooks (one-time setup)
make setup-hooks
# Pre-commit (runs on staged files):
# - Backend: gofumpt + goimports formatting (auto-fixed)
# - Frontend: Prettier + ESLint
# Pre-push:
# - Backend: go vet ./..., go test -short ./..., go build ./..., go-arch-lint check
# - Frontend: tsc --noEmit, eslint, vitestTo bypass hooks temporarily: git commit --no-verify or git push --no-verify.
Run linting, formatting check, and TypeScript compilation gates:
cd frontend
bun run lint # ESLint linting
bun run format:check # Prettier formatting check
bun run typecheck # tsc --noEmit check
bun run test # Vitest unit & component testsThis project uses progressive disclosure to avoid cognitive overload. Read in this order:
- Rules & Guidelines: AGENTS.md + conventions.md
- Methodology: general-instructions.md
- Architecture: architecture.md
- Design Specs: sds.md
- Roadmap: target-architecture-with-phases.md
- Sprints: sprint-0.md through sprint-6.md
See conventions.md for the full dependency graph.
This repository includes specialized configurations and tools designed to optimize the workflow of agentic AI coding assistants (like Antigravity and Opencode). Developers using agentic assistants can leverage these files for enhanced context management, token savings, and codebase navigation:
- β‘ Terminal Token Compression:
- RTK (Rust Token Killer): Minimizes input/output token consumption by 60β90%. Always prefix terminal commands with
rtk(e.g.rtk git status,rtk make test,rtk go test ./...).
- RTK (Rust Token Killer): Minimizes input/output token consumption by 60β90%. Always prefix terminal commands with
- π¬ Communication Optimization:
- Caveman Mode (.agents/skills/caveman/SKILL.md): Ultra-compressed communication skill that cuts conversation token usage by ~75% while maintaining technical accuracy.
- π Codebase Knowledge Graph:
- Graphify Rule (.agents/rules/graphify.md) / Graphify Skill (.agents/skills/graphify/SKILL.md): Builds and queries an AST-based knowledge graph. Run
graphify query "<question>"to BFS traverse orgraphify path "<A>" "<B>"to trace dependencies.
- Graphify Rule (.agents/rules/graphify.md) / Graphify Skill (.agents/skills/graphify/SKILL.md): Builds and queries an AST-based knowledge graph. Run
- π€ Core Instructions & Conventions:
- AGENTS.md: Main code guidelines, including simplicity-first principles and progressive document reading orders.
- Conventions (.agents/rules/conventions.md): Code boundaries and architectural rules.
- Karpathy Guidelines (.agents/rules/karpathy-guidelines.md): Red-Green-Refactor, TDD, and codebase change minimization guides.
Agent Skills for coding assistants (caveman, graphify, diagnose, review, tdd, etc.) are pre-installed under .agents/skills/ and registered in skills-lock.json. Skills auto-activate when the agent detects a matching task. No manual install needed for existing skills.
To install new skills from a remote source (e.g. mattpocock/skills):
# Opencode
opencode skill install <source>/<skill-name>
# Or sync all locked skills from skills-lock.json
opencode skill syncTo update all skills to their latest version:
opencode skill upgradeDevelopment Dependencies β one command to install everything:
| Layer | Command | What it installs |
|---|---|---|
| All (unified) | make install |
Go modules + root JS + .env + SSL certs + Go tools + git hooks + frontend deps |
| Backend (Go) | make setup (or make tools) |
goimports, staticcheck, golangci-lint (v2.2.1), govulncheck, gofumpt, gosec, go-arch-lint, lefthook |
| Backend (Go modules) | go mod download (via make install) |
Go library dependencies from go.sum |
| Frontend (Bun/Next.js) | bun install (via make install) |
npm packages from frontend/package.json |
| Docker | docker compose build |
Container images for backend + frontend |
To update Go dependencies:
go get -u ./... # update all deps
go mod tidy # clean upTo update frontend dependencies:
cd frontend
bun update # update all packages per semver rangesAll branches must match the naming schema: <username>/<ticket/issue-ID>-<detail>
-
Username: Your own Gitea username β resolve via
tea whoamiorcat ~/.config/tea/config.yml | grep 'user:' | head -1 | awk '{print $2}'. Known devs:epapamic,ekaramet,dkotsi,geoikonomou,smichail -
ticket/issue-ID: Ticket ID from
docs/sprints/ticket-tracker.md(e.g.S3-BE-01) or GitHub/Gitea issue number (e.g.42). Required β maps branch to work item. -
Detail: kebab-case description (e.g.
db-factory,fix-sqlite-busy-timeout). -
Examples:
ekaramet/S1-BE-05-db-factory,geoikonomou/42-fix-sqlite-busy-timeout - Branches must live
$\le$ 3 days (Trunk-Based Development).
Squash-merged commits onto the main branch must follow the Conventional Commits standard:
<type>(<scope>)[<ID>]: <description>
[Optional Body explaining the why behind changes]
- Examples:
feat(follow)[S3-BE-37]: add follow requests workflowfix(core)[42]: recover from websocket write panicrefactor(topic)[S2-BE-26]: migrate topic store to vertical slice
A task is marked completed when:
- TDD cycle is fully executed (write failing test -> make it pass -> refactor).
- Boundary checks (D5) verify no cross-slice http/store imports.
- Code compiles and linting/formatting passes cleanly (
make ci). - PR follows the standard PR description template (found in
.github/PULL_REQUEST_TEMPLATE.md). - Successfully verified through targeted manual smoke tests (e.g. age locks, privacy gates, follow actions).
Legacy layered code is migrated to vertical slices using the Strangler Fig pattern. See conventions.md for full steps:
- Write contract tests against old API
- Build new slice alongside old code
- Verify contract tests match
- Swap routing in bootstrap
- Delete old code after confidence window
- ertval.github.io β Portfolio & CV
- two-tier-safe-ai-gate β Safe AI execution model (Go + Inngest + Omnigent)
- keel-multi-agent-pipeline β Multi-agent maritime intelligence (Python + LangGraph)
- social-network β Go vertical-slices full-stack monolith (Next.js)
- make-your-game β Pure JS ECS game engine
- real-time-forum β Go + Vanilla JS real-time WebSocket SPA
- forum β Go hexagonal architecture monolith (zero-dependency)