changed deployment
This commit is contained in:
parent
ea4e057b02
commit
70396c321a
22 changed files with 391 additions and 52 deletions
|
|
@ -3,6 +3,8 @@ WORKDIR /app
|
|||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
ARG VITE_GO_LOOSE_API_KEY
|
||||
ENV VITE_GO_LOOSE_API_KEY=$VITE_GO_LOOSE_API_KEY
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:1.29-alpine
|
||||
|
|
|
|||
|
|
@ -37,10 +37,26 @@ application shell.
|
|||
## API integration
|
||||
|
||||
For local tenant hosts such as `nmbs.guess.local`, `src/api/client.ts` derives
|
||||
tenant `nmbs`, calls `http://nmbs.guess.local:8080/api`, and sends
|
||||
tenant `nmbs`, calls same-origin `/api` through the shared HTTPS proxy, and sends
|
||||
`X-Tenant-Id: nmbs` on every JSON, multipart, file-download, and event-stream
|
||||
request. `ypto.guess.local` behaves identically for tenant `ypto`. Other
|
||||
hostnames use same-origin `/api`; Vite retains its `/api` proxy for that case.
|
||||
|
||||
Set `VITE_GO_LOOSE_API_KEY` before `npm run dev` or `npm run build` to also send
|
||||
`X-API-Key`. Vite reads `frontend/.env.local` for local development; that file
|
||||
matches `*.local` and must not be committed. The standalone frontend image
|
||||
accepts the same value as a build argument:
|
||||
|
||||
```bash
|
||||
docker build --build-arg VITE_GO_LOOSE_API_KEY='gl_replace_with_issued_secret' \
|
||||
-t go-guess-frontend .
|
||||
```
|
||||
|
||||
The variable is inlined into the JavaScript bundle. Treat it as an application
|
||||
credential for Go Loose, not as a secret equivalent to the interviewer JWT. If
|
||||
it is unset or empty, the client omits the header and protected interviewer
|
||||
routes fail closed with 401. Login and participant routes do not require the
|
||||
key, but the client still sends it when the variable is present.
|
||||
Invitation and participant-meeting URLs use the validated request origin so
|
||||
links stay on the tenant hostname. Copy actions fall back to a temporary selected
|
||||
textarea when the Clipboard API is unavailable on local HTTP domains.
|
||||
|
|
@ -104,5 +120,7 @@ receives interviewer notes or assessment reference answers.
|
|||
|
||||
## Container
|
||||
|
||||
Build with `docker build -t go-guess-frontend .`. The production Nginx server serves the SPA and
|
||||
proxies `/api` to the Docker Compose service `api:8080`.
|
||||
Build with `docker build -t go-guess-frontend .`. Pass
|
||||
`--build-arg VITE_GO_LOOSE_API_KEY=...` when the image must call protected
|
||||
interviewer routes; see the API integration section. The production Nginx server
|
||||
serves the SPA and proxies `/api` to the Docker Compose service `api:8080`.
|
||||
|
|
|
|||
|
|
@ -7,14 +7,12 @@ describe('API client', () => {
|
|||
sessionStorage.clear()
|
||||
})
|
||||
|
||||
it('derives the local tenant API origin from the browser hostname', () => {
|
||||
it('uses the same-origin API behind the local HTTPS proxy', () => {
|
||||
expect(tenantFromHostname('nmbs.guess.local')).toBe('nmbs')
|
||||
expect(tenantFromHostname('ypto.guess.local')).toBe('ypto')
|
||||
expect(tenantFromHostname('localhost')).toBeNull()
|
||||
expect(tenantFromHostname('127.0.0.1')).toBeNull()
|
||||
expect(apiBaseURL({ hostname: 'nmbs.guess.local', protocol: 'http:' })).toBe(
|
||||
'http://nmbs.guess.local:8080/api',
|
||||
)
|
||||
expect(apiBaseURL({ hostname: 'nmbs.guess.local', protocol: 'https:' })).toBe('/api')
|
||||
expect(apiBaseURL({ hostname: 'app.example.com', protocol: 'https:' })).toBe('/api')
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export function tenantFromHostname(hostname: string): string | null {
|
|||
export function apiBaseURL(location: Pick<Location, 'hostname' | 'protocol'>): string {
|
||||
const hostname = location.hostname.toLowerCase().replace(/\.$/, '')
|
||||
if (hostname.endsWith('.guess.local')) {
|
||||
return `${location.protocol}//${hostname}:8080/api`
|
||||
return '/api'
|
||||
}
|
||||
return '/api'
|
||||
}
|
||||
|
|
@ -93,7 +93,11 @@ function apiURL(path: string): string {
|
|||
|
||||
function tenantHeader(): Record<string, string> {
|
||||
const tenant = tenantFromHostname(window.location.hostname)
|
||||
return tenant ? { 'X-Tenant-Id': tenant } : {}
|
||||
const apiKey = import.meta.env.VITE_GO_LOOSE_API_KEY
|
||||
return {
|
||||
...(tenant ? { 'X-Tenant-Id': tenant } : {}),
|
||||
...(typeof apiKey === 'string' && apiKey !== '' ? { 'X-API-Key': apiKey } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
async function request<T>(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue