diff --git a/.dockerignore b/.dockerignore index f910195d..bd684abf 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,45 +1,47 @@ -.svelte-kit -.vite -node_modules -dist -build -.cache -.DS_Store -.vscode -.idea -.git +# Build artifacts and local state +.svelte-kit/ +.vite/ +node_modules/ +build/ +dist/ +.cache/ + +# VCS and IDE +.git/ .gitignore -coverage -tests -documentation -backups +.vscode/ +.idea/ + +# OS junk +.DS_Store +.directory + +# Logs and temp files *.log *.bak *.tgz -.env -.env.* -npm-debug.log -package-lock.json.bak -yarn-error.log -/.cache -/.parcel-cachenode_modules/ -build/ -.svelte-kit/ -.git/ -.env -.env.* -!.env.staging -!.env.prod -npm_deploy/ -test-results/ -test_results/ -documentation/ -backups/ -*.log -*.bak -.claude/ -.vscode/ npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* + +# Test output and dev-only dirs +tests/ +test-results/ +test_results/ +coverage/ +documentation/ +backups/ +.claude/ + +# Deployment artifacts +npm_deploy/ +package-lock.json.bak + +# Env files: exclude all live secrets, allow only the per-environment files needed for Docker builds. +# .env.local is workstation-only and must never enter a container image. +.env +.env.* +!.env.dev +!.env.test +!.env.prod diff --git a/.env.dev.default b/.env.dev.default new file mode 100644 index 00000000..a9508c21 --- /dev/null +++ b/.env.dev.default @@ -0,0 +1,17 @@ +# One Sky IT's Aether Framework and System — DEV template (dev-*.oneskyit.com) +# Copy to .env.dev and fill in real values. + + +# Aether API access +PUBLIC_AE_API_PROTOCOL=https +PUBLIC_AE_API_SERVER=dev-api.oneskyit.com +PUBLIC_AE_API_BAK_SERVER=test-api.oneskyit.com +PUBLIC_AE_API_PORT=443 +PUBLIC_AE_API_PATH= +PUBLIC_AE_API_SECRET_KEY=XXXX +PUBLIC_AE_API_CRUD_SUPER_KEY=XXXX +# Bootstrap key: used only for the unauthenticated site-domain lookup on first load. +# Separate from the main API key — has limited permissions (no account_id required). +PUBLIC_AE_BOOTSTRAP_KEY=XXXX +PUBLIC_AE_NO_ACCOUNT_ID=No_Account_ID_Here + diff --git a/.env.prod.default b/.env.prod.default index 63242891..ff79d305 100644 --- a/.env.prod.default +++ b/.env.prod.default @@ -1,28 +1,14 @@ -# One Sky IT's Aether Framework and System — PRODUCTION template +# One Sky IT's Aether Framework and System — PROD template (api.oneskyit.com) # Copy to .env.prod and fill in real values. -# AE_CFG_ID: 1=Default, 5=Home Dev, 7=Live Testing/Prod - -# Shared config record (controls SMTP, API routing, external keys from DB) -AE_CFG_ID=7 # Aether API access PUBLIC_AE_API_PROTOCOL=https PUBLIC_AE_API_SERVER=api.oneskyit.com PUBLIC_AE_API_BAK_SERVER=bak-api.oneskyit.com PUBLIC_AE_API_PORT=443 -PUBLIC_AE_API_PATH= PUBLIC_AE_API_SECRET_KEY=XXXX PUBLIC_AE_API_CRUD_SUPER_KEY=XXXX # Bootstrap key: used only for the unauthenticated site-domain lookup on first load. # Separate from the main API key — has limited permissions (no account_id required). PUBLIC_AE_BOOTSTRAP_KEY=XXXX PUBLIC_AE_NO_ACCOUNT_ID=No_Account_ID_Here -PUBLIC_AE_NO_ACCOUNT_ID_TOKEN=Nothing_to_see_here - -# SvelteKit app config -AE_APP_NODE_PORT=3001 - -# Default demo/client context (set to the target account for this deployment) -PUBLIC_AE_ACCOUNT_ID=XXXX -PUBLIC_AE_EVENT_ID=XXXX -PUBLIC_AE_SPONSORSHIP_CFG_ID=XXXX diff --git a/.env.test.default b/.env.test.default new file mode 100644 index 00000000..0ea002de --- /dev/null +++ b/.env.test.default @@ -0,0 +1,14 @@ +# One Sky IT's Aether Framework and System — TEST template (test-api.oneskyit.com) +# Copy to .env.test and fill in real values. + +# Aether API access +PUBLIC_AE_API_PROTOCOL=https +PUBLIC_AE_API_SERVER=test-api.oneskyit.com +PUBLIC_AE_API_BAK_SERVER=api.oneskyit.com +PUBLIC_AE_API_PORT=443 +PUBLIC_AE_API_SECRET_KEY=XXXX +PUBLIC_AE_API_CRUD_SUPER_KEY=XXXX +# Bootstrap key: used only for the unauthenticated site-domain lookup on first load. +# Separate from the main API key — has limited permissions (no account_id required). +PUBLIC_AE_BOOTSTRAP_KEY=XXXX +PUBLIC_AE_NO_ACCOUNT_ID=No_Account_ID_Here diff --git a/.gitignore b/.gitignore index 4eb799f8..03414e92 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,8 @@ node_modules .env.* !.env.example !.env.prod.default -!.env.staging.default +!.env.test.default +!.env.dev.default vite.config.js.timestamp-* vite.config.ts.timestamp-* diff --git a/Dockerfile b/Dockerfile index 827ca905..3dd3da4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,18 +9,32 @@ RUN npm install # Copy the rest of the source code. COPY . . -# Build Argument to determine build environment (staging, prod, or production). -ARG BUILD_MODE=staging +# Build Argument to determine build environment (dev, test, prod). +ARG BUILD_MODE=dev ENV NODE_ENV=production # Sync the SvelteKit project to generate ./.svelte-kit/tsconfig.json RUN npx svelte-kit sync # Perform the build based on the BUILD_MODE argument. +# Each script uses vite --mode , which reads .env. directly — no cp hack needed. RUN if [ "$BUILD_MODE" = "prod" ] || [ "$BUILD_MODE" = "production" ]; then \ npm run build:prod; \ + elif [ "$BUILD_MODE" = "test" ]; then \ + npm run build:test; \ else \ - npm run build:staging; \ + npm run build:dev; \ + fi + +# Copy the source env file to .env.runtime for the deploy stage. +# PUBLIC_* vars are baked into the JS bundle by vite; non-PUBLIC vars (AE_CFG_ID, +# AE_APP_NODE_PORT) are read by the Node server at runtime and need this file. +RUN if [ "$BUILD_MODE" = "prod" ] || [ "$BUILD_MODE" = "production" ]; then \ + cp .env.prod .env.runtime; \ + elif [ "$BUILD_MODE" = "test" ]; then \ + cp .env.test .env.runtime; \ + else \ + cp .env.dev .env.runtime; \ fi # Stage 2: Final runtime image @@ -35,8 +49,8 @@ COPY --from=builder /app/package-lock.json . # Install only production dependencies. RUN npm install --omit=dev -# Copy the resulting .env.production file to .env. -COPY --from=builder /app/.env.production .env +# Copy the runtime env file (non-PUBLIC vars for the Node server). +COPY --from=builder /app/.env.runtime .env # SvelteKit (via adapter-node) defaults to port 3000. EXPOSE 3000 diff --git a/documentation/GUIDE__Development.md b/documentation/GUIDE__Development.md index 81ab4c4d..d5cd7c53 100644 --- a/documentation/GUIDE__Development.md +++ b/documentation/GUIDE__Development.md @@ -10,7 +10,7 @@ - **Zero Tolerance:** If a task introduces even a single svelte-check warning or error, it must not be merged. Resolve all warnings before committing. 2. **Type Safety:** Ensure interfaces in `src/lib/types/ae_types.ts` match backend schemas. 3. **Reactivity Check:** Verify Svelte 5 runes (`$state`, `$derived`) are not creating race conditions with Dexie `liveQuery`. -4. **Build Check:** For major changes, run `npm run build:staging` to ensure no SSR or build-time failures. +4. **Build Check:** For major changes, run `npm run build:dev` to ensure no SSR or build-time failures. 5. **Integration Tests:** For changes to badge print, event layouts, or auth/store logic, run the relevant Playwright test file(s): ```bash npx playwright test tests/event_badge_render.test.ts tests/event_badge_attendee_workflow.test.ts diff --git a/package.json b/package.json index 0dee0798..23983043 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,9 @@ "scripts": { "dev": "vite dev", "build": "vite build", - "build:prod": "cp .env.prod .env.production && vite build", - "build:staging": "cp .env.staging .env.production && vite build", + "build:dev": "vite build --mode dev", + "build:test": "vite build --mode test", + "build:prod": "vite build --mode prod", "preview": "vite preview", "test": "npm run test:integration && npm run test:unit", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", @@ -17,7 +18,8 @@ "format": "prettier --write .", "test:integration": "playwright test", "test:unit": "vitest", - "deploy:staging": "docker compose -f ../aether_container_env/docker-compose.yml build ae_app && docker compose -f ../aether_container_env/docker-compose.yml up -d ae_app", + "deploy:dev": "docker compose -f ../aether_container_env/docker-compose.yml build ae_app && docker compose -f ../aether_container_env/docker-compose.yml up -d ae_app", + "deploy:test": "docker compose -f ../aether_container_env/docker-compose.yml build --build-arg BUILD_MODE=test ae_app && docker compose -f ../aether_container_env/docker-compose.yml up -d ae_app", "deploy:prod": "docker compose -f ../aether_container_env/docker-compose.yml build --build-arg BUILD_MODE=prod ae_app && docker compose -f ../aether_container_env/docker-compose.yml up -d --remove-orphans ae_app", "compose:down": "docker compose -f ../aether_container_env/docker-compose.yml --profile database down" }, diff --git a/src/lib/stores/ae_stores.ts b/src/lib/stores/ae_stores.ts index 3ec3df43..ccc5f22f 100644 --- a/src/lib/stores/ae_stores.ts +++ b/src/lib/stores/ae_stores.ts @@ -18,10 +18,10 @@ import { PUBLIC_AE_API_SECRET_KEY, PUBLIC_AE_API_CRUD_SUPER_KEY, PUBLIC_AE_NO_ACCOUNT_ID, - PUBLIC_AE_NO_ACCOUNT_ID_TOKEN, - PUBLIC_AE_ACCOUNT_ID, - PUBLIC_AE_EVENT_ID, - PUBLIC_AE_SPONSORSHIP_CFG_ID + // PUBLIC_AE_NO_ACCOUNT_ID_TOKEN, + // PUBLIC_AE_ACCOUNT_ID, + // PUBLIC_AE_EVENT_ID, + // PUBLIC_AE_SPONSORSHIP_CFG_ID } from '$env/static/public'; const api_server_fqdn = PUBLIC_AE_API_SERVER; // 'api.oneskyit.com' @@ -34,9 +34,9 @@ const api_crud_super_key = PUBLIC_AE_API_CRUD_SUPER_KEY; // const ae_account_id = PUBLIC_AE_ACCOUNT_ID; const ae_account_id: null | string = null; const ae_no_account_id = PUBLIC_AE_NO_ACCOUNT_ID; -const ae_no_account_id_token = PUBLIC_AE_NO_ACCOUNT_ID_TOKEN; -const ae_event_id = PUBLIC_AE_EVENT_ID; -const ae_sponsorship_cfg_id = PUBLIC_AE_SPONSORSHIP_CFG_ID; +// const ae_no_account_id_token = PUBLIC_AE_NO_ACCOUNT_ID_TOKEN; +// const ae_event_id = PUBLIC_AE_EVENT_ID; +// const ae_sponsorship_cfg_id = PUBLIC_AE_SPONSORSHIP_CFG_ID; // Loose bag-of-anything type used throughout the store. Once stores are broken into // typed domain files, individual structs will have proper interfaces instead. @@ -174,7 +174,7 @@ const ae_app_local_data_defaults: key_val = { posts: {}, sponsorships: { - cfg_id: ae_sponsorship_cfg_id, + cfg_id: null, for_type: null, for_id: null, @@ -350,7 +350,7 @@ const slct_obj_template: key_val = { sponsorship_id: null, sponsorship_obj: {}, sponsorship_obj_li: [], - sponsorship_cfg_id: ae_sponsorship_cfg_id, + sponsorship_cfg_id: null, sponsorship_cfg_obj: {}, sponsorship_cfg_obj_li: [], post_id: null,