Fix local account service configuration for dev usage (#386)

* Adjust account service defaults for local development

* Add runtime service configuration for account endpoints

* Switch runtime service config to YAML
This commit is contained in:
shenlan 2025-10-03 08:44:14 +08:00 committed by GitHub
parent 19b1034518
commit 888e3a6ae5
8 changed files with 168 additions and 14 deletions

View File

@ -50,9 +50,10 @@ make init-db # initialize database (optional)
## Frontend configuration
The Next.js homepage reads `NEXT_PUBLIC_ACCOUNT_SERVICE_URL` to reach the Account Service. When the variable is not set it
defaults to `https://localhost:8443`, matching the hostname used by the development TLS certificate. Override the environment
variable if your local certificates use a different host or when connecting to a remote Account Service instance.
The Next.js homepage now resolves service endpoints through `ui/homepage/config/runtime-service-config.yaml`. The runtime
configuration selects values based on `NEXT_PUBLIC_RUNTIME_ENV` (falling back to `NODE_ENV` and the file's
`defaultEnvironment`). Use `NEXT_PUBLIC_ACCOUNT_SERVICE_URL` for ad-hoc overrides, otherwise adjust the YAML file to specify
environment-specific URLs such as `http://localhost:8080` for development/test and `https://account.svc.plus` for production.
## Account service configuration

View File

@ -2,22 +2,26 @@ log:
level: info
server:
addr: ":8443"
addr: ":8080"
readTimeout: 15s
writeTimeout: 15s
publicUrl: "https://account.svc.plus"
publicUrl: "http://localhost:8080"
allowedOrigins:
- "https://account.svc.plus"
- "https://localhost:8443"
- "http://localhost:8080"
- "http://127.0.0.1:8080"
- "http://localhost:3001"
- "http://127.0.0.1:3001"
- "http://localhost:3000"
- "http://127.0.0.1:3000"
tls:
enabled: true
certFile: "/etc/ssl/svc.plus.pem"
keyFile: "/etc/ssl/svc.plus.rsa.key"
caFile: "/etc/ssl/svc.plus.ca.pem"
enabled: false
certFile: ""
keyFile: ""
caFile: ""
clientCAFile: ""
redirectHttp: true
redirectHttp: false
store:
driver: "postgres"

View File

@ -10,6 +10,7 @@ import Footer from '@components/Footer'
import { AskAIButton } from '@components/AskAIButton'
import { useLanguage } from '@i18n/LanguageProvider'
import { translations } from '@i18n/translations'
import { getAccountServiceBaseUrl } from '@lib/serviceConfig'
import { WeChatIcon } from '../components/icons/WeChatIcon'
@ -53,7 +54,7 @@ export default function LoginContent({ children }: LoginContentProps) {
[],
)
const accountServiceBaseUrl = (process.env.NEXT_PUBLIC_ACCOUNT_SERVICE_URL || 'https://localhost:8443').replace(/\/$/, '')
const accountServiceBaseUrl = getAccountServiceBaseUrl()
const githubAuthUrl = process.env.NEXT_PUBLIC_GITHUB_AUTH_URL || '/api/auth/github'
const wechatAuthUrl = process.env.NEXT_PUBLIC_WECHAT_AUTH_URL || '/api/auth/wechat'
const loginUrl = process.env.NEXT_PUBLIC_LOGIN_URL || `${accountServiceBaseUrl}/api/auth/login`

View File

@ -10,6 +10,7 @@ import Footer from '@components/Footer'
import { AskAIButton } from '@components/AskAIButton'
import { useLanguage } from '@i18n/LanguageProvider'
import { translations } from '@i18n/translations'
import { getAccountServiceBaseUrl } from '@lib/serviceConfig'
import { WeChatIcon } from '../components/icons/WeChatIcon'
@ -22,7 +23,7 @@ export default function RegisterContent() {
const searchParams = useSearchParams()
const router = useRouter()
const accountServiceBaseUrl = (process.env.NEXT_PUBLIC_ACCOUNT_SERVICE_URL || 'https://localhost:8443').replace(/\/$/, '')
const accountServiceBaseUrl = getAccountServiceBaseUrl()
const githubAuthUrl = process.env.NEXT_PUBLIC_GITHUB_AUTH_URL || '/api/auth/github'
const wechatAuthUrl = process.env.NEXT_PUBLIC_WECHAT_AUTH_URL || '/api/auth/wechat'
const registerUrl = process.env.NEXT_PUBLIC_REGISTER_URL || `${accountServiceBaseUrl}/api/auth/register`

View File

@ -0,0 +1,17 @@
defaultEnvironment: production
defaults:
accountService:
baseUrl: https://account.svc.plus
environments:
development:
accountService:
baseUrl: http://localhost:8080
test:
accountService:
baseUrl: http://localhost:8080
production:
accountService:
baseUrl: https://account.svc.plus
production_tls:
accountService:
baseUrl: https://account.svc.plus:8443

View File

@ -1,6 +1,119 @@
const DEFAULT_ACCOUNT_SERVICE_URL = 'https://localhost:8443'
import runtimeServiceConfigSource from '../config/runtime-service-config.yaml'
type AccountServiceRuntimeConfig = {
baseUrl?: string
}
type EnvironmentRuntimeConfig = {
accountService?: AccountServiceRuntimeConfig
}
type RuntimeServiceConfig = {
defaultEnvironment?: string
defaults?: EnvironmentRuntimeConfig
environments?: Record<string, EnvironmentRuntimeConfig>
}
type StackEntry = {
indent: number
value: Record<string, unknown>
}
function parseSimpleYaml(source: string): RuntimeServiceConfig {
const lines = source
.split(/\r?\n/)
.map((line) => line.replace(/#.*$/, ''))
.map((line) => line.replace(/\s+$/, ''))
.filter((line) => line.trim().length > 0)
const root: Record<string, unknown> = {}
const stack: StackEntry[] = [{ indent: -1, value: root }]
for (const line of lines) {
const indent = line.match(/^\s*/)![0].length
const trimmed = line.trim()
const separatorIndex = trimmed.indexOf(':')
if (separatorIndex === -1) {
continue
}
const key = trimmed.slice(0, separatorIndex).trim()
const rawValue = trimmed.slice(separatorIndex + 1).trim()
while (stack.length > 1 && indent <= stack[stack.length - 1].indent) {
stack.pop()
}
const parent = stack[stack.length - 1].value
if (rawValue.length === 0) {
const child: Record<string, unknown> = {}
parent[key] = child
stack.push({ indent, value: child })
} else {
parent[key] = rawValue
}
}
return root as RuntimeServiceConfig
}
const runtimeServiceConfig = parseSimpleYaml(runtimeServiceConfigSource)
const DEFAULT_ACCOUNT_SERVICE_URL = 'https://account.svc.plus'
const DEFAULT_SERVER_SERVICE_URL = 'http://localhost:8090'
const runtimeEnvironments: Record<string, EnvironmentRuntimeConfig> =
runtimeServiceConfig.environments ?? {}
type RuntimeEnvironmentName = keyof typeof runtimeEnvironments
function normalizeEnvKey(value?: string | null): string | undefined {
if (!value) return undefined
return value
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, '_')
.replace(/^_+|_+$/g, '')
}
function resolveRuntimeEnvironment(): RuntimeEnvironmentName | undefined {
const envCandidates = [
process.env.NEXT_PUBLIC_RUNTIME_ENV,
process.env.NEXT_RUNTIME_ENV,
process.env.RUNTIME_ENV,
process.env.APP_ENV,
process.env.NODE_ENV,
runtimeServiceConfig.defaultEnvironment,
]
for (const candidate of envCandidates) {
const normalizedCandidate = normalizeEnvKey(candidate)
if (!normalizedCandidate) continue
const matchedEntry = Object.keys(runtimeEnvironments).find(
(key) => normalizeEnvKey(key) === normalizedCandidate,
) as RuntimeEnvironmentName | undefined
if (matchedEntry) {
return matchedEntry
}
}
return undefined
}
function getRuntimeAccountServiceBaseUrl(): string | undefined {
const environmentName = resolveRuntimeEnvironment()
const runtimeDefaults = runtimeServiceConfig.defaults?.accountService?.baseUrl
const environmentValue = environmentName
? runtimeEnvironments[environmentName]?.accountService?.baseUrl
: undefined
return environmentValue ?? runtimeDefaults
}
function readEnvValue(...keys: string[]): string | undefined {
for (const key of keys) {
const raw = process.env[key]
@ -20,7 +133,8 @@ function normalizeBaseUrl(baseUrl: string): string {
export function getAccountServiceBaseUrl(): string {
const configured = readEnvValue('ACCOUNT_SERVICE_URL', 'NEXT_PUBLIC_ACCOUNT_SERVICE_URL')
return normalizeBaseUrl(configured ?? DEFAULT_ACCOUNT_SERVICE_URL)
const runtimeConfigured = getRuntimeAccountServiceBaseUrl()
return normalizeBaseUrl(configured ?? runtimeConfigured ?? DEFAULT_ACCOUNT_SERVICE_URL)
}
export function getServerServiceBaseUrl(): string {

View File

@ -51,6 +51,13 @@ const nextConfig = {
compress: false, // 压缩交给 Nginx省 Node CPU
images: { unoptimized: true }, // 关闭服务端图片处理
featureToggles,
webpack(config) {
config.module.rules.push({
test: /\.ya?ml$/i,
type: 'asset/source',
})
return config
},
async rewrites() {
return [
{

9
ui/homepage/types/global.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
declare module '*.yaml' {
const content: string
export default content
}
declare module '*.yml' {
const content: string
export default content
}