Reorganize repo: backend/, deploy/, docs/ layout + AGENTS.md
Restructure the monorepo into clear top-level directories: - backend/: Go module root (cmd, internal, pkg, configs, migrations, docs/swagger, scripts, tests, go.mod, Makefile, .air.toml) - deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd - docs/: project documentation + reports/ (moved from repo root) - AGENTS.md: new AI coding-agent guide at repo root Update all references to the new layout: - Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root) - docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile, env_file ../../.env, volume mounts ../../backend:/app - deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile - CI: working-directory: backend for go commands, file deploy/docker/Dockerfile, coverage path backend/coverage.out, health_check backend/scripts/ - backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../ - README: architecture tree, quickstart, config paths updated Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh, gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to preserve history. Build, vet, SQLite tests, and docker compose config verified.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# GoChat Development Environment Overrides
|
||||
# Reference: Chatwoot config/environments/development.rb
|
||||
|
||||
server:
|
||||
mode: "debug"
|
||||
|
||||
database:
|
||||
name: "gochat_dev"
|
||||
log_level: "info"
|
||||
|
||||
log:
|
||||
level: "debug"
|
||||
format: "console"
|
||||
|
||||
worker:
|
||||
concurrency: 5
|
||||
|
||||
redis:
|
||||
channel_prefix: "gochat_dev"
|
||||
@@ -0,0 +1,29 @@
|
||||
# GoChat Production Environment Overrides
|
||||
# Reference: Chatwoot config/environments/production.rb
|
||||
|
||||
server:
|
||||
mode: "release"
|
||||
cors:
|
||||
# PRODUCTION: Must specify exact origins or wildcard patterns.
|
||||
# NEVER leave empty in production — empty + non-debug = no CORS allowed.
|
||||
allowed_origins:
|
||||
- "https://app.yourdomain.com"
|
||||
- "https://admin.yourdomain.com"
|
||||
- "*.yourdomain.com" # matches any subdomain
|
||||
allow_credentials: true # needed for JWT cookie-based auth
|
||||
max_age: 86400
|
||||
|
||||
database:
|
||||
name: "gochat_production"
|
||||
pool_max: 20
|
||||
log_level: "warn"
|
||||
|
||||
log:
|
||||
level: "info"
|
||||
format: "json"
|
||||
|
||||
worker:
|
||||
concurrency: 10
|
||||
|
||||
redis:
|
||||
channel_prefix: "gochat_production"
|
||||
@@ -0,0 +1,72 @@
|
||||
server:
|
||||
host: "0.0.0.0"
|
||||
port: 3000
|
||||
mode: "debug" # debug, release, test
|
||||
cors:
|
||||
allowed_origins: [] # empty = Allow-Origin:* in debug mode; production must list exact origins
|
||||
# Examples:
|
||||
# - "https://app.example.com"
|
||||
# - "*.example.com"
|
||||
allowed_methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
allowed_headers: ["Origin", "Content-Type", "Accept", "Authorization", "X-Account-ID", "access-token", "client", "uid", "token-type", "expiry"]
|
||||
expose_headers: ["Content-Length", "access-token", "client", "uid", "token-type", "expiry"]
|
||||
allow_credentials: false # set to true only if you need cookies/auth headers
|
||||
max_age: 86400 # preflight cache duration in seconds
|
||||
|
||||
database:
|
||||
host: "localhost"
|
||||
port: 5432
|
||||
user: "gochat"
|
||||
password: "gochat_dev"
|
||||
dbname: "gochat_dev"
|
||||
sslmode: "disable"
|
||||
max_idle_conns: 10
|
||||
max_open_conns: 100
|
||||
conn_max_lifetime: 3600 # seconds
|
||||
run_migrations: false # set to true to auto-run migrations on startup
|
||||
migrations_path: "migrations"
|
||||
|
||||
redis:
|
||||
host: "localhost"
|
||||
port: 6379
|
||||
password: ""
|
||||
db: 0
|
||||
pool_size: 50
|
||||
|
||||
jwt:
|
||||
secret: "gochat_dev_secret_change_in_production"
|
||||
expiry_hours: 72
|
||||
|
||||
log:
|
||||
level: "debug" # debug, info, warn, error
|
||||
format: "json" # json, text
|
||||
|
||||
rate_limit:
|
||||
enabled: true
|
||||
requests_per_minute: 100 # max requests per client IP per window
|
||||
window_seconds: 60 # sliding window duration in seconds
|
||||
|
||||
search:
|
||||
# Chatwoot parity target. Use "db" only for explicit local fallback.
|
||||
engine: "meilisearch"
|
||||
host: "http://localhost:7700"
|
||||
api_key: ""
|
||||
index_prefix: "gochat_"
|
||||
timeout_seconds: 5
|
||||
|
||||
saml:
|
||||
enabled: false # SAML 2.0 SSO — enable for enterprise IdP integration
|
||||
# IdP metadata: provide URL or inline XML (URL preferred for auto-refresh)
|
||||
idp_metadata_url: "" # e.g. "https://idp.example.com/metadata"
|
||||
idp_metadata_xml: "" # fallback: paste IdP metadata XML here
|
||||
sp_entity_id: "https://gochat.example.com/saml" # our SP entity ID
|
||||
acs_url: "https://gochat.example.com/api/v1/saml/acs" # Assertion Consumer Service URL
|
||||
# SP key/certificate: PEM format (required for signed AuthnRequest + response validation)
|
||||
sp_private_key: "" # path or inline PEM — generate with: openssl genrsa -out sp.key 2048
|
||||
sp_certificate: "" # path or inline PEM — generate with: openssl req -new -x509 -key sp.key -out sp.crt
|
||||
clock_drift_tolerance: 180 # seconds of allowed clock drift for NotOnOrAfter validation
|
||||
attribute_map:
|
||||
email: "email" # SAML attribute → GoChat email field
|
||||
display_name: "displayName" # SAML attribute → GoChat name field
|
||||
first_name: "firstName" # SAML attribute → first name component
|
||||
last_name: "lastName" # SAML attribute → last name component
|
||||
@@ -0,0 +1,65 @@
|
||||
# GoChat Fluentd Configuration
|
||||
# Reference: Chatwoot production uses structured JSON logging
|
||||
# This config collects logs from gochat containers and forwards to outputs
|
||||
|
||||
<source>
|
||||
@type tail
|
||||
path /var/log/gochat/*.log
|
||||
pos_file /var/log/fluentd/gochat.log.pos
|
||||
tag gochat.app
|
||||
<parse>
|
||||
@type json
|
||||
time_key timestamp
|
||||
time_format %Y-%m-%dT%H:%M:%S.%NZ
|
||||
keep_time_key true
|
||||
</parse>
|
||||
</source>
|
||||
|
||||
<source>
|
||||
@type tail
|
||||
path /var/log/gochat/worker.log
|
||||
pos_file /var/log/fluentd/gochat-worker.log.pos
|
||||
tag gochat.worker
|
||||
<parse>
|
||||
@type json
|
||||
time_key timestamp
|
||||
time_format %Y-%m-%dT%H:%M:%S.%NZ
|
||||
keep_time_key true
|
||||
</parse>
|
||||
</source>
|
||||
|
||||
# Docker container logs via systemd/journald
|
||||
<source>
|
||||
@type systemd
|
||||
filters [{ "_COMM": "docker" }]
|
||||
tag docker
|
||||
</source>
|
||||
|
||||
# ---- Outputs ----
|
||||
|
||||
# Console output for development
|
||||
<match gochat.**>
|
||||
@type stdout
|
||||
</match>
|
||||
|
||||
# Production: send to Elasticsearch or Loki
|
||||
# Uncomment based on your backend:
|
||||
#
|
||||
# <match gochat.**>
|
||||
# @type elasticsearch
|
||||
# host elasticsearch
|
||||
# port 9200
|
||||
# logstash_format true
|
||||
# logstash_prefix gochat
|
||||
# <buffer>
|
||||
# @type file
|
||||
# path /var/log/fluentd/buffers/gochat
|
||||
# flush_interval 5s
|
||||
# </buffer>
|
||||
# </match>
|
||||
#
|
||||
# <match gochat.**>
|
||||
# @type loki
|
||||
# url http://loki:3100
|
||||
# labels { "app": "gochat", "environment": "production" }
|
||||
# </match>
|
||||
@@ -0,0 +1,84 @@
|
||||
# GoChat Prometheus Alert Rules
|
||||
# Reference: Chatwoot production monitoring with Sidekiq queue alerts
|
||||
# Adjust thresholds based on your deployment scale
|
||||
|
||||
groups:
|
||||
- name: gochat-app
|
||||
rules:
|
||||
# Application down
|
||||
- alert: GoChatAppDown
|
||||
expr: up{job="gochat"} == 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "GoChat application is down"
|
||||
description: "GoChat instance {{ $labels.instance }} has been down for more than 1 minute."
|
||||
|
||||
# High error rate
|
||||
- alert: GoChatHighErrorRate
|
||||
expr: rate(http_requests_total{job="gochat", status=~"5.."}[5m]) / rate(http_requests_total{job="gochat"}[5m]) > 0.05
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "GoChat error rate above 5%"
|
||||
description: "Error rate is {{ $value | humanizePercentage }} over the last 5 minutes."
|
||||
|
||||
# High memory usage
|
||||
- alert: GoChatHighMemory
|
||||
expr: gochat_go_memory_alloc_bytes / (1024 * 1024) > 400
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "GoChat memory usage above 400MB"
|
||||
description: "Memory allocation is {{ $value }}MB."
|
||||
|
||||
# Too many goroutines
|
||||
- alert: GoChatHighGoroutines
|
||||
expr: gochat_go_goroutines > 1000
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "GoChat goroutine count above 1000"
|
||||
description: "{{ $value }} goroutines running."
|
||||
|
||||
- name: gochat-infra
|
||||
rules:
|
||||
# PostgreSQL down
|
||||
- alert: GoChatPostgresDown
|
||||
expr: up{job="gochat-postgres"} == 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "PostgreSQL is down"
|
||||
|
||||
# Redis down
|
||||
- alert: GoChatRedisDown
|
||||
expr: up{job="gochat-redis"} == 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Redis is down"
|
||||
|
||||
# Redis memory approaching limit
|
||||
- alert: GoChatRedisMemoryHigh
|
||||
expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.8
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Redis memory usage above 80%"
|
||||
|
||||
# PostgreSQL connections exhausted
|
||||
- alert: GoChatPostgresConnectionsHigh
|
||||
expr: pg_stat_activity_count / pg_settings_max_connections > 0.8
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "PostgreSQL connection usage above 80%"
|
||||
@@ -0,0 +1,30 @@
|
||||
# GoChat Redis Configuration
|
||||
# Reference: Chatwoot production Redis uses appendonly + maxmemory policies
|
||||
# This file is for standalone Redis deployment; compose uses command-line flags
|
||||
|
||||
# ---- Persistence ----
|
||||
appendonly yes
|
||||
appendfsync everysec
|
||||
auto-aof-rewrite-percentage 100
|
||||
auto-aof-rewrite-min-size 64mb
|
||||
|
||||
# ---- Memory ----
|
||||
maxmemory 512mb
|
||||
maxmemory-policy allkeys-lru
|
||||
|
||||
# ---- Security ----
|
||||
requirepass ${REDIS_PASSWORD}
|
||||
|
||||
# ---- Networking ----
|
||||
bind 0.0.0.0
|
||||
port 6379
|
||||
timeout 300
|
||||
|
||||
# ---- Logging ----
|
||||
loglevel notice
|
||||
logfile ""
|
||||
|
||||
# ---- Performance ----
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
||||
Reference in New Issue
Block a user