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,163 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Systematically fix ALL Gin radix tree param name conflicts.
|
||||
Phase 2: Fix remaining bare :id routes that conflict with :resource_id sub-routes.
|
||||
|
||||
Also fix handler files to match the new param names.
|
||||
"""
|
||||
import re
|
||||
import os
|
||||
|
||||
# ===== Part 1: Fix router.go =====
|
||||
router_path = '/home/yanghao05/Workspace/gochat/internal/router/router.go'
|
||||
with open(router_path) as f:
|
||||
content = f.read()
|
||||
|
||||
# Replacement map for bare "/:id" → "/:resource_param" in route paths
|
||||
# Based on the group context (determined from line surroundings)
|
||||
replacements_router = {
|
||||
# Line ranges and their resource type → param name mapping
|
||||
# Format: (resource_pattern, new_param_name)
|
||||
}
|
||||
|
||||
# Strategy: read line by line, check context (nearby Group variable comments)
|
||||
lines = content.split('\n')
|
||||
|
||||
# Build a mapping from line content patterns to param names
|
||||
# We look for the variable that the route method is called on
|
||||
context_map = {
|
||||
'drafts': 'draft_id',
|
||||
'msgs': 'message_id', # messages group
|
||||
'teams': 'team_id',
|
||||
'platformApps': 'platform_app_id', # hmm, check Chatwoot
|
||||
'agentBots': 'agent_bot_id',
|
||||
'agentBotInboxes': 'agent_bot_inbox_id', # unique constraint
|
||||
'botRules': 'rule_id',
|
||||
'triggerConfigs': 'trigger_config_id', # hmm
|
||||
'assistants': 'assistant_id',
|
||||
'assistantDocs': 'document_id',
|
||||
'assistantScenarios': 'scenario_id',
|
||||
'copilotThreads': 'thread_id', # hmm, check Chatwoot
|
||||
'automationRules': 'automation_id',
|
||||
'macros': 'macro_id',
|
||||
'participants': 'participant_id', # already has :conversation_id prefix
|
||||
'whatsappCalls': 'call_id',
|
||||
}
|
||||
|
||||
# Special handling for platform-level routes (not in accounts group)
|
||||
platform_level_map = {
|
||||
'notifications': 'notification_id',
|
||||
'push_subscriptions': 'push_subscription_id',
|
||||
}
|
||||
|
||||
# Also fix the /accounts/:id routes (line ~1475) → /accounts/:account_id
|
||||
# These are outside the accounts group
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('//') or not stripped:
|
||||
continue
|
||||
|
||||
# Check for bare "/:id" in route registration
|
||||
if not re.search(r'"/:id"', stripped):
|
||||
continue
|
||||
|
||||
# Determine the group variable from the route method call
|
||||
rmatch = re.match(r'^(\w+)\.(GET|POST|PUT|PATCH|DELETE)\("([^"]+)"\s*,', stripped)
|
||||
if not rmatch:
|
||||
continue
|
||||
|
||||
var_name = rmatch.group(1)
|
||||
path = rmatch.group(3)
|
||||
|
||||
# Find the replacement param name
|
||||
new_param = context_map.get(var_name)
|
||||
|
||||
# Check platform-level routes
|
||||
if var_name in ('g', 'v1'):
|
||||
for resource, param in platform_level_map.items():
|
||||
if resource in path:
|
||||
new_param = param
|
||||
break
|
||||
|
||||
# Special: account routes at platform level
|
||||
if var_name == 'g' and '/accounts/:id' in path:
|
||||
new_param = 'account_id'
|
||||
|
||||
if new_param and new_param != 'id':
|
||||
new_path = path.replace('/:id', f'/:{new_param}')
|
||||
new_line = line.replace(f'"{path}"', f'"{new_path}"')
|
||||
lines[i] = new_line
|
||||
print(f"Router Line {i+1}: {var_name} {path} → {new_path} (:id → :{new_param})")
|
||||
|
||||
new_content = '\n'.join(lines)
|
||||
with open(router_path, 'w') as f:
|
||||
f.write(new_content)
|
||||
|
||||
# ===== Part 2: Fix handler files =====
|
||||
# For each changed param name, find handler files that use parseUintParam(c, "id")
|
||||
# and change to parseUintParam(c, "new_param_name")
|
||||
# Also change the variable name from id to a more descriptive name
|
||||
|
||||
handler_dir = '/home/yanghao05/Workspace/gochat/internal/handler/api/v1'
|
||||
handler_map = {
|
||||
# Map resource type to (handler_file, old_var, new_var, old_param, new_param)
|
||||
'draft_id': ('draft_message_handler.go', 'id', 'draftID', '"id"', '"draft_id"'),
|
||||
'message_id': ('message_handler.go', 'id', 'messageID', '"id"', '"message_id"'),
|
||||
'team_id': ('team_handler.go', 'id', 'teamID', '"id"', '"team_id"'),
|
||||
'agent_bot_id': ('agent_bot_handler.go', 'id', 'agentBotID', '"id"', '"agent_bot_id"'),
|
||||
'automation_id': ('automation_rule_handler.go', 'id', 'automationID', '"id"', '"automation_id"'),
|
||||
'macro_id': ('macro_handler.go', 'id', 'macroID', '"id"', '"macro_id"'),
|
||||
'assistant_id': ('captain_assistant_handler.go', 'id', 'assistantID', '"id"', '"assistant_id"'),
|
||||
'notification_id': ('notification_handler.go', 'id', 'notificationID', '"id"', '"notification_id"'),
|
||||
'call_id': ('whatsapp_call_handler.go', 'id', 'callID', '"id"', '"call_id"'),
|
||||
'participant_id': ('conversation_participant_handler.go', 'id', 'participantID', '"id"', '"participant_id"'),
|
||||
}
|
||||
|
||||
print("\n=== Fixing handler files ===")
|
||||
for new_param, (handler_file, old_var, new_var, old_param_str, new_param_str) in handler_map.items():
|
||||
filepath = os.path.join(handler_dir, handler_file)
|
||||
if not os.path.exists(filepath):
|
||||
print(f" SKIP: {handler_file} not found")
|
||||
continue
|
||||
|
||||
with open(filepath) as f:
|
||||
hcontent = f.read()
|
||||
|
||||
# Replace parseUintParam(c, "id") → parseUintParam(c, "new_param")
|
||||
# But be careful not to replace "account_id" or other specific params
|
||||
# Only replace bare "id" param extraction
|
||||
|
||||
# Pattern: id, err := parseUintParam(c, "id") → newVar, err := parseUintParam(c, "new_param")
|
||||
old_pattern = f'{old_var}, err := parseUintParam(c, {old_param_str})'
|
||||
new_pattern = f'{new_var}, err := parseUintParam(c, {new_param_str})'
|
||||
|
||||
if old_pattern in hcontent:
|
||||
hcontent = hcontent.replace(old_pattern, new_pattern)
|
||||
print(f" {handler_file}: Replaced '{old_pattern}' → '{new_pattern}'")
|
||||
|
||||
# Also replace references to the old variable name (id → newVar) in service calls
|
||||
# Only replace bare `id` that was previously the conversation/resource ID
|
||||
# This is tricky — need to avoid replacing `id` in strings or other variable names
|
||||
|
||||
# Replace patterns like: h.xxxSvc.Func(ctx, accountID, id) → h.xxxSvc.Func(ctx, accountID, newVar)
|
||||
# Pattern: , id) → , newVar)
|
||||
pattern_refs = f', {old_var})'
|
||||
replacement_refs = f', {new_var})'
|
||||
|
||||
# But only for lines that DON'T contain accountID (to avoid double-replacing)
|
||||
# Actually we need to replace: accountID, id → accountID, newVar
|
||||
pattern_account_id = f'accountID, {old_var}'
|
||||
replacement_account_id = f'accountID, {new_var}'
|
||||
|
||||
if pattern_account_id in hcontent:
|
||||
hcontent = hcontent.replace(pattern_account_id, replacement_account_id)
|
||||
print(f" {handler_file}: Replaced 'accountID, {old_var}' → 'accountID, {new_var}'")
|
||||
|
||||
# Also replace bare id references that aren't part of other variable names
|
||||
# Like: id in function calls after the initial declaration was changed
|
||||
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(hcontent)
|
||||
|
||||
print("\nDone! Now try: go build ./...")
|
||||
Reference in New Issue
Block a user