diff --git a/vite.chatelet.config.ts b/vite.chatelet.config.ts
new file mode 100644
index 0000000..0d69fb8
--- /dev/null
+++ b/vite.chatelet.config.ts
@@ -0,0 +1,142 @@
+import { fileURLToPath, URL } from 'node:url'
+import vue from '@vitejs/plugin-vue'
+import tailwindcss from '@tailwindcss/vite'
+import { defineConfig, type Plugin } from 'vite'
+import { VitePWA } from 'vite-plugin-pwa'
+import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'
+import { visualizer } from 'rollup-plugin-visualizer'
+import {
+ brand,
+ brandAlias,
+ brandAppBannerAliasEntry,
+ brandAppLogoAliasEntry,
+ brandAssetsPlugin,
+ brandHubLogoAliasEntry,
+ brandManifestName,
+ resolveAppBanner,
+} from './vite-branding'
+
+/**
+ * SPA fallback: rewrite dev-server requests to chatelet.html.
+ */
+function chateletHtmlPlugin(): Plugin {
+ return {
+ name: 'chatelet-html-rewrite',
+ configureServer(server) {
+ server.middlewares.use((req, _res, next) => {
+ const path = req.url ? req.url.split('?')[0] : ''
+ if (
+ req.url &&
+ !req.url.startsWith('/@') &&
+ !req.url.startsWith('/src/') &&
+ !req.url.startsWith('/node_modules/') &&
+ !path.includes('.')
+ ) {
+ req.url = '/chatelet.html'
+ }
+ next()
+ })
+ },
+ }
+}
+
+/**
+ * Vite config for the standalone chatelet app (guest room booking).
+ *
+ * Set VITE_BASE_PATH to deploy under a path prefix:
+ * VITE_BASE_PATH=/chatelet/ → app.domain/chatelet/ (shared auth)
+ * (default: /) → standalone subdomain
+ */
+const APP_NAME = brandManifestName()
+process.env.VITE_APP_NAME = APP_NAME
+process.env.VITE_APP_BANNER = resolveAppBanner('chatelet') ? '1' : ''
+
+export default defineConfig(({ mode }) => ({
+ base: process.env.VITE_BASE_PATH || '/',
+ cacheDir: 'node_modules/.vite-chatelet',
+ server: {
+ port: 5188,
+ strictPort: true,
+ },
+ plugins: [
+ brandAssetsPlugin(),
+ chateletHtmlPlugin(),
+ vue(),
+ tailwindcss(),
+ VitePWA({
+ registerType: 'autoUpdate',
+ devOptions: {
+ enabled: false,
+ },
+ workbox: {
+ globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
+ navigateFallback: 'chatelet.html',
+ navigateFallbackAllowlist: [
+ new RegExp(`^${(process.env.VITE_BASE_PATH || '/').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`),
+ ],
+ },
+ includeAssets: [
+ 'icons/favicon.ico',
+ 'icons/apple-touch-icon.png',
+ 'icons/icon-192.png',
+ 'icons/icon-512.png',
+ 'icons/icon-maskable-192.png',
+ 'icons/icon-maskable-512.png',
+ ],
+ manifest: {
+ name: APP_NAME,
+ short_name: brand.shortName ?? APP_NAME,
+ description: 'Book a room',
+ theme_color: brand.themeColor ?? '#1f2937',
+ background_color: brand.backgroundColor ?? '#ffffff',
+ display: 'standalone',
+ orientation: 'portrait-primary',
+ start_url: process.env.VITE_BASE_PATH || '/',
+ scope: process.env.VITE_BASE_PATH || '/',
+ id: 'aiolabs-chatelet',
+ categories: ['travel', 'lifestyle'],
+ icons: [
+ { src: 'icons/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
+ { src: 'icons/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
+ { src: 'icons/icon-maskable-192.png', sizes: '192x192', type: 'image/png', purpose: 'maskable' },
+ { src: 'icons/icon-maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
+ ],
+ },
+ }),
+ ViteImageOptimizer({
+ jpg: { quality: 80 },
+ png: { quality: 80 },
+ webp: { lossless: true },
+ }),
+ mode === 'analyze' &&
+ visualizer({
+ open: true,
+ filename: 'dist-chatelet/stats.html',
+ gzipSize: true,
+ brotliSize: true,
+ }),
+ ],
+ resolve: {
+ alias: [
+ brandAppLogoAliasEntry('chatelet'),
+ brandAppBannerAliasEntry('chatelet'),
+ brandHubLogoAliasEntry(),
+ ...Object.entries(brandAlias).map(([find, replacement]) => ({ find, replacement })),
+ { find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)) },
+ ],
+ },
+ build: {
+ outDir: 'dist-chatelet',
+ rollupOptions: {
+ input: 'chatelet.html',
+ output: {
+ manualChunks: {
+ 'vue-vendor': ['vue', 'vue-router', 'pinia'],
+ 'ui-vendor': ['radix-vue', '@vueuse/core'],
+ 'shadcn': ['class-variance-authority', 'clsx', 'tailwind-merge'],
+ },
+ },
+ },
+ chunkSizeWarningLimit: 1000,
+ },
+}))