refactor(domain-manager): simplify frontend URL configuration (#10194)

Replaced multiple environment variables for frontend URL construction
with a single FRONTEND_URL variable. This change reduces complexity and
improves clarity by consolidating frontend URL handling into one source.
Updated relevant validations and removed unused variables like
FRONT_PROTOCOL and FRONT_PORT.

Fix #10016
This commit is contained in:
Antoine Moreaux
2025-02-14 12:03:07 +01:00
committed by GitHub
parent 01665ca8ae
commit 171091e1ef
9 changed files with 29 additions and 83 deletions

View File

@ -20,7 +20,7 @@ services:
ports:
- "3000:3000"
environment:
PORT: 3000
NODE_PORT: 3000
PG_DATABASE_URL: postgres://${PG_DATABASE_USER:-postgres}:${PG_DATABASE_PASSWORD:-postgres}@${PG_DATABASE_HOST:-db}:${PG_DATABASE_PORT:-5432}/default
SERVER_URL: ${SERVER_URL}
REDIS_URL: ${REDIS_URL:-redis://redis:6379}

View File

@ -33,7 +33,7 @@ spec:
image: twentycrm/twenty:latest
imagePullPolicy: Always
env:
- name: PORT
- name: NODE_PORT
value: 3000
- name: SERVER_URL
value: "https://crm.example.com:443"

View File

@ -38,7 +38,7 @@ resource "kubernetes_deployment" "twentycrm_server" {
tty = true
env {
name = "PORT"
name = "NODE_PORT"
value = "3000"
}

View File

@ -5,9 +5,7 @@ REDIS_URL=redis://localhost:6379
APP_SECRET=replace_me_with_a_random_string
SIGN_IN_PREFILLED=true
FRONT_PROTOCOL=http
FRONT_DOMAIN=localhost
FRONT_PORT=3001
FRONTEND_URL=http://localhost:3001
# ———————— Optional ————————
# PORT=3000

View File

@ -15,8 +15,7 @@ describe('DomainManagerService', () => {
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONTEND_URL: 'https://example.com',
};
return env[key];
@ -39,8 +38,7 @@ describe('DomainManagerService', () => {
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONTEND_URL: 'https://example.com',
};
return env[key];
@ -84,13 +82,12 @@ describe('DomainManagerService', () => {
});
describe('buildBaseUrl', () => {
it('should build the base URL with protocol and domain from environment variables', () => {
it('should build the base URL from environment variables', () => {
jest
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONTEND_URL: 'https://example.com',
};
return env[key];
@ -106,8 +103,8 @@ describe('DomainManagerService', () => {
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONTEND_URL: 'https://example.com',
IS_MULTIWORKSPACE_ENABLED: true,
DEFAULT_SUBDOMAIN: 'test',
};
@ -119,24 +116,6 @@ describe('DomainManagerService', () => {
expect(result.toString()).toBe('https://test.example.com/');
});
it('should append port if FRONT_PORT is set', () => {
jest
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONT_PORT: '8080',
};
return env[key];
});
const result = domainManagerService.getBaseUrl();
expect(result.toString()).toBe('https://example.com:8080/');
});
});
describe('buildWorkspaceURL', () => {
@ -145,8 +124,8 @@ describe('DomainManagerService', () => {
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONTEND_URL: 'https://example.com',
IS_MULTIWORKSPACE_ENABLED: true,
DEFAULT_SUBDOMAIN: 'default',
};
@ -170,8 +149,7 @@ describe('DomainManagerService', () => {
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONTEND_URL: 'https://example.com',
};
return env[key];
@ -194,8 +172,7 @@ describe('DomainManagerService', () => {
.spyOn(environmentService, 'get')
.mockImplementation((key: string) => {
const env = {
FRONT_PROTOCOL: 'https',
FRONT_DOMAIN: 'example.com',
FRONTEND_URL: 'https://example.com',
};
return env[key];

View File

@ -21,28 +21,10 @@ export class DomainManagerService {
) {}
getFrontUrl() {
let baseUrl: URL;
const frontPort = this.environmentService.get('FRONT_PORT');
const frontDomain = this.environmentService.get('FRONT_DOMAIN');
const frontProtocol = this.environmentService.get('FRONT_PROTOCOL');
const serverUrl = this.environmentService.get('SERVER_URL');
if (!frontDomain) {
baseUrl = new URL(serverUrl);
} else {
baseUrl = new URL(`${frontProtocol}://${frontDomain}`);
}
if (frontPort) {
baseUrl.port = frontPort.toString();
}
if (frontProtocol) {
baseUrl.protocol = frontProtocol;
}
return baseUrl;
return new URL(
this.environmentService.get('FRONTEND_URL') ??
this.environmentService.get('SERVER_URL'),
);
}
getBaseUrl(): URL {

View File

@ -551,11 +551,11 @@ export class EnvironmentVariables {
@EnvironmentVariablesMetadata({
group: EnvironmentVariablesGroup.ServerConfig,
description: 'Domain for the frontend application',
description: 'Url for the frontend application',
})
@IsString()
@IsUrl({ require_tld: false, require_protocol: true })
@IsOptional()
FRONT_DOMAIN?: string;
FRONTEND_URL: string;
@EnvironmentVariablesMetadata({
group: EnvironmentVariablesGroup.ServerConfig,
@ -566,23 +566,6 @@ export class EnvironmentVariables {
@ValidateIf((env) => env.IS_MULTIWORKSPACE_ENABLED)
DEFAULT_SUBDOMAIN = 'app';
@EnvironmentVariablesMetadata({
group: EnvironmentVariablesGroup.ServerConfig,
description: 'Protocol for the frontend application (http or https)',
})
@IsString()
@IsOptional()
FRONT_PROTOCOL?: 'http' | 'https' = 'http';
@EnvironmentVariablesMetadata({
group: EnvironmentVariablesGroup.ServerConfig,
description: 'Port for the frontend application',
})
@CastToPositiveNumber()
@IsNumber()
@IsOptional()
FRONT_PORT?: number;
@EnvironmentVariablesMetadata({
group: EnvironmentVariablesGroup.Other,
description: 'ID for the Chrome extension',

View File

@ -155,8 +155,7 @@ yarn command:prod cron:calendar:ongoing-stale
['FRONT_DOMAIN', 'localhost', 'Domain of the hosted frontend'],
['DEFAULT_SUBDOMAIN', 'app', 'The default subdomain name when multiworkspace mode is enabled'],
['SERVER_URL', 'http://localhost:3000', 'Url to the hosted server'],
['FRONT_PROTOCOL', 'http', 'protocol of the frontend server. Could be `http` or `https`'],
['FRONT_PORT', '3001', 'Port of the frontend server.'],
['FRONTEND_URL', '$SERVER_URL', 'Url to the frontend server. Same as SERVER_URL by default'],
['PORT', '3000', 'Port of the backend server'],
['CACHE_STORAGE_TTL', '3600 * 24 * 7', 'Cache TTL in seconds']
]}></ArticleTable>

View File

@ -26,7 +26,14 @@ If you want to upgrade your instance by few versions, e.g. from 0.33.0 to 0.35.0
## Version-specific upgrade steps
### v0.41.0 to v0.42.0
Upgrade your Twenty instance to use v0.42.0 image
**Environment Variables**
- Removed: `FRONT_PORT`, `FRONT_PROTOCOL`, `FRONT_DOMAIN`, `PORT`
- Added: `FRONTEND_URL`, `NODE_PORT`
### v0.40.0 to v0.41.0