Skip to content

Commit faa4990

Browse files
feat(backoffice): bootstrap backoffice project (#1797)
* feat(backoffice): bootstrap backoffice project ci(backoffice): create backoffice standalone image * update dependencies in backoffice * update bun lock * fix tests errors --------- Co-authored-by: William Schlegel <william.schlegel@gmail.com>
1 parent 69dc7ae commit faa4990

165 files changed

Lines changed: 7146 additions & 464 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/frontend-dev-guidelines/resources/forms-and-modals.md

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ import { getFieldErrors, handleSubmit } from '@app-builder/utils/form';
9393

9494
### Form Components
9595

96-
| Component | Props | Purpose |
97-
|-----------|-------|---------|
98-
| `FormInput` | `type`, `name`, `defaultValue`, `onChange`, `onBlur`, `valid` | Text/number input with error border |
99-
| `FormLabel` | `name`, `valid` | Label linked to input via `htmlFor` |
100-
| `FormErrorOrDescription` | `errors?`, `description?` | Shows errors or help text |
101-
| `FormTextArea` | Same as FormInput | Multi-line input |
102-
| `FormError` | `field`, `asString?`, `translations?` | Translates Zod error codes to i18n |
96+
| Component | Props | Purpose |
97+
| ------------------------ | ------------------------------------------------------------- | ----------------------------------- |
98+
| `FormInput` | `type`, `name`, `defaultValue`, `onChange`, `onBlur`, `valid` | Text/number input with error border |
99+
| `FormLabel` | `name`, `valid` | Label linked to input via `htmlFor` |
100+
| `FormErrorOrDescription` | `errors?`, `description?` | Shows errors or help text |
101+
| `FormTextArea` | Same as FormInput | Multi-line input |
102+
| `FormError` | `field`, `asString?`, `translations?` | Translates Zod error codes to i18n |
103103

104104
### Number Fields
105105

@@ -161,14 +161,14 @@ export function DeleteConfirmModal({ onDelete }: { onDelete: () => void }) {
161161

162162
### Modal Components
163163

164-
| Component | Purpose |
165-
|-----------|---------|
166-
| `Modal.Root` | Root state manager. Props: `open`, `onOpenChange` |
167-
| `Modal.Trigger` | Opens the modal. Use `asChild` to wrap custom trigger |
168-
| `Modal.Content` | Dialog container. Props: `size` (`small`/`medium`/`large`/`xlarge`) |
169-
| `Modal.Title` | Dialog title (required for accessibility) |
170-
| `Modal.Close` | Closes on click. Use `asChild` to wrap custom button |
171-
| `Modal.Footer` | Standard buttons in the footer, asClosed for the buttons that close the modal, with optional icon and isLoading state |
164+
| Component | Purpose |
165+
| --------------- | --------------------------------------------------------------------------------------------------------------------- |
166+
| `Modal.Root` | Root state manager. Props: `open`, `onOpenChange` |
167+
| `Modal.Trigger` | Opens the modal. Use `asChild` to wrap custom trigger |
168+
| `Modal.Content` | Dialog container. Props: `size` (`small`/`medium`/`large`/`xlarge`) |
169+
| `Modal.Title` | Dialog title (required for accessibility) |
170+
| `Modal.Close` | Closes on click. Use `asChild` to wrap custom button |
171+
| `Modal.Footer` | Standard buttons in the footer, asClosed for the buttons that close the modal, with optional icon and isLoading state |
172172

173173
### Modal with Form
174174

@@ -196,7 +196,7 @@ Wrap `<form>` around `Modal.Title`, content, and `Modal.Footer`:
196196
Right-side sliding panel for detail views. Import from app-builder components.
197197

198198
```typescript
199-
import { Panel } from '@app-builder/components/Panel';
199+
import { Panel } from 'ui-design-system';
200200
import { useTranslation } from 'react-i18next';
201201

202202
export function DetailPanel({ open, onOpenChange }: { open: boolean; onOpenChange: (open: boolean) => void }) {
@@ -225,11 +225,10 @@ export function DetailPanel({ open, onOpenChange }: { open: boolean; onOpenChang
225225

226226
### Panel Sizes
227227

228-
| Size | Max Width |
229-
|------|-----------|
230-
| small | 'max-w-[calc(100vw_/_3)]' |
231-
| medium | 'max-w-[50vw]' |
232-
| large | 'max-w-[calc(100vw_*_(2_/_3))]' |
233-
228+
| Size | Max Width |
229+
| ------ | ------------------------------- |
230+
| small | 'max-w-[calc(100vw_/_3)]' |
231+
| medium | 'max-w-[50vw]' |
232+
| large | 'max-w-[calc(100vw_*_(2_/_3))]' |
234233

235234
Features: slide animation, focus trapping, Escape to close, portal rendering.

.dockerignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
node_modules
1515

1616
# Build outputs
17-
packages/app-builder/build
1817
**/.output
1918
**/.nitro
2019
**/build

.github/workflows/build_and_deploy.yaml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ name: Reusable build and deploy job
33
on:
44
workflow_call:
55
inputs:
6+
app:
7+
type: string
8+
description: "Application to build and deploy (app-builder or backoffice)"
9+
required: true
10+
default: "app-builder"
611
environment:
712
type: string
813
description: "Github environment to use"
@@ -33,7 +38,7 @@ jobs:
3338
environment: ${{ inputs.environment }}
3439
env:
3540
VERSION: ${{ inputs.version }}
36-
IMAGE: europe-west1-docker.pkg.dev/marble-infra/marble/marble-frontend:${{ inputs.version }}
41+
IMAGE: europe-west1-docker.pkg.dev/marble-infra/marble/${{ inputs.app }}:${{ inputs.version }}
3742
SERVICE_ACCOUNT: marble-frontend-cloud-run@${{ vars.GCP_PROJECT_ID }}.iam.gserviceaccount.com
3843
steps:
3944
- name: Checkout
@@ -71,9 +76,9 @@ jobs:
7176
with:
7277
context: .
7378
push: true
74-
target: app-builder
79+
target: ${{ inputs.app }}
7580
tags: ${{ env.IMAGE }}
76-
file: ./Dockerfile
81+
file: ${{ inputs.dockerfile }}
7782
build-args: |
7883
SENTRY_PROJECT=marble-frontend
7984
SENTRY_RELEASE=${{ inputs.SENTRY_RELEASE }}
@@ -89,7 +94,7 @@ jobs:
8994

9095
- name: Deploy server
9196
run: |
92-
gcloud run deploy marble-frontend \
97+
gcloud run deploy ${{ inputs.app }} \
9398
--quiet \
9499
--region="europe-west1" \
95100
--image="$IMAGE"

.github/workflows/check.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,6 @@ jobs:
6060

6161
- name: Build app-builder
6262
run: bun run -F app-builder build
63+
64+
- name: Build backoffice
65+
run: bun run -F backoffice build

.github/workflows/main_push.yaml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,34 @@ jobs:
1616
actions: read
1717
uses: ./.github/workflows/check.yaml
1818

19-
build_and_deploy:
19+
build_and_deploy_app_builder:
2020
needs: check
2121
permissions:
2222
contents: read
2323
actions: read
24-
id-token: 'write' # needed for using open id token to authenticate with GCP
24+
id-token: "write" # needed for using open id token to authenticate with GCP
2525
uses: ./.github/workflows/build_and_deploy.yaml
2626
with:
27-
environment: 'staging'
27+
app: "app-builder"
28+
dockerfile: ./Dockerfile
29+
environment: "staging"
30+
version: latest
31+
SENTRY_RELEASE: ${{ github.sha }}
32+
secrets:
33+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
34+
SEGMENT_WRITE_KEY_OPENSOURCE: ${{ secrets.SEGMENT_WRITE_KEY_OPENSOURCE }}
35+
36+
build_and_deploy_backoffice:
37+
needs: check
38+
permissions:
39+
contents: read
40+
actions: read
41+
id-token: "write" # needed for using open id token to authenticate with GCP
42+
uses: ./.github/workflows/build_and_deploy.yaml
43+
with:
44+
app: "backoffice"
45+
dockerfile: ./Dockerfile.backoffice
46+
environment: "staging"
2847
version: latest
2948
SENTRY_RELEASE: ${{ github.sha }}
3049
secrets:

.github/workflows/tags_push.yaml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,33 @@ jobs:
1717
actions: read
1818
uses: ./.github/workflows/check.yaml
1919

20-
build_and_deploy:
20+
build_and_deploy_app_builder:
2121
needs: check
2222
permissions:
2323
contents: read
2424
actions: read
2525
id-token: "write" # needed for using open id token to authenticate with GCP
2626
uses: ./.github/workflows/build_and_deploy.yaml
2727
with:
28+
app: "app-builder"
29+
dockerfile: ./Dockerfile
30+
environment: "production"
31+
version: ${{ github.ref_name }}
32+
SENTRY_RELEASE: ${{ github.ref_name }}
33+
secrets:
34+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
35+
SEGMENT_WRITE_KEY_OPENSOURCE: ${{ secrets.SEGMENT_WRITE_KEY_OPENSOURCE }}
36+
37+
build_and_deploy_backoffice:
38+
needs: check
39+
permissions:
40+
contents: read
41+
actions: read
42+
id-token: "write" # needed for using open id token to authenticate with GCP
43+
uses: ./.github/workflows/build_and_deploy.yaml
44+
with:
45+
app: "backoffice"
46+
dockerfile: ./Dockerfile.backoffice
2847
environment: "production"
2948
version: ${{ github.ref_name }}
3049
SENTRY_RELEASE: ${{ github.ref_name }}

Dockerfile

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ WORKDIR /usr/src/app
77
# Copy only workspace manifests to maximize install cache hits
88
COPY package.json bun.lock ./
99
COPY packages/app-builder/package.json ./packages/app-builder/
10+
COPY packages/backoffice/package.json ./packages/backoffice/
1011
COPY packages/shared/package.json ./packages/shared/
1112
COPY packages/marble-api/package.json ./packages/marble-api/
1213
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
@@ -68,9 +69,13 @@ RUN --mount=type=secret,id=SENTRY_AUTH_TOKEN \
6869
if [ -f /run/secrets/SENTRY_AUTH_TOKEN ]; then export SENTRY_AUTH_TOKEN=$(cat /run/secrets/SENTRY_AUTH_TOKEN); fi; \
6970
bun run -F app-builder build
7071

72+
RUN bun run -F backoffice build
73+
7174
# Collect build artifacts and dependencies for runtime
7275
RUN mkdir -p /prod/app-builder && \
73-
cp -R packages/app-builder/.output /prod/app-builder/.output
76+
cp -R packages/app-builder/.output /prod/app-builder/.output && \
77+
mkdir -p /prod/backoffice && \
78+
cp -R packages/backoffice/.output /prod/backoffice/.output
7479

7580
# ---- Production Dependencies stage ----
7681
FROM ${BUN_IMAGE} AS deps-prod
@@ -79,6 +84,7 @@ WORKDIR /usr/src/app
7984
# Copy only workspace manifests to maximize install cache hits
8085
COPY package.json bun.lock ./
8186
COPY packages/app-builder/package.json ./packages/app-builder/
87+
COPY packages/backoffice/package.json ./packages/backoffice/
8288
COPY packages/shared/package.json ./packages/shared/
8389
COPY packages/marble-api/package.json ./packages/marble-api/
8490
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
@@ -119,3 +125,23 @@ COPY --from=deps-prod /usr/src/app/node_modules ./node_modules
119125

120126
EXPOSE $PORT
121127
CMD [".output/server/index.mjs"]
128+
129+
# ---- Runtime stage (backoffice) ----
130+
FROM ${BUN_IMAGE} AS backoffice
131+
WORKDIR /prod/backoffice
132+
133+
ENV NODE_ENV=production
134+
ARG PORT=8080
135+
ENV PORT=${PORT:-8080}
136+
137+
ARG APP_VERSION
138+
ENV APP_VERSION=$APP_VERSION
139+
140+
# Copy build output
141+
COPY --from=build /prod/backoffice/.output ./.output
142+
143+
# Copy ONLY production dependencies
144+
COPY --from=deps-prod /usr/src/app/node_modules ./node_modules
145+
146+
EXPOSE $PORT
147+
CMD ["bun", ".output/server/index.mjs"]

Dockerfile.backoffice

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
ARG BUN_IMAGE=oven/bun:1.3
2+
ARG RUNTIME_IMAGE=oven/bun:1.3-distroless
3+
# ---- Dependencies stage ----
4+
FROM ${BUN_IMAGE} AS deps-dev
5+
WORKDIR /usr/src/app
6+
7+
# Copy only workspace manifests to maximize install cache hits
8+
COPY package.json bun.lock ./
9+
COPY packages/app-builder/package.json ./packages/app-builder/
10+
COPY packages/backoffice/package.json ./packages/backoffice/
11+
COPY packages/shared/package.json ./packages/shared/
12+
COPY packages/marble-api/package.json ./packages/marble-api/
13+
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
14+
COPY packages/ui-design-system/package.json ./packages/ui-design-system/
15+
COPY packages/ui-icons/package.json ./packages/ui-icons/
16+
COPY packages/tailwind-preset/package.json ./packages/tailwind-preset/
17+
COPY packages/tests/package.json ./packages/tests/
18+
19+
# Install WITH dev dependencies (needed for build stage)
20+
RUN --mount=type=cache,target=/root/.bun \
21+
bun ci
22+
23+
# ---- Build stage ---- (uses dev deps from above)
24+
FROM ${BUN_IMAGE} AS build
25+
WORKDIR /usr/src/app
26+
27+
# Copy full source AFTER deps to leverage layer caching
28+
COPY . .
29+
# Reuse cached node_modules from deps stage (root + workspace-local)
30+
COPY --from=deps-dev /usr/src/app/node_modules ./node_modules
31+
COPY --from=deps-dev /usr/src/app/packages/backoffice/node_modules ./packages/backoffice/node_modules
32+
33+
# Build-time configuration
34+
ARG SENTRY_ORG
35+
ENV SENTRY_ORG=$SENTRY_ORG
36+
ARG SENTRY_PROJECT
37+
ENV SENTRY_PROJECT=$SENTRY_PROJECT
38+
ARG SENTRY_RELEASE
39+
ENV SENTRY_RELEASE=$SENTRY_RELEASE
40+
41+
RUN bun run -F backoffice build
42+
43+
# Collect build artifacts and dependencies for runtime
44+
RUN mkdir -p /prod/backoffice && \
45+
cp -R packages/backoffice/.output /prod/backoffice/.output
46+
47+
# ---- Production Dependencies stage ----
48+
FROM ${BUN_IMAGE} AS deps-prod
49+
WORKDIR /usr/src/app
50+
51+
# Copy only workspace manifests to maximize install cache hits
52+
COPY package.json bun.lock ./
53+
COPY packages/app-builder/package.json ./packages/app-builder/
54+
COPY packages/backoffice/package.json ./packages/backoffice/
55+
COPY packages/shared/package.json ./packages/shared/
56+
COPY packages/marble-api/package.json ./packages/marble-api/
57+
COPY packages/typescript-utils/package.json ./packages/typescript-utils/
58+
COPY packages/ui-design-system/package.json ./packages/ui-design-system/
59+
COPY packages/ui-icons/package.json ./packages/ui-icons/
60+
COPY packages/tailwind-preset/package.json ./packages/tailwind-preset/
61+
COPY packages/tests/package.json ./packages/tests/
62+
63+
# Install ONLY production dependencies
64+
RUN --mount=type=cache,target=/root/.bun \
65+
bun install --production --frozen-lockfile
66+
67+
# ---- Runtime stage (backoffice) ----
68+
FROM ${RUNTIME_IMAGE} AS backoffice
69+
WORKDIR /prod/backoffice
70+
71+
ENV NODE_ENV=production
72+
ARG PORT=8080
73+
ENV PORT=${PORT:-8080}
74+
75+
ARG APP_VERSION
76+
ENV APP_VERSION=$APP_VERSION
77+
78+
# Copy build output
79+
COPY --from=build /prod/backoffice/.output ./.output
80+
81+
# Copy ONLY production dependencies
82+
COPY --from=deps-prod /usr/src/app/node_modules ./node_modules
83+
84+
EXPOSE $PORT
85+
CMD [".output/server/index.mjs"]

biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"!**/coverage",
2222
"!**/public",
2323
"!packages/marble-api/src/generated",
24-
"!packages/app-builder/src/routeTree.gen.ts",
24+
"!packages/*/src/routeTree.gen.ts",
2525
"!packages-licenses.json"
2626
]
2727
},

0 commit comments

Comments
 (0)