create-nextblock 0.17.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +4 -2
- package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +8203 -7038
- package/templates/nextblock-template/app/cms/settings/security/page.tsx +1 -1
- package/templates/nextblock-template/docs/02-ECOMMERCE-CAPABILITIES.md +1 -1
- package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +1 -1
- package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +402 -293
- package/templates/nextblock-template/docs/05-DEVELOPER-GUIDE.md +15 -8
- package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +5 -5
- package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +1 -1
- package/templates/nextblock-template/docs/11-SELF-HOSTED-DOCKER.md +4 -1
- package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +12 -9
- package/templates/nextblock-template/docs/13-STAYING-UP-TO-DATE.md +8 -0
- package/templates/nextblock-template/docs/14-MESSAGES-INBOX.md +2 -2
- package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +154 -163
- package/templates/nextblock-template/lib/config/email-settings.ts +323 -323
- package/templates/nextblock-template/lib/seo/redirect-store.ts +3 -2
- package/templates/nextblock-template/lib/setup/migrations-bundle.ts +18 -203
- package/templates/nextblock-template/package.json +1 -1
|
@@ -10,7 +10,7 @@ NextBlock CMS is an AI-Native, Open-Core Content Management System purpose-built
|
|
|
10
10
|
|
|
11
11
|
The system's central value proposition — "Speed. Scalability. AI-Readiness (coming soon)." — is encoded directly in its architectural decisions: a Next.js 16 App Router application (`apps/nextblock`) backed by Supabase, leveraging React Server Components, edge caching, and an image-optimization pipeline targeting a default 100/100 Lighthouse Performance score. Users bootstrap new projects in under thirty seconds via the `npm create nextblock@latest` CLI, which produces a standalone, production-ready Next.js application.
|
|
12
12
|
|
|
13
|
-
A live sandbox instance at `https://cms.nextblock.dev/` (accessible with demo credentials `demo@nextblock.dev` / `password`) resets
|
|
13
|
+
A live sandbox instance at `https://cms.nextblock.dev/` (accessible with demo credentials `demo@nextblock.dev` / `password`) resets every 15 minutes via a cron-triggered endpoint (`/api/cron/reset-sandbox`) to provide evaluators with a clean-state environment.
|
|
14
14
|
|
|
15
15
|
### 1.1.2 Core Business Problem
|
|
16
16
|
|
|
@@ -27,7 +27,7 @@ The core problem statement — "stop cloning heavy repos; start with our CLI and
|
|
|
27
27
|
|
|
28
28
|
### 1.1.3 Key Stakeholders and Users
|
|
29
29
|
|
|
30
|
-
The system recognizes three database-enforced user roles (defined as the `user_role` enum `ADMIN`, `WRITER`, `USER` in migration `
|
|
30
|
+
The system recognizes three database-enforced user roles (defined as the `user_role` enum `ADMIN`, `WRITER`, `USER` in migration `02001_baseline_schema.sql`) and three additional implicit stakeholder classes observable from the scaffolding and documentation artifacts.
|
|
31
31
|
|
|
32
32
|
| Stakeholder | Role / Audience | Primary Entry Point |
|
|
33
33
|
|:--|:--|:--|
|
|
@@ -247,7 +247,7 @@ The following architectural invariants are enforced at workspace level and must
|
|
|
247
247
|
| Media Optimization | Blur placeholders generated for uploaded images | `sharp` + `plaiceholder` pipeline |
|
|
248
248
|
| Developer Adoption | CLI install success rate | `apps/create-nextblock/bin/create-nextblock.js` |
|
|
249
249
|
| Commerce Conversion | Checkout success by provider (Stripe / Freemius) | `app/api/checkout/route.ts` + webhooks |
|
|
250
|
-
| Scheduled Job Health |
|
|
250
|
+
| Scheduled Job Health | Success of reset-sandbox (every 15 min) and sync-currencies (daily) | `vercel.json` cron configuration |
|
|
251
251
|
| Bundle Discipline | Removed console calls in production | `compiler.removeConsole` in `next.config.js` |
|
|
252
252
|
|
|
253
253
|
---
|
|
@@ -267,7 +267,7 @@ The following architectural invariants are enforced at workspace level and must
|
|
|
267
267
|
|
|
268
268
|
**Editor Capabilities** — The `@nextblock-cms/editor` library exports `Editor`, `NotionEditor`, `EditorToolbar`, `EditorBubbleMenu`, `EditorFloatingMenu`, `EnhancedFloatingMenu`, `SlashCommandList`, `DragHandle`, `HtmlContent`, and `editorExtensions`. Feature set includes Tiptap StarterKit rich text, syntax-highlighted code blocks, tables, task lists, slash commands, drag handles, image handling, character counting, typography, mathematics, emoji, mentions, inline alert and call-to-action widgets, and custom HTML-preserving extensions for `div`, `style`, `script`, `svg`, `span`, and catch-all attribute preservation. A media-picker bridge is exposed via `setOpenImagePicker()`.
|
|
269
269
|
|
|
270
|
-
**Translation & Localization** — The set of served locales is the active rows of the `languages` table (managed at `/cms/settings/languages`; the proxy reads them with a 60-second in-memory cache and only falls back to the hardcoded `FALLBACK_LOCALES` `en`/`fr` when the DB is unreadable), backed by `languages` and `translations` tables from migration `
|
|
270
|
+
**Translation & Localization** — The set of served locales is the active rows of the `languages` table (managed at `/cms/settings/languages`; the proxy reads them with a 60-second in-memory cache and only falls back to the hardcoded `FALLBACK_LOCALES` `en`/`fr` when the DB is unreadable), backed by `languages` and `translations` tables from migration `02001_baseline_schema.sql`. First-visit language detection is admin-configurable (see F-007): browser `Accept-Language`, IP-country via host geo headers, combined, or always-default — implemented in `apps/nextblock/lib/i18n/detection.ts` and stored in `site_settings.language_detection_settings`. Content revision history is stored as snapshot + JSON Patch diff (enum `revision_type: snapshot, diff`) per migration `02001_baseline_schema.sql`.
|
|
271
271
|
|
|
272
272
|
**Page Lifecycle** — Pages move through `draft`, `published`, and `archived` statuses (enum `page_status`).
|
|
273
273
|
|
|
@@ -343,7 +343,7 @@ Profile completion is enforced via a redirect: users without a `full_name` value
|
|
|
343
343
|
|
|
344
344
|
#### 1.3.2.3 Geographic and Market Coverage
|
|
345
345
|
|
|
346
|
-
Shipping resolution operates at country and state granularity. Multi-currency pricing is supported with a configurable default currency seeded in migration `
|
|
346
|
+
Shipping resolution operates at country and state granularity. Multi-currency pricing is supported with a configurable default currency seeded in migration `02001_baseline_schema.sql`. The database schema includes a `shipping_zone_locations.postal_code` column for future finer-grained geographic resolution, although the current runtime resolver does not yet consume it.
|
|
347
347
|
|
|
348
348
|
#### 1.3.2.4 Data Domains Included
|
|
349
349
|
|
|
@@ -403,7 +403,7 @@ The system does not natively integrate with: alternative payment processors beyo
|
|
|
403
403
|
- `tsconfig.base.json` — Shared TypeScript strict-mode configuration and `@nextblock-cms/*` path aliases
|
|
404
404
|
- `components.json` — shadcn/ui configuration (Slate base, CSS variables, RSC)
|
|
405
405
|
- `tailwind.config.js` — Root Tailwind CSS theme tokens and dark-mode configuration
|
|
406
|
-
- `vercel.json` — Cron schedule definitions (reset-sandbox
|
|
406
|
+
- `vercel.json` — Cron schedule definitions (reset-sandbox every 15 minutes, sync-currencies at 18:00 UTC)
|
|
407
407
|
- `.env.example` — Environment variable reference template
|
|
408
408
|
|
|
409
409
|
### 1.4.2 Documentation Hub (`docs/`)
|
|
@@ -446,11 +446,14 @@ The system does not natively integrate with: alternative payment processors beyo
|
|
|
446
446
|
|
|
447
447
|
### 1.4.5 Database Migrations
|
|
448
448
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
- `libs/db/src/supabase/migrations/
|
|
452
|
-
- `libs/db/src/supabase/migrations/
|
|
453
|
-
-
|
|
449
|
+
One squash generation at a time (`GGNNN_name.sql`; see §6.2.3.1 and docs/04):
|
|
450
|
+
|
|
451
|
+
- `libs/db/src/supabase/migrations/02000_catchup_gen1.sql` — Version-aware replay of the retired generation-1 forward migrations
|
|
452
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — Enums (`user_role`, `page_status`, `menu_location`, `revision_type`, …), functions, every table and sequence
|
|
453
|
+
- `libs/db/src/supabase/migrations/02002_baseline_constraints_and_indexes.sql` — Constraints and indexes
|
|
454
|
+
- `libs/db/src/supabase/migrations/02003_baseline_security_and_grants.sql` — RLS, policies, triggers, grants
|
|
455
|
+
- `libs/db/src/supabase/migrations/02004_baseline_seed.sql` — Default settings (footer copyright, payment providers, inventory, invoice settings), languages, translations, demo content
|
|
456
|
+
- `02005` onward — forward migrations appended since the generation-2 squash
|
|
454
457
|
|
|
455
458
|
### 1.4.6 Agent Skill Documents
|
|
456
459
|
|
|
@@ -623,7 +626,7 @@ Served locales are the active rows of the `languages` table, managed at `/cms/se
|
|
|
623
626
|
|
|
624
627
|
Locale propagation uses the `NEXT_USER_LOCALE` cookie and the `X-User-Locale` request header, both set by the request proxy. When `rememberVisitorChoice` is `true` (default) the cookie persists for one year (`maxAge: 31_536_000` seconds); when `false` it is a session cookie, so detection re-runs each new browser session (the client `LanguageProvider` mirrors the same expiry for manual switcher choices). A valid cookie always beats detection. The client-side provider chain `LanguageProvider → TranslationsProvider` in `apps/nextblock/app/providers.tsx` bridges server-resolved locale into React context.
|
|
625
628
|
|
|
626
|
-
**Business Value:** Unlocks multi-market deployments without requiring adopters to integrate a separate i18n library. **User Benefits:** Language switching persists across sessions; same content IDs preserve relationships across translations. **Technical Context:** Implemented at schema level (migration `
|
|
629
|
+
**Business Value:** Unlocks multi-market deployments without requiring adopters to integrate a separate i18n library. **User Benefits:** Language switching persists across sessions; same content IDs preserve relationships across translations. **Technical Context:** Implemented at schema level (migration `02001_baseline_schema.sql`), proxy level, and provider level.
|
|
627
630
|
|
|
628
631
|
**Dependencies**
|
|
629
632
|
|
|
@@ -648,7 +651,7 @@ Locale propagation uses the `NEXT_USER_LOCALE` cookie and the `X-User-Locale` re
|
|
|
648
651
|
|
|
649
652
|
**Description**
|
|
650
653
|
|
|
651
|
-
Revisions are implemented in the `page_revisions` and `post_revisions` tables defined in migration `
|
|
654
|
+
Revisions are implemented in the `page_revisions` and `post_revisions` tables defined in migration `02001_baseline_schema.sql`, using a hybrid snapshot/diff model. The `revision_type` enum (`snapshot`, `diff`) distinguishes between full snapshots and JSON Patch diffs (generated via `fast-json-patch`). A UNIQUE constraint on `(page_id, version)` ensures monotonically increasing snapshot versions. The CMS surface resides under `apps/nextblock/app/cms/revisions/`.
|
|
652
655
|
|
|
653
656
|
**Business Value:** Provides audit trail and rollback capability for authored content. **User Benefits:** Authors can restore prior states; accidental deletions are recoverable. **Technical Context:** Diff generation reduces storage overhead for frequently-updated content.
|
|
654
657
|
|
|
@@ -675,7 +678,7 @@ Revisions are implemented in the `page_revisions` and `post_revisions` tables de
|
|
|
675
678
|
|
|
676
679
|
**Description**
|
|
677
680
|
|
|
678
|
-
Three menu locations are supported: `HEADER`, `FOOTER`, and `SIDEBAR`, encoded by the `menu_location` enum. The `navigation_items` table (migration `
|
|
681
|
+
Three menu locations are supported: `HEADER`, `FOOTER`, and `SIDEBAR`, encoded by the `menu_location` enum. The `navigation_items` table (migration `02001_baseline_schema.sql`) supports hierarchical menus through a `parent_id` self-reference, explicit `order` for sibling sorting, translation group affiliation, and optional page references. Administrative CRUD operations reside at `apps/nextblock/app/cms/navigation/`.
|
|
679
682
|
|
|
680
683
|
**Dependencies**
|
|
681
684
|
|
|
@@ -729,7 +732,7 @@ Authentication is layered over Supabase Auth using `@supabase/ssr` and `@supabas
|
|
|
729
732
|
|
|
730
733
|
**Description**
|
|
731
734
|
|
|
732
|
-
RBAC is enforced through a three-valued `user_role` enum (`ADMIN`, `WRITER`, `USER`) defined in migration `
|
|
735
|
+
RBAC is enforced through a three-valued `user_role` enum (`ADMIN`, `WRITER`, `USER`) defined in migration `02001_baseline_schema.sql`. Route-level enforcement is implemented in `apps/nextblock/proxy.ts` (lines 12–17): `/cms` requires `WRITER` or `ADMIN`; `/cms/admin`, `/cms/users`, and `/cms/settings` require `ADMIN` exclusively. A foundational authorization rule encoded in the `on_auth_user_created` trigger elevates the first registered user to `ADMIN` and assigns all subsequent users the `USER` role, guaranteeing each deployment has exactly one guaranteed administrator at bootstrap. Users without a `full_name` value are redirected to `/profile` before being permitted to access other authenticated surfaces. Database-layer enforcement is provided via Row-Level Security with helper functions `get_current_user_role()` and `is_admin()` (both `SECURITY DEFINER`).
|
|
733
736
|
|
|
734
737
|
**Dependencies**
|
|
735
738
|
|
|
@@ -833,7 +836,7 @@ All features in this section are gated by F-022 (Package Activation) via `verify
|
|
|
833
836
|
|
|
834
837
|
**Description**
|
|
835
838
|
|
|
836
|
-
Products are modeled in migration `
|
|
839
|
+
Products are modeled in migration `02001_baseline_schema.sql` with fields including `sku`, `slug`, `title`, `type` (`physical` | `digital`), `payment_provider` (`stripe` | `freemius`), `price` as an integer in the smallest currency unit, a multi-currency `prices` JSONB column, `stock`, `status` (`draft` | `active` | `archived`), descriptions, Freemius-specific fields, UPC, and an `is_taxable` flag. A CHECK constraint named `products_type_provider_consistency_check` enforces that `physical` products use `stripe` and `digital` products use `freemius`. Related tables `product_media`, `product_attributes`, `product_attribute_terms`, `product_variants`, and `variant_attribute_mapping` model assets and variations. CMS surfaces at `apps/nextblock/app/cms/products/` provide list, create, edit, media, attribute, and variation management flows.
|
|
837
840
|
|
|
838
841
|
**Dependencies**
|
|
839
842
|
|
|
@@ -858,7 +861,7 @@ Products are modeled in migration `00000000000003_setup_catalog_and_licensing.sq
|
|
|
858
861
|
|
|
859
862
|
**Description**
|
|
860
863
|
|
|
861
|
-
The `inventory_items` table (migration `
|
|
864
|
+
The `inventory_items` table (migration `02001_baseline_schema.sql`) uses SKU as key and enforces `quantity >= 0` via CHECK constraint. Tracking is globally controlled by the `trackQuantities` setting in `ecommerce_inventory_settings`. Inventory deduction during order finalization follows a resilient pattern: the runtime first calls the `apply_order_inventory_deduction()` Postgres RPC, and if that path is unavailable, falls back to direct SQL via the `POSTGRES_URL` or `DATABASE_URL` connection, as coordinated by `libs/ecommerce/src/lib/shared-inventory.ts` and `libs/ecommerce/src/lib/order-inventory.ts`.
|
|
862
865
|
|
|
863
866
|
**Dependencies**
|
|
864
867
|
|
|
@@ -958,7 +961,7 @@ Freemius integration lives in `libs/ecommerce/src/lib/providers/` and supports d
|
|
|
958
961
|
|
|
959
962
|
**Description**
|
|
960
963
|
|
|
961
|
-
The `currencies` table (migration `
|
|
964
|
+
The `currencies` table (migration `02001_baseline_schema.sql`) stores `exchange_rate` as a `numeric(20,10)`, a single-row `is_default` constraint, `rounding_mode` (`none`, `nearest`, `up`, `down`, `charm`), `rounding_increment`, `rounding_charm_amount`, and flags `auto_update_exchange_rate` and `auto_sync_product_prices`. The default currency must satisfy `exchange_rate = 1`, `auto_update_exchange_rate = false`, and `auto_sync_product_prices = false`. FX rates are pulled from `https://api.frankfurter.dev` (overridable via `FX_API_BASE_URL`). Operations `syncStoreCurrencyRates()` and `rebaseStoreCurrencyExchangeRates()` are exposed by `libs/ecommerce/src/lib/currency-sync.ts`. A daily cron invokes `/api/cron/sync-currencies` at 18:00 UTC (`vercel.json`). Seed migration `02001_baseline_schema.sql` provides USD as the default.
|
|
962
965
|
|
|
963
966
|
**Dependencies**
|
|
964
967
|
|
|
@@ -1008,7 +1011,7 @@ Three shipping tables model geographic and rate configurations: `shipping_zones`
|
|
|
1008
1011
|
|
|
1009
1012
|
**Description**
|
|
1010
1013
|
|
|
1011
|
-
The `tax_rates` table (migration `
|
|
1014
|
+
The `tax_rates` table (migration `02001_baseline_schema.sql`) supports two modes: `manual` (keyed on country and state, supporting stacked rates such as GST + PST) and `automatic` (delegated to Stripe Tax via tax codes on line items). Mode selection is controlled by the `enableTaxes` and `taxCalculationMode` properties in `ecommerce_inventory_settings`. Schema constraints require `tax_rate` between 0 and 100 and enforce a uniqueness constraint on `(country_code, state_code, lower(tax_name))`. Implementation lives in `libs/ecommerce/src/lib/tax-calculation.ts` and `libs/ecommerce/src/lib/order-tax-details.ts`.
|
|
1012
1015
|
|
|
1013
1016
|
**Dependencies**
|
|
1014
1017
|
|
|
@@ -1033,7 +1036,7 @@ The `tax_rates` table (migration `00000000000004_setup_fulfillment_shipping_taxe
|
|
|
1033
1036
|
|
|
1034
1037
|
**Description**
|
|
1035
1038
|
|
|
1036
|
-
Orders transition through five statuses — `pending`, `paid`, `shipped`, `cancelled`, `refunded` — and store totals (`total`, `subtotal`, `shipping_total`, `tax_total`), a JSONB `tax_details` breakdown, `exchange_rate_at_purchase` as `numeric(20,10)`, `invoice_number`, `paid_at`, and `inventory_deducted_at`. Stable invoice numbering is produced by the `order_invoice_number_seq` sequence. The `invoice_settings` site-setting (seeded by `
|
|
1039
|
+
Orders transition through five statuses — `pending`, `paid`, `shipped`, `cancelled`, `refunded` — and store totals (`total`, `subtotal`, `shipping_total`, `tax_total`), a JSONB `tax_details` breakdown, `exchange_rate_at_purchase` as `numeric(20,10)`, `invoice_number`, `paid_at`, and `inventory_deducted_at`. Stable invoice numbering is produced by the `order_invoice_number_seq` sequence. The `invoice_settings` site-setting (seeded by `02001_baseline_schema.sql`) stores business name, email, address, and tax registrations. UI components `InvoiceDocument` and `InvoiceViewerShell` in `libs/ecommerce/src/lib/` render invoices. Customer order history is surfaced via `libs/ecommerce/src/lib/customer-orders.ts`, with admin management at `apps/nextblock/app/cms/orders/` and customer self-service at `apps/nextblock/app/profile/orders/`.
|
|
1037
1040
|
|
|
1038
1041
|
**Dependencies**
|
|
1039
1042
|
|
|
@@ -1058,7 +1061,7 @@ Orders transition through five statuses — `pending`, `paid`, `shipped`, `cance
|
|
|
1058
1061
|
|
|
1059
1062
|
**Description**
|
|
1060
1063
|
|
|
1061
|
-
The `package_activations` table (migration `
|
|
1064
|
+
The `package_activations` table (migration `02001_baseline_schema.sql`) contains `license_key`, `instance_name`, `package_id`, `status` (defaulting to `active`), `meta`, `last_validated_at`, and a UNIQUE constraint on `(license_key, package_id)`. The helper `verifyPackageOnline(packageId, customClient?)` in `libs/db/src/lib/package-validation.ts` returns a boolean based on `status === 'active'` and uses `unstable_cache` with a 60-second revalidation window. This function is invoked from four surfaces: the CMS commerce navigation visibility check, the checkout API gate at `apps/nextblock/app/api/checkout/route.ts` line 36, premium route wrappers injected during scaffold activation, and the CLI's module activation flows.
|
|
1062
1065
|
|
|
1063
1066
|
**Dependencies**
|
|
1064
1067
|
|
|
@@ -1160,7 +1163,7 @@ The SDK library at `libs/sdk` provides a typed contract for external block autho
|
|
|
1160
1163
|
|
|
1161
1164
|
**Description**
|
|
1162
1165
|
|
|
1163
|
-
Two cron jobs are declared in `vercel.json`. The `/api/cron/reset-sandbox` endpoint runs
|
|
1166
|
+
Two cron jobs are declared in `vercel.json`. The `/api/cron/reset-sandbox` endpoint runs every 15 minutes (`*/15 * * * *`); it clears R2 storage, executes the generated SQL bootstrap (`SANDBOX_RESET_SQL`), normalizes media records, ensures required assets, seeds commerce and content data, and synchronizes Freemius products (product ID `24851`). The `/api/cron/sync-currencies` endpoint runs daily at 18:00 UTC (`0 18 * * *`) and invokes `syncStoreCurrencyRates()` from `@nextblock-cms/ecommerce/server`. Both endpoints require an `Authorization: Bearer ${CRON_SECRET}` header.
|
|
1164
1167
|
|
|
1165
1168
|
**Dependencies**
|
|
1166
1169
|
|
|
@@ -1185,13 +1188,13 @@ Two cron jobs are declared in `vercel.json`. The `/api/cron/reset-sandbox` endpo
|
|
|
1185
1188
|
|
|
1186
1189
|
**Description**
|
|
1187
1190
|
|
|
1188
|
-
Sandbox mode is toggled via the `NEXT_PUBLIC_IS_SANDBOX` environment variable. When enabled, the application renders the `SandboxBanner` and `SandboxCredentialsAlert` components (with demo credentials `demo@nextblock.dev`/`password`), and relaxes Freemius webhook signature verification to tolerate signature mismatches. A live deployment at `https://cms.nextblock.dev/` demonstrates the feature and resets
|
|
1191
|
+
Sandbox mode is toggled via the `NEXT_PUBLIC_IS_SANDBOX` environment variable. When enabled, the application renders the `SandboxBanner` and `SandboxCredentialsAlert` components (with demo credentials `demo@nextblock.dev`/`password`), and relaxes Freemius webhook signature verification to tolerate signature mismatches. A live deployment at `https://cms.nextblock.dev/` demonstrates the feature and resets every 15 minutes via F-025.
|
|
1189
1192
|
|
|
1190
1193
|
**Dependencies**
|
|
1191
1194
|
|
|
1192
1195
|
| Dependency Type | Details |
|
|
1193
1196
|
|:--|:--|
|
|
1194
|
-
| Prerequisite Features | F-025 (for
|
|
1197
|
+
| Prerequisite Features | F-025 (for the 15-minute reset) |
|
|
1195
1198
|
| System Dependencies | None |
|
|
1196
1199
|
| External Dependencies | None |
|
|
1197
1200
|
| Integration Requirements | `NEXT_PUBLIC_IS_SANDBOX` flag |
|
|
@@ -1422,7 +1425,7 @@ This subsection provides the detailed, testable requirements that operationalize
|
|
|
1422
1425
|
| F-023-RQ-002 | `activate ecommerce` MUST install the alias `@nextblock-cms/ecommerce@npm:@nextblock-cms/ecom@latest` and inject route wrappers with `verifyPackageOnline()` | Must-Have | High |
|
|
1423
1426
|
| F-024-RQ-001 | SDK MUST expose `BlockContentSchema`, `BlockData`, `BlockProps`, `BlockEditorProps`, `BlockConfig`, `LucideIcon` | Must-Have | Low |
|
|
1424
1427
|
| F-024-RQ-002 | External block authoring MUST follow the contract shape documented in `docs/07-BLOCK-SDK-AND-EXTENSIBILITY.md` | Must-Have | Medium |
|
|
1425
|
-
| F-025-RQ-001 | `/api/cron/reset-sandbox` MUST run
|
|
1428
|
+
| F-025-RQ-001 | `/api/cron/reset-sandbox` MUST run every 15 minutes with `Bearer CRON_SECRET` authorization | Must-Have | Medium |
|
|
1426
1429
|
| F-025-RQ-002 | `/api/cron/sync-currencies` MUST run daily at 18:00 UTC with `Bearer CRON_SECRET` authorization | Must-Have | Low |
|
|
1427
1430
|
| F-026-RQ-001 | Sandbox banner and credential alert MUST render when `NEXT_PUBLIC_IS_SANDBOX === 'true'` | Should-Have | Low |
|
|
1428
1431
|
| F-027-RQ-001 | `/api/revalidate` MUST validate `REVALIDATE_SECRET_TOKEN` before calling `revalidatePath` | Must-Have | Medium |
|
|
@@ -1679,7 +1682,7 @@ The following matrix links features to the sections of the technical specificati
|
|
|
1679
1682
|
| Package alignment | `@nextblock-cms/ecom` package name vs. `@nextblock-cms/ecommerce` alias (per §1.3.3.1) requires coordination when republished | F-013–F-022 |
|
|
1680
1683
|
| Locale expansion | Locales are DB-driven: add an active `languages` row (plus translations/content); `FALLBACK_LOCALES` in `proxy.ts` is only a DB-unreachable safety net | F-007 |
|
|
1681
1684
|
| Block registry updates | New block types must satisfy F-024 contract and register in `blockRegistry.ts` | F-004, F-024 |
|
|
1682
|
-
| RLS policy review | Migration `
|
|
1685
|
+
| RLS policy review | Migration `02001_baseline_schema.sql` should be audited on new table introduction | All DB-backed features |
|
|
1683
1686
|
|
|
1684
1687
|
### 2.4.6 Assumptions and Constraints Summary
|
|
1685
1688
|
|
|
@@ -1700,7 +1703,7 @@ The following matrix links features to the sections of the technical specificati
|
|
|
1700
1703
|
- `README.md` — Product value proposition, competitive positioning, Lighthouse and CLI claims
|
|
1701
1704
|
- `package.json` — Workspace dependency versions (Next.js, React, TypeScript, Nx, Tailwind, Tiptap)
|
|
1702
1705
|
- `nx.json` — Nx plugin and release configuration
|
|
1703
|
-
- `vercel.json` — Cron schedule definitions (reset-sandbox
|
|
1706
|
+
- `vercel.json` — Cron schedule definitions (reset-sandbox every 15 minutes; sync-currencies 18:00 UTC)
|
|
1704
1707
|
- `.env.example` — Environment variable reference template
|
|
1705
1708
|
- `eslint.config.mjs` — `@nx/enforce-module-boundaries` scope-tag rules (F-028)
|
|
1706
1709
|
- `apps/nextblock/next.config.js` — Image format/device-size config; CSP; `transpilePackages`
|
|
@@ -1726,14 +1729,14 @@ The following matrix links features to the sections of the technical specificati
|
|
|
1726
1729
|
- `apps/create-nextblock/bin/create-nextblock.js` — CLI `create` and `activate` commands (F-023)
|
|
1727
1730
|
- `libs/db/src/lib/package-validation.ts` — `verifyPackageOnline()` with 60 s cache (F-022)
|
|
1728
1731
|
- `libs/db/src/lib/media-actions.ts` — Role-gated media recording (F-006)
|
|
1729
|
-
- `libs/db/src/supabase/migrations/
|
|
1730
|
-
- `libs/db/src/supabase/migrations/
|
|
1731
|
-
- `libs/db/src/supabase/migrations/
|
|
1732
|
-
- `libs/db/src/supabase/migrations/
|
|
1733
|
-
- `libs/db/src/supabase/migrations/
|
|
1734
|
-
- `libs/db/src/supabase/migrations/
|
|
1735
|
-
- `libs/db/src/supabase/migrations/
|
|
1736
|
-
- `libs/db/src/supabase/migrations/
|
|
1732
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `user_role`, `page_status`, `menu_location`, `revision_type` enums
|
|
1733
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — languages, translations, media, profiles (F-002, F-006, F-007)
|
|
1734
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — pages, posts, blocks, navigation, revisions (F-004, F-008, F-009)
|
|
1735
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — products, variants, attributes, inventory, package_activations (F-013, F-014, F-022)
|
|
1736
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — orders, shipping zones, tax rates, currencies (F-018–F-021)
|
|
1737
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `handle_new_user()`, `on_auth_user_created` (F-002, F-003)
|
|
1738
|
+
- `libs/db/src/supabase/migrations/02003_baseline_security_and_grants.sql` — RLS policies and helper functions
|
|
1739
|
+
- `libs/db/src/supabase/migrations/02004_baseline_seed.sql` — Default settings, USD currency, `en`/`fr` languages
|
|
1737
1740
|
- `libs/db/src/supabase/templates/` — Six Supabase Auth email templates (F-002)
|
|
1738
1741
|
- `libs/editor/README.md` — Public editor surface exports (F-005)
|
|
1739
1742
|
- `libs/editor/ADVANCED_FEATURES.md` — Enhanced floating menu, placeholder behaviors (F-005)
|
|
@@ -2203,7 +2206,7 @@ The `vercel.json` file declares two scheduled jobs:
|
|
|
2203
2206
|
|
|
2204
2207
|
| Path | Schedule (UTC) | Purpose |
|
|
2205
2208
|
|:--|:--|:--|
|
|
2206
|
-
| `/api/cron/reset-sandbox` |
|
|
2209
|
+
| `/api/cron/reset-sandbox` | `*/15 * * * *` (every 15 minutes) | Resets sandbox R2 + data for the demo deployment (F-025, F-026) |
|
|
2207
2210
|
| `/api/cron/sync-currencies` | `0 18 * * *` (18:00 daily) | FX rate synchronization (F-018, F-025) |
|
|
2208
2211
|
|
|
2209
2212
|
Both endpoints enforce `Authorization: Bearer ${CRON_SECRET}` per the security mitigation in Section 2.4.4.
|
|
@@ -2222,14 +2225,14 @@ Supabase PostgreSQL is the authoritative data store for all structured data in t
|
|
|
2222
2225
|
|
|
2223
2226
|
| Migration File | Purpose |
|
|
2224
2227
|
|:--|:--|
|
|
2225
|
-
| `
|
|
2226
|
-
| `
|
|
2227
|
-
| `
|
|
2228
|
-
| `
|
|
2229
|
-
| `
|
|
2228
|
+
| `02001_baseline_schema.sql` | Enums: `user_role`, `page_status`, `menu_location`, `revision_type` |
|
|
2229
|
+
| `02001_baseline_schema.sql` | `languages`, `translations`, `media`, `profiles`, `settings`, `logos` |
|
|
2230
|
+
| `02001_baseline_schema.sql` | `pages`, `posts`, `blocks`, `navigation_items`, `page_revisions`, `post_revisions` |
|
|
2231
|
+
| `02001_baseline_schema.sql` | `products`, `product_variants`, `inventory_items`, `package_activations` |
|
|
2232
|
+
| `02001_baseline_schema.sql` | `currencies`, `tax_rates`, shipping tables |
|
|
2230
2233
|
| `00000000000005` through `00000000000007` | Commerce extensions |
|
|
2231
|
-
| `
|
|
2232
|
-
| `
|
|
2234
|
+
| `02001_baseline_schema.sql` | Row-Level Security policies |
|
|
2235
|
+
| `02001_baseline_schema.sql` | Default settings, USD currency, English language |
|
|
2233
2236
|
| `00000000000009` — `00000000000010` | Additional platform seeds |
|
|
2234
2237
|
| `00000000000011` through `00000000000016` | Cortex AI settings, coupons, audit, drafts, and page feature images |
|
|
2235
2238
|
| `00000000000017` through `00000000000024` | Product blocks, bot-protection settings, product categories + translations, hero→section migration, Cortex AI guide seed, custom block definitions, and cart sessions |
|
|
@@ -2521,7 +2524,7 @@ The premium `libs/ecommerce` is guarded at runtime by the `verifyPackageOnline('
|
|
|
2521
2524
|
- `package.json` — Root workspace package metadata, all dependency versions, and npm scripts
|
|
2522
2525
|
- `nx.json` — Nx workspace configuration, registered plugins, generators, and targets
|
|
2523
2526
|
- `tsconfig.base.json` — Shared TypeScript strict-mode configuration and monorepo path aliases
|
|
2524
|
-
- `vercel.json` — Cron schedules for `reset-sandbox` (
|
|
2527
|
+
- `vercel.json` — Cron schedules for `reset-sandbox` (every 15 minutes) and `sync-currencies` (18:00 UTC)
|
|
2525
2528
|
- `tailwind.config.js` — Root Tailwind CSS theme tokens, dark-mode configuration, content globs
|
|
2526
2529
|
- `postcss.config.js` — PostCSS pipeline with `@tailwindcss/postcss` and `autoprefixer`
|
|
2527
2530
|
- `eslint.config.mjs` — Flat ESLint configuration with `@nx/enforce-module-boundaries` rules
|
|
@@ -3432,7 +3435,7 @@ flowchart LR
|
|
|
3432
3435
|
|
|
3433
3436
|
### 4.5.1 Sandbox Reset Cron
|
|
3434
3437
|
|
|
3435
|
-
The sandbox reset cron at `/api/cron/reset-sandbox/` executes
|
|
3438
|
+
The sandbox reset cron at `/api/cron/reset-sandbox/` executes every 15 minutes and performs a comprehensive environment rebuild: R2 storage deletion and re-seeding, database bootstrap via generated `SANDBOX_RESET_SQL`, and seeding of commerce products, localized content, and navigation entries. The endpoint requires `NEXT_PUBLIC_IS_SANDBOX === 'true'` and rejects execution in production environments.
|
|
3436
3439
|
|
|
3437
3440
|
```mermaid
|
|
3438
3441
|
flowchart TB
|
|
@@ -3923,7 +3926,7 @@ The following table consolidates all documented timing constraints and SLAs acro
|
|
|
3923
3926
|
| Sync-Currencies maxDuration | 30 seconds | `api/cron/sync-currencies` |
|
|
3924
3927
|
| Reset-Sandbox maxDuration | 60 seconds | `api/cron/reset-sandbox` |
|
|
3925
3928
|
| Currency Sync Schedule | 18:00 UTC daily (`0 18 * * *`) | `vercel.json` |
|
|
3926
|
-
| Sandbox Reset Schedule |
|
|
3929
|
+
| Sandbox Reset Schedule | every 15 minutes (`*/15 * * * *`) | `vercel.json` |
|
|
3927
3930
|
| Max Source Image Width | 2560 pixels | `api/process-image` |
|
|
3928
3931
|
| Image Derivative Widths | 1920, 1280, 768, 384, 128 | `api/process-image` |
|
|
3929
3932
|
| Lighthouse Performance Target | 100/100 | `README.md` |
|
|
@@ -3953,9 +3956,9 @@ flowchart LR
|
|
|
3953
3956
|
HstsHeader[HSTS Header<br/>2 years max-age]
|
|
3954
3957
|
end
|
|
3955
3958
|
|
|
3956
|
-
subgraph Scheduled[" Scheduled
|
|
3959
|
+
subgraph Scheduled[" Scheduled (Vercel Cron) "]
|
|
3957
3960
|
CurrencyDay[18:00 UTC<br/>Sync Currencies]
|
|
3958
|
-
ResetDay[
|
|
3961
|
+
ResetDay[Every 15 min<br/>Sandbox Reset]
|
|
3959
3962
|
end
|
|
3960
3963
|
```
|
|
3961
3964
|
|
|
@@ -4002,14 +4005,14 @@ flowchart LR
|
|
|
4002
4005
|
|
|
4003
4006
|
#### Database Migrations Referenced
|
|
4004
4007
|
|
|
4005
|
-
- `
|
|
4006
|
-
- `
|
|
4007
|
-
- `
|
|
4008
|
-
- `
|
|
4009
|
-
- `
|
|
4010
|
-
- `
|
|
4011
|
-
- `
|
|
4012
|
-
- `
|
|
4008
|
+
- `02001_baseline_schema.sql` - `user_role` enum
|
|
4009
|
+
- `02001_baseline_schema.sql` - Translations schema
|
|
4010
|
+
- `02001_baseline_schema.sql` - Pages, posts, revisions, navigation
|
|
4011
|
+
- `02001_baseline_schema.sql` - Products, inventory, package_activations
|
|
4012
|
+
- `02001_baseline_schema.sql` - Orders, tax, shipping, currencies
|
|
4013
|
+
- `02003_baseline_security_and_grants.sql` - `on_auth_user_created` trigger (first-user ADMIN rule), RLS policies
|
|
4014
|
+
- `02001_baseline_schema.sql` - helper functions
|
|
4015
|
+
- `02001_baseline_schema.sql` - Default currency, languages, invoice settings
|
|
4013
4016
|
|
|
4014
4017
|
#### Folders Explored
|
|
4015
4018
|
|
|
@@ -4194,7 +4197,7 @@ The integration landscape comprises eight external domains declared in `libs/env
|
|
|
4194
4197
|
| Freemius | HTTPS + `x-freemius-signature` (HMAC SHA-256) | Sandbox bypass when `NEXT_PUBLIC_IS_SANDBOX===true` |
|
|
4195
4198
|
| Frankfurter FX | HTTPS (JSON) | Cron runs 18:00 UTC daily; `maxDuration: 30s` |
|
|
4196
4199
|
| SMTP | SMTP + TLS | Best-effort from server actions |
|
|
4197
|
-
| Vercel Cron | HTTPS + Bearer `CRON_SECRET` |
|
|
4200
|
+
| Vercel Cron | HTTPS + Bearer `CRON_SECRET` | every 15 min (reset-sandbox, 60s); 18:00 UTC (sync-currencies, 30s) |
|
|
4198
4201
|
| Google Tag Manager | HTTPS (JS) | GTM id from `privacy_settings` (site_settings); allowlisted in CSP |
|
|
4199
4202
|
|
|
4200
4203
|
## 5.2 COMPONENT DETAILS
|
|
@@ -4638,7 +4641,7 @@ Observability instrumentation includes @vercel/speed-insights for performance me
|
|
|
4638
4641
|
| Prefetch Accuracy | Correct `X-Prefetch-Priority` per page-type | `proxy.ts` |
|
|
4639
4642
|
| Media Optimization | Blur placeholders on uploads | sharp + plaiceholder pipeline |
|
|
4640
4643
|
| Commerce Conversion | Checkout success by provider | `app/api/checkout/route.ts` + webhooks |
|
|
4641
|
-
| Scheduled Job Health |
|
|
4644
|
+
| Scheduled Job Health | Success of sandbox reset (every 15 min) + currency sync (daily) | `vercel.json` cron configuration |
|
|
4642
4645
|
| Bundle Discipline | Removed console calls in production | `compiler.removeConsole` in `next.config.js` |
|
|
4643
4646
|
|
|
4644
4647
|
### 5.4.2 Logging and Tracing Strategy
|
|
@@ -4761,7 +4764,7 @@ Measurable performance objectives include 100/100 Lighthouse performance, a CLI
|
|
|
4761
4764
|
|
|
4762
4765
|
#### 5.4.6.1 Sandbox Reset
|
|
4763
4766
|
|
|
4764
|
-
The `/api/cron/reset-sandbox` endpoint, scheduled
|
|
4767
|
+
The `/api/cron/reset-sandbox` endpoint, scheduled every 15 minutes, reconstructs the demo environment end-to-end: it clears and repopulates Cloudflare R2 media, runs a generated SQL bootstrap (`sandboxResetSql.ts`) against Supabase, normalizes legacy media records, ensures required media assets exist, and seeds commerce/content data. The endpoint only executes when in sandbox mode and after verifying the Bearer `CRON_SECRET`.
|
|
4765
4768
|
|
|
4766
4769
|
#### 5.4.6.2 Currency Synchronization
|
|
4767
4770
|
|
|
@@ -4779,8 +4782,8 @@ Supabase provides point-in-time recovery at the platform level; the eleven canon
|
|
|
4779
4782
|
|
|
4780
4783
|
```mermaid
|
|
4781
4784
|
flowchart LR
|
|
4782
|
-
subgraph Scheduled["
|
|
4783
|
-
Reset[
|
|
4785
|
+
subgraph Scheduled["Schedules (Vercel Cron)"]
|
|
4786
|
+
Reset[Every 15 min<br/>/api/cron/reset-sandbox<br/>maxDuration 60s]
|
|
4784
4787
|
Sync[18:00 UTC<br/>/api/cron/sync-currencies<br/>maxDuration 30s]
|
|
4785
4788
|
end
|
|
4786
4789
|
|
|
@@ -5443,7 +5446,7 @@ Two scheduled recovery flows are declared in `vercel.json` and serve both routin
|
|
|
5443
5446
|
```mermaid
|
|
5444
5447
|
flowchart LR
|
|
5445
5448
|
subgraph Schedules["vercel.json crons[]"]
|
|
5446
|
-
Reset03[
|
|
5449
|
+
Reset03[Every 15 min<br/>/api/cron/reset-sandbox<br/>maxDuration 60s]
|
|
5447
5450
|
Sync18[18:00 UTC daily<br/>/api/cron/sync-currencies<br/>maxDuration 30s]
|
|
5448
5451
|
end
|
|
5449
5452
|
|
|
@@ -5480,7 +5483,7 @@ flowchart LR
|
|
|
5480
5483
|
C4 --> C5
|
|
5481
5484
|
```
|
|
5482
5485
|
|
|
5483
|
-
The sandbox reset (`apps/nextblock/app/api/cron/reset-sandbox/route.ts`) only executes when in sandbox mode, providing a self-healing loop for the public demo environment. It serves as a **
|
|
5486
|
+
The sandbox reset (`apps/nextblock/app/api/cron/reset-sandbox/route.ts`) only executes when in sandbox mode, providing a self-healing loop for the public demo environment. It serves as a **continuous reconstruction rehearsal** that validates the schema migrations and seed scripts.
|
|
5484
5487
|
|
|
5485
5488
|
#### 6.1.6.3 Content Recovery via Revisions
|
|
5486
5489
|
|
|
@@ -5533,7 +5536,7 @@ Failover behavior is **implicit via Vercel's platform** and **explicit via dual-
|
|
|
5533
5536
|
- The workspace uses **library decomposition** (eight components in an Nx monorepo) with boundaries enforced at compile time by ESLint `@nx/enforce-module-boundaries`.
|
|
5534
5537
|
- **Scalability is platform-delegated**: Vercel provides automatic horizontal scaling of stateless serverless functions. Application-level tuning is confined to cache TTLs, `maxDuration`, and caching layers.
|
|
5535
5538
|
- **Resilience is expressed at the integration surface** via a five-pattern classification (strict failure, dual-path, and graceful degrade), exemplified by the RPC + SQL fallback inventory deduction.
|
|
5536
|
-
- **Disaster recovery** rests on Supabase platform PITR, 11 canonical migrations, `page_revisions`/`post_revisions` hybrid snapshot/diff content history, and a
|
|
5539
|
+
- **Disaster recovery** rests on Supabase platform PITR, 11 canonical migrations, `page_revisions`/`post_revisions` hybrid snapshot/diff content history, and a 15-minute sandbox-reset cron that doubles as a reconstruction rehearsal.
|
|
5537
5540
|
|
|
5538
5541
|
#### 6.1.7.2 Cross-References
|
|
5539
5542
|
|
|
@@ -5565,7 +5568,7 @@ Failover behavior is **implicit via Vercel's platform** and **explicit via dual-
|
|
|
5565
5568
|
- `apps/nextblock/app/api/checkout/route.ts` — Checkout orchestration with `resolveProviderFromItem` chain and license-gate integration
|
|
5566
5569
|
- `apps/nextblock/app/api/webhooks/stripe/route.ts` — Stripe signature verification + event dispatch
|
|
5567
5570
|
- `apps/nextblock/app/api/webhooks/freemius/route.ts` — Freemius HMAC-SHA-256 verification + sandbox bypass
|
|
5568
|
-
- `apps/nextblock/app/api/cron/reset-sandbox/route.ts` —
|
|
5571
|
+
- `apps/nextblock/app/api/cron/reset-sandbox/route.ts` — 15-minute sandbox reset flow; R2 clearing, SQL bootstrap, media normalization, seeding
|
|
5569
5572
|
- `apps/nextblock/app/api/cron/sync-currencies/route.ts` — Daily Frankfurter FX sync; Bearer `CRON_SECRET` auth
|
|
5570
5573
|
- `apps/nextblock/app/api/revalidate/route.ts` — On-demand ISR invalidation from Supabase webhooks
|
|
5571
5574
|
- `apps/nextblock/app/api/upload/presigned-url/route.ts` — R2 presigned URL generation (300s TTL, 10 MB cap)
|
|
@@ -5580,7 +5583,7 @@ Failover behavior is **implicit via Vercel's platform** and **explicit via dual-
|
|
|
5580
5583
|
- `libs/db/src/lib/supabase/middleware.ts` — Supabase session synchronization helper
|
|
5581
5584
|
- `libs/db/project.json` — Nx project definition with `scope:public` tag
|
|
5582
5585
|
- `libs/environment.d.ts` — NodeJS.ProcessEnv augmentation declaring all external-service env vars
|
|
5583
|
-
- `vercel.json` — Two cron schedule declarations (
|
|
5586
|
+
- `vercel.json` — Two cron schedule declarations (every-15-minutes reset-sandbox; 18:00 UTC sync-currencies)
|
|
5584
5587
|
- `nx.json` — Nx workspace orchestration and target defaults
|
|
5585
5588
|
- `eslint.config.mjs` — `@nx/enforce-module-boundaries` rules for scope:public/scope:premium
|
|
5586
5589
|
- `tsconfig.base.json` — Path aliases for all `@nextblock-cms/*` packages
|
|
@@ -5643,7 +5646,7 @@ The design leans on the Supabase managed platform for replication, connection po
|
|
|
5643
5646
|
|
|
5644
5647
|
#### 6.2.2.1 Enumerated Types
|
|
5645
5648
|
|
|
5646
|
-
All domain-specific enumerations are declared in migration `
|
|
5649
|
+
All domain-specific enumerations are declared in migration `02001_baseline_schema.sql` using idempotent `DO $$` guards so re-application is safe. The migration also grants `USAGE` on the `public` schema to the Supabase-managed roles `postgres`, `anon`, `authenticated`, and `service_role`.
|
|
5647
5650
|
|
|
5648
5651
|
| Enum | Values | Usage |
|
|
5649
5652
|
|------|--------|-------|
|
|
@@ -5654,7 +5657,7 @@ All domain-specific enumerations are declared in migration `00000000000000_setup
|
|
|
5654
5657
|
|
|
5655
5658
|
#### 6.2.2.2 Identity and Core CMS Entities
|
|
5656
5659
|
|
|
5657
|
-
Declared in migration `
|
|
5660
|
+
Declared in migration `02001_baseline_schema.sql`, these tables bootstrap the authentication mirror, languages, media registry, translations, logos, and the global key/value settings store.
|
|
5658
5661
|
|
|
5659
5662
|
| Table | Primary Key | Key Columns / Constraints |
|
|
5660
5663
|
|-------|-------------|----------------------------|
|
|
@@ -5673,7 +5676,7 @@ Declared in migration `00000000000001_setup_cms_core.sql`, these tables bootstra
|
|
|
5673
5676
|
|
|
5674
5677
|
#### 6.2.2.3 Authoring Content Entities
|
|
5675
5678
|
|
|
5676
|
-
Declared in migration `
|
|
5679
|
+
Declared in migration `02001_baseline_schema.sql`, these tables form the CMS authoring domain. The relationships are summarized in the ER diagram below.
|
|
5677
5680
|
|
|
5678
5681
|
```mermaid
|
|
5679
5682
|
erDiagram
|
|
@@ -5760,7 +5763,7 @@ erDiagram
|
|
|
5760
5763
|
|
|
5761
5764
|
#### 6.2.2.4 Commerce Entities
|
|
5762
5765
|
|
|
5763
|
-
Declared across
|
|
5766
|
+
Declared across migration `02001_baseline_schema.sql`, commerce spans catalog, licensing, orders, shipping, taxation, and currency infrastructure.
|
|
5764
5767
|
|
|
5765
5768
|
```mermaid
|
|
5766
5769
|
erDiagram
|
|
@@ -5896,7 +5899,7 @@ Both `products` and `product_variants` store prices in two redundant shapes —
|
|
|
5896
5899
|
|
|
5897
5900
|
#### 6.2.2.5 Indexing Strategy
|
|
5898
5901
|
|
|
5899
|
-
Migration `
|
|
5902
|
+
Migration `02001_baseline_schema.sql` adds 38 secondary indexes. The strategy groups into four categories:
|
|
5900
5903
|
|
|
5901
5904
|
| Category | Representative Indexes | Optimization Target |
|
|
5902
5905
|
|----------|------------------------|---------------------|
|
|
@@ -5957,7 +5960,7 @@ flowchart TB
|
|
|
5957
5960
|
| Manual restore | `psql` with duplicate-error collapser | `apps/nextblock/scripts/restore.js` |
|
|
5958
5961
|
| Schema reconstruction | Replay 11 migrations in order | `npm run db:reset` via `supabase db reset --workdir libs/db/src` |
|
|
5959
5962
|
| Content rollback | Hybrid snapshot/diff revisions | `page_revisions`, `post_revisions` (F-008) |
|
|
5960
|
-
| Sandbox rehearsal |
|
|
5963
|
+
| Sandbox rehearsal | Every 15 minutes, 60s maxDuration | `/api/cron/reset-sandbox` (§4.5) |
|
|
5961
5964
|
|
|
5962
5965
|
The `backup.js` script reads `POSTGRES_URL` or `DATABASE_URL` via `dotenv`, parses the connection URL, supports a `--name` CLI flag (or interactive prompt) for friendly backup names, creates timestamped directories under `apps/nextblock/backups/`, and spawns `pg_dump` with `PGPASSWORD` and `PGSSLMODE` passed via environment variables.
|
|
5963
5966
|
|
|
@@ -5967,29 +5970,17 @@ The `backup.js` script reads `POSTGRES_URL` or `DATABASE_URL` via `dotenv`, pars
|
|
|
5967
5970
|
|
|
5968
5971
|
#### 6.2.3.1 Migration Procedures
|
|
5969
5972
|
|
|
5970
|
-
Migrations live in `libs/db/src/supabase/migrations/` and are managed via the Supabase CLI
|
|
5973
|
+
Migrations live in `libs/db/src/supabase/migrations/` and are managed via the Supabase CLI plus the repo's own appliers (the `/setup` wizard, the build hook, `npm run update`, the Docker migration runner). The folder holds exactly one **squash generation**; files are named `GGNNN_name.sql` (GG = generation, NNN = contiguous sequence) and applied in lexical order. The current generation is 2 (built 2026-09-10); its first five slots are fixed and everything from `02005` upward is an ordinary forward migration.
|
|
5971
5974
|
|
|
5972
5975
|
| File | Purpose | Key Outputs |
|
|
5973
5976
|
|------|---------|-------------|
|
|
5974
|
-
| `
|
|
5975
|
-
| `
|
|
5976
|
-
| `
|
|
5977
|
-
| `
|
|
5978
|
-
| `
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
| `00000000000007_setup_indexes.sql` | Performance indexes | 38 indexes across all domains |
|
|
5982
|
-
| `00000000000008_seed_platform_defaults.sql` | Baseline platform state | English/French languages, USD as default currency, site_settings defaults |
|
|
5983
|
-
| `00000000000009_seed_translations.sql` | Internationalization content | Hundreds of en/es/fr i18n rows |
|
|
5984
|
-
| `00000000000010_seed_content_scaffold.sql` | Starter content | Default logos, home/articles pages, featured posts, navigation |
|
|
5985
|
-
| `00000000000011_setup_cortex_ai_settings.sql` | AI settings | Cortex AI configuration |
|
|
5986
|
-
| `00000000000012_setup_commerce_coupons.sql` | Commerce coupons | Coupon tables and constraints |
|
|
5987
|
-
| `00000000000013_setup_cortex_ai_db_mutation_audit.sql` | AI audit | Cortex AI database mutation audit support |
|
|
5988
|
-
| `00000000000014_setup_content_drafts.sql` | Content drafts | Visual-editing draft support |
|
|
5989
|
-
| `00000000000015_setup_product_drafts.sql` | Product drafts | Product draft workflow support |
|
|
5990
|
-
| `00000000000016_add_feature_image_to_pages.sql` | CMS page media | Optional page feature image relationship |
|
|
5991
|
-
|
|
5992
|
-
Per Section 2.4.5, the **numbered migration files in `libs/db/src/supabase/migrations/` must remain applied in order**; out-of-sequence application will violate referential integrity. For live/shared databases, new changes must be appended as new non-destructive migrations. Do not rewrite, recycle, squash, reorder, or delete migrations that may already be recorded in production.
|
|
5977
|
+
| `02000_catchup_gen1.sql` | Version-aware replay of the retired generation-1 forward migrations | Converges databases that sat behind generation 1; skipped on empty databases and on databases already at generation ≥ 2; sets `site_settings.migration_baseline_generation` |
|
|
5978
|
+
| `02001_baseline_schema.sql` | Schema | All enums, functions, tables, sequences and defaults (`IF NOT EXISTS` / `CREATE OR REPLACE`); the `auth.users` → `handle_new_user` trigger |
|
|
5979
|
+
| `02002_baseline_constraints_and_indexes.sql` | Integrity + performance | Primary/unique/check/foreign-key constraints (catalog-guarded) and every index |
|
|
5980
|
+
| `02003_baseline_security_and_grants.sql` | Security | RLS enablement on every table, all policies, business/timestamp triggers, grants |
|
|
5981
|
+
| `02004_baseline_seed.sql` | Seed | Canonical demo content (languages, currencies, site settings, translations, media, pages/posts/blocks, navigation, shipping defaults, themes) — runs only on an empty database |
|
|
5982
|
+
|
|
5983
|
+
Per Section 2.4.5, the **numbered migration files in `libs/db/src/supabase/migrations/` must remain applied in order**; out-of-sequence application will violate referential integrity. For live/shared databases, new changes must be appended as new non-destructive migrations. Do not rewrite, recycle, reorder, or delete migration files outside the documented squash runbook (`docs/04-DATABASE-AND-AUTH.md` → "Squashing migrations"); a squash always ships a catch-up so existing databases converge.
|
|
5993
5984
|
|
|
5994
5985
|
##### 6.2.3.1.1 Migration Command Surface
|
|
5995
5986
|
|
|
@@ -6000,7 +5991,7 @@ The root `package.json` exposes the following migration-related scripts:
|
|
|
6000
5991
|
| `db:migrate:check` | `node tools/scripts/push-db-migrations.js --check` | Dry-run pending remote migrations |
|
|
6001
5992
|
| `db:migrate` / `db:push` | `node tools/scripts/push-db-migrations.js --confirm` | Apply pending migration files only; no reset, sandbox seed, function deploy, or config push |
|
|
6002
5993
|
| `db:migrate:repair-history:check` | `node tools/scripts/repair-db-migration-history.js --check` | Preview baseline migration-history repair |
|
|
6003
|
-
| `db:migrate:repair-history` | `node tools/scripts/repair-db-migration-history.js --confirm` | Mark existing baseline migrations as applied without running their SQL |
|
|
5994
|
+
| `db:migrate:repair-history` | `node tools/scripts/repair-db-migration-history.js --confirm` | Mark existing baseline migrations as applied without running their SQL; with `-- --reconcile-squash`, record a migration squash (revert retired versions, mark the new generation applied) |
|
|
6004
5995
|
| `db:migrate:fresh` | `node tools/scripts/push-db-migrations.js --confirm --allow-baseline-replay` | Apply the full baseline only to a brand-new empty database |
|
|
6005
5996
|
| `db:reset` | `supabase db reset --workdir libs/db/src` | Full local reset and replay |
|
|
6006
5997
|
| `db:link` | `dotenv + supabase-link` via `tools/scripts/supabase-link.js` | Link local workspace to remote project |
|
|
@@ -6191,11 +6182,11 @@ All three paths **fail closed**: missing env vars, query errors, or non-`active`
|
|
|
6191
6182
|
|
|
6192
6183
|
#### 6.2.4.2 Backup and Fault-Tolerance Policies
|
|
6193
6184
|
|
|
6194
|
-
Detailed in §6.2.2.8. In summary: Supabase-managed PITR and managed backups (primary DR); `pg_dump` / `psql` scripts (operator-initiated); 11 migrations as schema-of-truth (rebuild); hybrid snapshot/diff revisions (content rollback). The Sandbox Reset Cron
|
|
6185
|
+
Detailed in §6.2.2.8. In summary: Supabase-managed PITR and managed backups (primary DR); `pg_dump` / `psql` scripts (operator-initiated); 11 migrations as schema-of-truth (rebuild); hybrid snapshot/diff revisions (content rollback). The Sandbox Reset Cron every 15 minutes (60s `maxDuration`) doubles as a reconstruction rehearsal, as documented in §4.5.
|
|
6195
6186
|
|
|
6196
6187
|
#### 6.2.4.3 Privacy Controls via Row-Level Security
|
|
6197
6188
|
|
|
6198
|
-
RLS is **enabled on every table** in migration `
|
|
6189
|
+
RLS is **enabled on every table** in migration `02001_baseline_schema.sql`. The policy matrix distributes into four access tiers.
|
|
6199
6190
|
|
|
6200
6191
|
| Access Tier | Representative Scope | Tables |
|
|
6201
6192
|
|-------------|----------------------|--------|
|
|
@@ -6327,7 +6318,7 @@ Application-layer details:
|
|
|
6327
6318
|
|
|
6328
6319
|
| Batch Workload | Mechanism | Frequency |
|
|
6329
6320
|
|----------------|-----------|-----------|
|
|
6330
|
-
| Sandbox reset (cron) | Service-role client replays seed migrations |
|
|
6321
|
+
| Sandbox reset (cron) | Service-role client replays seed migrations | Every 15 minutes, 60s `maxDuration` |
|
|
6331
6322
|
| Currency exchange-rate sync (cron) | Service-role client updates `currencies.exchange_rate` from Frankfurter API | Daily 18:00 UTC, 30s `maxDuration` |
|
|
6332
6323
|
| Bulk variant upsert | `upsert_product_with_variants(jsonb)` PL/pgSQL function — admin-only via `is_admin()` | Ad-hoc, CMS-triggered |
|
|
6333
6324
|
| Migration seeds | Direct SQL in migrations `00000000000008` through `00000000000010` with `ON CONFLICT` merge logic preserving existing values | At deploy time |
|
|
@@ -6479,17 +6470,17 @@ The local Supabase stack is configured through `libs/db/src/supabase/config.toml
|
|
|
6479
6470
|
|
|
6480
6471
|
#### 6.2.9.1 Files Examined
|
|
6481
6472
|
|
|
6482
|
-
- `libs/db/src/supabase/migrations/
|
|
6483
|
-
- `libs/db/src/supabase/migrations/
|
|
6484
|
-
- `libs/db/src/supabase/migrations/
|
|
6485
|
-
- `libs/db/src/supabase/migrations/
|
|
6486
|
-
- `libs/db/src/supabase/migrations/
|
|
6487
|
-
- `libs/db/src/supabase/migrations/
|
|
6488
|
-
- `libs/db/src/supabase/migrations/
|
|
6489
|
-
- `libs/db/src/supabase/migrations/
|
|
6490
|
-
- `libs/db/src/supabase/migrations/
|
|
6491
|
-
- `libs/db/src/supabase/migrations/
|
|
6492
|
-
- `libs/db/src/supabase/migrations/
|
|
6473
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — Enums and schema grants
|
|
6474
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — Core CMS tables (profiles, media, languages, translations)
|
|
6475
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — Pages, posts, blocks, revisions, navigation
|
|
6476
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — Commerce catalog and license registry
|
|
6477
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — Orders, shipping, tax, currencies
|
|
6478
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — Business logic functions and triggers
|
|
6479
|
+
- `libs/db/src/supabase/migrations/02003_baseline_security_and_grants.sql` — Row-Level Security policy matrix
|
|
6480
|
+
- `libs/db/src/supabase/migrations/02002_baseline_constraints_and_indexes.sql` — 38 secondary indexes
|
|
6481
|
+
- `libs/db/src/supabase/migrations/02004_baseline_seed.sql` — Baseline platform seed
|
|
6482
|
+
- `libs/db/src/supabase/migrations/02004_baseline_seed.sql` — Internationalization seed
|
|
6483
|
+
- `libs/db/src/supabase/migrations/02004_baseline_seed.sql` — Starter content seed
|
|
6493
6484
|
- `libs/db/src/supabase/config.toml` — Supabase local stack configuration
|
|
6494
6485
|
- `libs/db/src/lib/supabase/client.ts` — Browser client factory
|
|
6495
6486
|
- `libs/db/src/lib/supabase/server.ts` — Server / SSR / service-role client factories
|
|
@@ -6829,7 +6820,7 @@ All "events" in this system are either **HTTP webhooks delivered by external pro
|
|
|
6829
6820
|
| Stripe | `checkout.session.completed` (others ignored) | `libs/ecommerce/src/lib/stripe/webhooks.ts` |
|
|
6830
6821
|
| Freemius | `install.upgraded`, `license.activated` (others ignored) | `apps/nextblock/app/api/webhooks/freemius/route.ts` |
|
|
6831
6822
|
| Supabase DB Triggers | Row INSERT/UPDATE/DELETE on `pages` / `posts` | `apps/nextblock/app/api/revalidate/route.ts` |
|
|
6832
|
-
| Vercel Cron Ticks | Scheduled GET at
|
|
6823
|
+
| Vercel Cron Ticks | Scheduled GET at `*/15 * * * *` / `0 18 * * *` | `/api/cron/reset-sandbox`, `/api/cron/sync-currencies` |
|
|
6833
6824
|
|
|
6834
6825
|
##### 6.3.3.1.2 Stripe Event Dispatcher Discipline
|
|
6835
6826
|
|
|
@@ -6862,12 +6853,12 @@ The revalidation flow functions as a degenerate "stream" with batch size 1: ever
|
|
|
6862
6853
|
|
|
6863
6854
|
#### 6.3.3.4 Batch Processing Flows
|
|
6864
6855
|
|
|
6865
|
-
Two
|
|
6856
|
+
Two Vercel cron jobs constitute the entire batch processing surface, declared explicitly in `vercel.json`:
|
|
6866
6857
|
|
|
6867
6858
|
```mermaid
|
|
6868
6859
|
flowchart LR
|
|
6869
6860
|
subgraph CronDecl["vercel.json crons[]"]
|
|
6870
|
-
A[path: /api/cron/reset-sandbox<br/>schedule:
|
|
6861
|
+
A[path: /api/cron/reset-sandbox<br/>schedule: */15 * * * *]
|
|
6871
6862
|
B[path: /api/cron/sync-currencies<br/>schedule: 0 18 * * *]
|
|
6872
6863
|
end
|
|
6873
6864
|
|
|
@@ -6916,7 +6907,7 @@ flowchart LR
|
|
|
6916
6907
|
SA6 --> SA7
|
|
6917
6908
|
```
|
|
6918
6909
|
|
|
6919
|
-
##### 6.3.3.4.1 Sandbox Reset Cron (
|
|
6910
|
+
##### 6.3.3.4.1 Sandbox Reset Cron (every 15 minutes, maxDuration 60s)
|
|
6920
6911
|
|
|
6921
6912
|
Purpose: Reconstruct the public demo environment from scratch so that visitor-driven modifications do not pollute the demo. The handler executes eleven ordered steps including R2 bucket clearing via `ListObjectsV2Command` + `DeleteObjectsCommand`, seed asset re-upload via `PutObjectCommand`, SQL bootstrap via the `postgres` driver, media record normalization, Freemius product synchronization, and commerce catalog seeding. The `finally { db.end() }` block guarantees Postgres connection teardown even on error.
|
|
6922
6913
|
|
|
@@ -7370,7 +7361,7 @@ Per Section 5.1.4.2, each external integration carries explicit SLA-like propert
|
|
|
7370
7361
|
| Freemius | HTTPS + `x-freemius-signature` HMAC-SHA-256 | Sandbox bypass when `NEXT_PUBLIC_IS_SANDBOX===true` |
|
|
7371
7362
|
| Frankfurter | HTTPS (JSON) | Cron daily 18:00 UTC; `maxDuration: 30s` |
|
|
7372
7363
|
| SMTP | SMTP + TLS | Best-effort from server actions |
|
|
7373
|
-
| Vercel Cron | HTTPS + Bearer CRON_SECRET |
|
|
7364
|
+
| Vercel Cron | HTTPS + Bearer CRON_SECRET | every 15 min (reset-sandbox 60s); 18:00 UTC (sync-currencies 30s) |
|
|
7374
7365
|
| Google Tag Manager | HTTPS (JS) | GTM id from `privacy_settings` (site_settings); allowlisted in CSP |
|
|
7375
7366
|
|
|
7376
7367
|
#### 6.3.6.2 Known Integration Limitations
|
|
@@ -7403,7 +7394,7 @@ The `shipping_zone_locations.postal_code` column exists in the schema but the cu
|
|
|
7403
7394
|
- **Four canonical patterns** (outbound HTTPS, signed webhook, token webhook, scheduled cron) cover every integration.
|
|
7404
7395
|
- **Seven authentication mechanisms** coexist, each tailored to its upstream provider's requirements.
|
|
7405
7396
|
- **Three-layer authorization** (cookie session → path-prefix guard → RLS + license gate) provides defense in depth.
|
|
7406
|
-
- **Batch processing** is limited to two
|
|
7397
|
+
- **Batch processing** is limited to two Vercel crons (sandbox reset every 15 minutes, currency sync daily at 18:00 UTC).
|
|
7407
7398
|
- **Error handling** is classified into strict-fail, dual-path, and best-effort categories with the RPC + SQL fallback for inventory deduction being the most sophisticated resilience primitive.
|
|
7408
7399
|
- **Known limitations** include incomplete Freemius reconciliation, a package alias mismatch, FX schema coupling, and an unused postal-code column.
|
|
7409
7400
|
|
|
@@ -7428,7 +7419,7 @@ The `shipping_zone_locations.postal_code` column exists in the schema but the cu
|
|
|
7428
7419
|
|
|
7429
7420
|
#### Files Examined
|
|
7430
7421
|
|
|
7431
|
-
- `vercel.json` — Cron schedule declarations (`reset-sandbox`
|
|
7422
|
+
- `vercel.json` — Cron schedule declarations (`reset-sandbox` every 15 minutes, `sync-currencies` at 18:00 UTC)
|
|
7432
7423
|
- `libs/environment.d.ts` — NodeJS.ProcessEnv augmentation declaring all external-integration environment variables
|
|
7433
7424
|
- `.env.example` — Authoritative environment variable template
|
|
7434
7425
|
- `apps/nextblock/proxy.ts` — 272-line request proxy consolidating session sync, RBAC, locale, security headers, CSP, and page-type classification
|
|
@@ -7507,7 +7498,7 @@ Security controls are layered so that the failure of any single layer does not r
|
|
|
7507
7498
|
|-------|----------------------|------------------|
|
|
7508
7499
|
| Edge | Request proxy — session refresh, path-prefix RBAC, security headers, CSP | `apps/nextblock/proxy.ts` |
|
|
7509
7500
|
| Application | Client-layout role guard, server-action `verifyAdmin()`, role-gated page components | `app/cms/CmsClientLayout.tsx`, `app/cms/users/actions.ts` |
|
|
7510
|
-
| Data | Row-Level Security policies, SECURITY DEFINER helpers, service-role bypass | `libs/db/src/supabase/migrations/
|
|
7501
|
+
| Data | Row-Level Security policies, SECURITY DEFINER helpers, service-role bypass | `libs/db/src/supabase/migrations/02003_baseline_security_and_grants.sql` |
|
|
7511
7502
|
| Integration | Webhook signature verification, Bearer-secret cron, HMAC-verified callbacks | `/api/webhooks/*`, `/api/cron/*`, `/api/revalidate/route.ts` |
|
|
7512
7503
|
|
|
7513
7504
|
#### 6.4.1.3 Security Architecture Topology
|
|
@@ -7617,7 +7608,7 @@ The system manages three distinct token classes, each with differentiated lifecy
|
|
|
7617
7608
|
| OAuth Authorization Code | Short-lived code exchange | URL query parameter, consumed immediately at `/auth/callback` |
|
|
7618
7609
|
| Supabase Service Role Key | Server-only RLS bypass | Vercel environment variable (`SUPABASE_SERVICE_ROLE_KEY`) |
|
|
7619
7610
|
|
|
7620
|
-
A **per-request nonce** is generated via `crypto.randomUUID()` in `proxy.ts` and used for the nonce-based CSP (see §6.4.4.5). JWT claims are read inside Postgres by the `get_my_claim(claim text)` SECURITY DEFINER function via `current_setting('request.jwt.claims', true)::jsonb`, which is defined in `libs/db/src/supabase/migrations/
|
|
7611
|
+
A **per-request nonce** is generated via `crypto.randomUUID()` in `proxy.ts` and used for the nonce-based CSP (see §6.4.4.5). JWT claims are read inside Postgres by the `get_my_claim(claim text)` SECURITY DEFINER function via `current_setting('request.jwt.claims', true)::jsonb`, which is defined in `libs/db/src/supabase/migrations/02001_baseline_schema.sql`.
|
|
7621
7612
|
|
|
7622
7613
|
The **service role key** requires two independent compile-time and runtime guards to prevent leakage into the browser bundle:
|
|
7623
7614
|
|
|
@@ -7715,7 +7706,7 @@ The `resolvePostAuthRedirect` helper enforces four rules as a gate against open-
|
|
|
7715
7706
|
|
|
7716
7707
|
#### 6.4.3.1 Role-Based Access Control Model
|
|
7717
7708
|
|
|
7718
|
-
Authorization is driven by the `user_role` enum declared in migration `
|
|
7709
|
+
Authorization is driven by the `user_role` enum declared in migration `02001_baseline_schema.sql`, which admits three values plus an implicit fourth (Supabase's `service_role`) for server-only privilege elevation:
|
|
7719
7710
|
|
|
7720
7711
|
| Role | Assignment Mechanism | Zone Capabilities |
|
|
7721
7712
|
|------|---------------------|-------------------|
|
|
@@ -7728,7 +7719,7 @@ Role assignment at bootstrap is governed by the `handle_new_user()` SECURITY DEF
|
|
|
7728
7719
|
|
|
7729
7720
|
#### 6.4.3.2 Permission Management and SECURITY DEFINER Helpers
|
|
7730
7721
|
|
|
7731
|
-
Role checks executed inside SQL contexts use SECURITY DEFINER helper functions declared in `libs/db/src/supabase/migrations/
|
|
7722
|
+
Role checks executed inside SQL contexts use SECURITY DEFINER helper functions declared in `libs/db/src/supabase/migrations/02001_baseline_schema.sql`. SECURITY DEFINER elevates the function's execution privileges to the function owner, bypassing caller-side RLS for the function body while `SET search_path = ''` prevents search-path hijacking attacks.
|
|
7732
7723
|
|
|
7733
7724
|
| Function | Purpose | Security Annotation |
|
|
7734
7725
|
|----------|---------|---------------------|
|
|
@@ -7741,7 +7732,7 @@ These helpers form the primitive vocabulary of all RLS policies: a user's effect
|
|
|
7741
7732
|
|
|
7742
7733
|
#### 6.4.3.3 Resource Authorization Matrix
|
|
7743
7734
|
|
|
7744
|
-
RLS is enabled on every table in migration `
|
|
7735
|
+
RLS is enabled on every table in migration `02001_baseline_schema.sql` (872 lines). The matrix distributes into four access tiers:
|
|
7745
7736
|
|
|
7746
7737
|
| Access Tier | Typical Policy Predicate | Representative Tables |
|
|
7747
7738
|
|-------------|--------------------------|------------------------|
|
|
@@ -8127,7 +8118,7 @@ The security control matrix below enumerates the principal threats, their mitiga
|
|
|
8127
8118
|
|
|
8128
8119
|
| Threat | Mitigation | Migration or File |
|
|
8129
8120
|
|--------|-----------|-------------------|
|
|
8130
|
-
| Public data exposure through writes | RLS writes restricted; public read only for intended tables and statuses | `migrations/
|
|
8121
|
+
| Public data exposure through writes | RLS writes restricted; public read only for intended tables and statuses | `migrations/02003_baseline_security_and_grants.sql` |
|
|
8131
8122
|
| Draft content leakage | Anon policy `status='published'` on pages; `status='published' AND published_at<=now()` on posts | `migration 00000000000006` |
|
|
8132
8123
|
| Path traversal in uploads | `sanitizeFolder()` collapses `../`, strips leading slashes, removes illegal chars | `/api/upload/presigned-url/route.ts` |
|
|
8133
8124
|
| Search-path hijacking in SECURITY DEFINER | `SET search_path = ''` on auth helper functions | `migration 00000000000005` |
|
|
@@ -8196,7 +8187,7 @@ For details beyond the scope of this section, consult:
|
|
|
8196
8187
|
|
|
8197
8188
|
- `apps/nextblock/proxy.ts` — 272-line edge proxy (session sync, RBAC, locale, CSP, headers, page-type signaling)
|
|
8198
8189
|
- `apps/nextblock/next.config.js` — 91-line image security config + `compiler.removeConsole`
|
|
8199
|
-
- `apps/nextblock/vercel.json` — Cron schedule declarations (
|
|
8190
|
+
- `apps/nextblock/vercel.json` — Cron schedule declarations (every-15-minutes reset-sandbox, 18:00 sync-currencies)
|
|
8200
8191
|
|
|
8201
8192
|
#### Authentication and Authorization
|
|
8202
8193
|
|
|
@@ -8226,9 +8217,9 @@ For details beyond the scope of this section, consult:
|
|
|
8226
8217
|
|
|
8227
8218
|
#### Database Security Surface
|
|
8228
8219
|
|
|
8229
|
-
- `libs/db/src/supabase/migrations/
|
|
8230
|
-
- `libs/db/src/supabase/migrations/
|
|
8231
|
-
- `libs/db/src/supabase/migrations/
|
|
8220
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `user_role` enum declaration
|
|
8221
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `handle_new_user`, `get_current_user_role`, `is_admin`, `get_my_claim` SECURITY DEFINER functions
|
|
8222
|
+
- `libs/db/src/supabase/migrations/02003_baseline_security_and_grants.sql` — 872-line RLS policy matrix
|
|
8232
8223
|
- `libs/db/src/supabase/config.toml` — 341-line Supabase Auth + MFA + rate-limit configuration
|
|
8233
8224
|
- `libs/db/src/supabase/templates/` — Six transactional email templates
|
|
8234
8225
|
|
|
@@ -8546,7 +8537,7 @@ No dedicated `/api/health` or `/api/readiness` endpoint exists in the repository
|
|
|
8546
8537
|
|
|
8547
8538
|
##### 6.5.3.1.2 Scheduled-Execution Health Signal
|
|
8548
8539
|
|
|
8549
|
-
The two Vercel cron schedules in `vercel.json` serve a dual purpose: they perform their business function (sandbox reset and currency sync) while simultaneously producing a
|
|
8540
|
+
The two Vercel cron schedules in `vercel.json` serve a dual purpose: they perform their business function (sandbox reset and currency sync) while simultaneously producing a recurring heartbeat that is visible on the Vercel dashboard. A cron invocation that returns HTTP 500 is therefore the closest the system comes to an automated unhealthy signal, because it is automatically surfaced in Vercel's cron execution history.
|
|
8550
8541
|
|
|
8551
8542
|
#### 6.5.3.2 Performance Metrics
|
|
8552
8543
|
|
|
@@ -8608,7 +8599,7 @@ SLAs are encoded directly in configuration files (`vercel.json`, `next.config.js
|
|
|
8608
8599
|
| Sync-currencies `maxDuration` | 30 seconds | `vercel.json` + route |
|
|
8609
8600
|
| Reset-sandbox `maxDuration` | 60 seconds | `vercel.json` + route |
|
|
8610
8601
|
| Currency sync schedule | `0 18 * * *` (18:00 UTC daily) | `vercel.json` |
|
|
8611
|
-
| Sandbox reset schedule |
|
|
8602
|
+
| Sandbox reset schedule | `*/15 * * * *` (every 15 minutes) | `vercel.json` |
|
|
8612
8603
|
| Max source image width | 2560 pixels | `/api/process-image` |
|
|
8613
8604
|
| Lighthouse performance target | 100/100 | `README.md` |
|
|
8614
8605
|
| CLI scaffold target | ≤ 30 seconds | `README.md` |
|
|
@@ -8651,9 +8642,9 @@ flowchart LR
|
|
|
8651
8642
|
HstsHeader[HSTS Header<br/>2 years max-age]
|
|
8652
8643
|
end
|
|
8653
8644
|
|
|
8654
|
-
subgraph Scheduled[" Scheduled
|
|
8645
|
+
subgraph Scheduled[" Scheduled (Vercel Cron) "]
|
|
8655
8646
|
CurrencyDay[18:00 UTC<br/>Sync Currencies]
|
|
8656
|
-
ResetDay[
|
|
8647
|
+
ResetDay[Every 15 min<br/>Sandbox Reset]
|
|
8657
8648
|
end
|
|
8658
8649
|
```
|
|
8659
8650
|
|
|
@@ -8764,7 +8755,7 @@ Operators have four primary recovery mechanisms, all described in detail in Sect
|
|
|
8764
8755
|
1. **Content rollback via revisions.** `page_revisions` and `post_revisions` tables store hybrid snapshot/diff records (JSON Patch via `fast-json-patch`) keyed by `UNIQUE (page_id, version)`. Any published state can be restored without a database restore.
|
|
8765
8756
|
2. **Supabase Point-in-Time Recovery.** Platform-level PITR is the authoritative recovery path for catastrophic data loss.
|
|
8766
8757
|
3. **Schema reconstruction from migrations.** The eleven canonical SQL files in `libs/db/src/supabase/migrations/` (`000_foundation_and_enums` through `010_seed_content_scaffold`) allow deterministic schema rebuild on a fresh Supabase project.
|
|
8767
|
-
4. **
|
|
8758
|
+
4. **15-minute sandbox reset as reconstruction rehearsal.** The 15-minute `/api/cron/reset-sandbox` job exercises the full R2-clear → SQL-bootstrap → media-normalize → seed pipeline every 15 minutes, serving as continuous validation that the recovery procedure still works.
|
|
8768
8759
|
|
|
8769
8760
|
#### 6.5.4.5 Post-mortem Processes
|
|
8770
8761
|
|
|
@@ -8856,7 +8847,7 @@ The following observability gaps are acknowledged and documented for honest stak
|
|
|
8856
8847
|
- **Alert routing is manual.** The primary alert path is the `FeedbackModal` → `submitFeedback` → SMTP → `feedback@nextblock.dev` flow; platform alerts are configured in Vercel/Supabase consoles.
|
|
8857
8848
|
- **No distributed tracing, no alert manager, no runbooks, no post-mortems, no persistent audit log table.** These absences are deliberate for the system's scale and are documented as explicit gaps.
|
|
8858
8849
|
- **SLAs are codified in config, not monitored actively.** The canonical SLA table (Section 4.12) lists all timing constraints; crossings surface as HTTP errors or terminated function invocations in the Vercel log stream.
|
|
8859
|
-
- **Disaster recovery rests on Supabase PITR, canonical migrations, content revisions, and the
|
|
8850
|
+
- **Disaster recovery rests on Supabase PITR, canonical migrations, content revisions, and the 15-minute sandbox-reset reconstruction rehearsal** (detailed in Section 6.1.6 and Section 5.4.6).
|
|
8860
8851
|
|
|
8861
8852
|
#### 6.5.7.2 Cross-References to Related Sections
|
|
8862
8853
|
|
|
@@ -8899,7 +8890,7 @@ The following observability gaps are acknowledged and documented for honest stak
|
|
|
8899
8890
|
- `libs/ecommerce/src/lib/stripe/webhooks.ts` — Stripe webhook handler with `[Stripe Webhook Error]` prefix; `console.error` on missing `STRIPE_WEBHOOK_SECRET` and on `constructEvent` failure
|
|
8900
8891
|
- `libs/db/src/lib/package-validation.ts` — License gate with `console.error` and 60-second `unstable_cache` tagged `'package-activation'`
|
|
8901
8892
|
- `libs/environment.d.ts` — `NodeJS.ProcessEnv` augmentation declaring external-service env vars (Supabase, R2/S3, SMTP, Freemius, OpenRouter/Cortex AI). GTM is no longer env-configured — it lives in `privacy_settings`.
|
|
8902
|
-
- `vercel.json` — Two cron schedule declarations:
|
|
8893
|
+
- `vercel.json` — Two cron schedule declarations: `*/15 * * * *` reset-sandbox (60s) and `0 18 * * *` sync-currencies (30s)
|
|
8903
8894
|
- `package.json` (root) — Dependency declarations including `@vercel/speed-insights` and `@next/third-parties`
|
|
8904
8895
|
- `apps/nextblock/package.json` — Template-level dependency declarations including `@vercel/analytics` (declared but not imported)
|
|
8905
8896
|
- `docs/05-DEVELOPER-GUIDE.md` — Operational handbook, deployment notes, sandbox operations
|
|
@@ -9102,7 +9093,7 @@ Because no integration test suite exists, there is no dedicated test environment
|
|
|
9102
9093
|
|:--|:--|
|
|
9103
9094
|
| Local Supabase via `libs/db/src/supabase/config.toml` | Developer database for hand-driven verification |
|
|
9104
9095
|
| Vercel Preview Deployments | Per-branch verification prior to production |
|
|
9105
|
-
| Sandbox production environment | End-to-end smoke testing via `NEXT_PUBLIC_IS_SANDBOX=true` flag with
|
|
9096
|
+
| Sandbox production environment | End-to-end smoke testing via `NEXT_PUBLIC_IS_SANDBOX=true` flag with a 15-minute reset cron |
|
|
9106
9097
|
|
|
9107
9098
|
---
|
|
9108
9099
|
|
|
@@ -9112,7 +9103,7 @@ Because no integration test suite exists, there is no dedicated test environment
|
|
|
9112
9103
|
|
|
9113
9104
|
No E2E test framework (Playwright, Cypress, WebdriverIO, Puppeteer) is installed. This is explicitly documented as the accepted tradeoff in ADR §5.3.1: *"Vitest-only — Limited end-to-end coverage."* The absence is compensated by:
|
|
9114
9105
|
|
|
9115
|
-
1. **Sandbox reset cron as reconstruction rehearsal.** The `/api/cron/reset-sandbox` endpoint (§6.1.6.2) runs
|
|
9106
|
+
1. **Sandbox reset cron as reconstruction rehearsal.** The `/api/cron/reset-sandbox` endpoint (§6.1.6.2) runs every 15 minutes, clearing R2, running `SANDBOX_RESET_SQL`, normalizing legacy media, re-seeding commerce and content. A successful reset validates that the full happy-path data pipeline — migrations, storage, seeding — functions end-to-end.
|
|
9116
9107
|
2. **Lighthouse performance score targeting 100/100.** Per §5.3.4 and §5.4.5, the 100/100 Lighthouse target provides an observational E2E signal on a per-deployment basis.
|
|
9117
9108
|
3. **Production monitoring via Vercel Speed Insights + structured `console.warn`/`console.error`.** Per §6.4.3.5, production diagnostics survive `compiler.removeConsole` stripping and provide post-release observability.
|
|
9118
9109
|
|
|
@@ -9545,7 +9536,7 @@ The accepted tradeoff in §5.3.1 ("Vitest-only — Limited end-to-end coverage")
|
|
|
9545
9536
|
- `apps/create-nextblock/package.json` — npm-init stub `"test": "echo \"Error: no test specified\" && exit 1"`
|
|
9546
9537
|
- `apps/nextblock/project.json` — No test target declared
|
|
9547
9538
|
- `tools/scripts/release-lib.js` — Library release pipeline; runs `npx nx run ${nxProject}:build --skip-nx-cache --with-deps` with no test invocation
|
|
9548
|
-
- `vercel.json` — Cron declarations (
|
|
9539
|
+
- `vercel.json` — Cron declarations (every-15-minutes reset-sandbox; 18:00 UTC sync-currencies); no test hooks
|
|
9549
9540
|
- `docs/05-DEVELOPER-GUIDE.md` — Developer command reference; no test commands documented
|
|
9550
9541
|
- `.agent/skills/nx-operations/SKILL.md` — Front matter mentions tests but body documents only Building, Linting, and Development
|
|
9551
9542
|
|
|
@@ -10564,7 +10555,7 @@ The repository supports three deployment environments, with promotion driven by
|
|
|
10564
10555
|
| Preview / Staging | Push to non-deployment branch or PR | Vercel Preview Deployment (unique URL per commit) |
|
|
10565
10556
|
| Production | Push to Vercel-integrated deployment branch (default base: `master`) | Vercel Production Deployment (`NEXT_PUBLIC_URL`) |
|
|
10566
10557
|
|
|
10567
|
-
A special **Sandbox production environment** is gated by `NEXT_PUBLIC_IS_SANDBOX=true` and is reset
|
|
10558
|
+
A special **Sandbox production environment** is gated by `NEXT_PUBLIC_IS_SANDBOX=true` and is reset every 15 minutes via the `/api/cron/reset-sandbox` endpoint. Sandbox serves as a public demonstration site and as a continuous reconstruction rehearsal for the disaster recovery pipeline (see §8.2.2.5).
|
|
10568
10559
|
|
|
10569
10560
|
#### 8.2.2.4 Environment Promotion Flow Diagram
|
|
10570
10561
|
|
|
@@ -10575,7 +10566,7 @@ flowchart LR
|
|
|
10575
10566
|
Preview[Vercel Preview Deployment<br/>Per-commit URL<br/>Shared Supabase preview]
|
|
10576
10567
|
Merge[Merge to master]
|
|
10577
10568
|
Prod[Vercel Production Deployment<br/>NEXT_PUBLIC_URL<br/>Production Supabase]
|
|
10578
|
-
Sandbox[Sandbox Production<br/>NEXT_PUBLIC_IS_SANDBOX=true<br/>
|
|
10569
|
+
Sandbox[Sandbox Production<br/>NEXT_PUBLIC_IS_SANDBOX=true<br/>Reset every 15 min]
|
|
10579
10570
|
ResetCycle[R2 clear +<br/>SANDBOX_RESET_SQL +<br/>media normalize +<br/>seed content]
|
|
10580
10571
|
|
|
10581
10572
|
Dev --> PR
|
|
@@ -10585,7 +10576,7 @@ flowchart LR
|
|
|
10585
10576
|
Prod -.parallel branch.-> Sandbox
|
|
10586
10577
|
|
|
10587
10578
|
Sandbox -->|cron/reset-sandbox| ResetCycle
|
|
10588
|
-
ResetCycle -.
|
|
10579
|
+
ResetCycle -.every 15 min.-> Sandbox
|
|
10589
10580
|
|
|
10590
10581
|
style Dev fill:#e0f2fe,stroke:#0284c7
|
|
10591
10582
|
style Preview fill:#fef3c7,stroke:#d97706
|
|
@@ -10602,7 +10593,7 @@ Disaster recovery relies on **four compounding recovery mechanisms**, none of wh
|
|
|
10602
10593
|
| Supabase Point-in-Time Recovery (PITR) | Catastrophic data loss | Platform-managed by Supabase |
|
|
10603
10594
|
| Content revisions | Accidental edits / content rollback | `page_revisions` + `post_revisions` tables with JSON Patch diffs (via `fast-json-patch`), `UNIQUE(page_id, version)` |
|
|
10604
10595
|
| Schema reconstruction from migrations | Cold-start rebuild | 11 canonical SQL files in `libs/db/src/supabase/migrations/` applied in order |
|
|
10605
|
-
|
|
|
10596
|
+
| 15-minute sandbox reset (reconstruction rehearsal) | Continuous validation that recovery pipeline works | `/api/cron/reset-sandbox` every 15 minutes |
|
|
10606
10597
|
|
|
10607
10598
|
Backup responsibility matrix:
|
|
10608
10599
|
|
|
@@ -10787,7 +10778,7 @@ Security is enforced across four layers, with compliance-relevant controls conce
|
|
|
10787
10778
|
|:--|:--|:--|
|
|
10788
10779
|
| Edge | Nonce-based CSP, HSTS, X-Frame-Options SAMEORIGIN, X-Content-Type-Options nosniff, Referrer-Policy origin-when-cross-origin, Permissions-Policy, COOP same-origin | `proxy.ts` |
|
|
10789
10780
|
| Application | RBAC via `cmsRoutePermissions` (`/cms` ADMIN/WRITER; `/cms/admin`, `/cms/users`, `/cms/settings` ADMIN only); `verifyAdmin()` in server actions | `proxy.ts`, server actions |
|
|
10790
|
-
| Data | RLS policies + SECURITY DEFINER helpers (`get_my_claim`, `get_current_user_role`, `is_admin`, `handle_new_user`) | Migration `
|
|
10781
|
+
| Data | RLS policies + SECURITY DEFINER helpers (`get_my_claim`, `get_current_user_role`, `is_admin`, `handle_new_user`) | Migration `02001_baseline_schema.sql` (872 lines) |
|
|
10791
10782
|
| Integration | Stripe `constructEvent` signature verification; Freemius HMAC-SHA-256; `CRON_SECRET` Bearer auth; `REVALIDATE_SECRET_TOKEN` via `x-revalidate-secret` header | Webhook + cron route handlers |
|
|
10792
10783
|
|
|
10793
10784
|
**Service role key hardening**: `SUPABASE_SERVICE_ROLE_KEY` is guarded at runtime via `typeof window !== 'undefined'` checks and build-time via `import 'server-only'` directives to prevent browser exposure.
|
|
@@ -11047,7 +11038,7 @@ Scheduled jobs deploy automatically with the application via `vercel.json`:
|
|
|
11047
11038
|
```json
|
|
11048
11039
|
{
|
|
11049
11040
|
"crons": [
|
|
11050
|
-
{"path": "/api/cron/reset-sandbox", "schedule": "
|
|
11041
|
+
{"path": "/api/cron/reset-sandbox", "schedule": "*/15 * * * *"},
|
|
11051
11042
|
{"path": "/api/cron/sync-currencies", "schedule": "0 18 * * *"}
|
|
11052
11043
|
]
|
|
11053
11044
|
}
|
|
@@ -11055,7 +11046,7 @@ Scheduled jobs deploy automatically with the application via `vercel.json`:
|
|
|
11055
11046
|
|
|
11056
11047
|
| Cron | Schedule (UTC) | maxDuration | Authentication |
|
|
11057
11048
|
|:--|:--|:--|:--|
|
|
11058
|
-
| `/api/cron/reset-sandbox` |
|
|
11049
|
+
| `/api/cron/reset-sandbox` | `*/15 * * * *` (every 15 minutes) | 60s | `Authorization: Bearer ${CRON_SECRET}` |
|
|
11059
11050
|
| `/api/cron/sync-currencies` | `0 18 * * *` (18:00 daily) | 30s | `Authorization: Bearer ${CRON_SECRET}` |
|
|
11060
11051
|
|
|
11061
11052
|
Purpose: `reset-sandbox` performs R2 clear + `SANDBOX_RESET_SQL` + media normalize + content seed; `sync-currencies` performs Frankfurter FX fetch + currency row update.
|
|
@@ -11111,7 +11102,7 @@ flowchart TB
|
|
|
11111
11102
|
subgraph CronPipeline["Scheduled Jobs - Vercel Cron"]
|
|
11112
11103
|
CronDecl[vercel.json crons array]
|
|
11113
11104
|
CronRuntime[Vercel Cron Dispatcher]
|
|
11114
|
-
ResetJob[/api/cron/reset-sandbox<br/>
|
|
11105
|
+
ResetJob[/api/cron/reset-sandbox<br/>every 15 min]
|
|
11115
11106
|
SyncJob[/api/cron/sync-currencies<br/>18:00 UTC]
|
|
11116
11107
|
end
|
|
11117
11108
|
|
|
@@ -11285,7 +11276,7 @@ Per §4.12, the following are the codified timing constraints. Breaches surface
|
|
|
11285
11276
|
| Sync-currencies maxDuration | 30s | `vercel.json` + route export |
|
|
11286
11277
|
| Reset-sandbox maxDuration | 60s | `vercel.json` + route export |
|
|
11287
11278
|
| Currency sync schedule | 18:00 UTC daily | `vercel.json` |
|
|
11288
|
-
| Sandbox reset schedule |
|
|
11279
|
+
| Sandbox reset schedule | every 15 minutes | `vercel.json` |
|
|
11289
11280
|
| Max source image width | 2560 px | `/api/process-image` |
|
|
11290
11281
|
| Image derivative widths | 1920, 1280, 768, 384, 128 | `next.config.js` `deviceSizes`/`imageSizes` |
|
|
11291
11282
|
| Image quality presets | 60, 75 | `next.config.js` `qualities` |
|
|
@@ -11300,7 +11291,7 @@ Per §4.12, the following are the codified timing constraints. Breaches surface
|
|
|
11300
11291
|
| Vercel function invocations | Vercel dashboard | Auto-scaled; `maxDuration` capping |
|
|
11301
11292
|
| Vercel bandwidth | Vercel dashboard | 1-year image cache TTL, AVIF compression |
|
|
11302
11293
|
| Vercel image optimization count | Vercel dashboard | `minimumCacheTTL: 31_536_000` |
|
|
11303
|
-
| Supabase DB CPU/IO | Supabase dashboard | RLS indexing (`
|
|
11294
|
+
| Supabase DB CPU/IO | Supabase dashboard | RLS indexing (`02001_baseline_schema.sql`) |
|
|
11304
11295
|
| Supabase egress | Supabase dashboard | Server-side aggregation; `count` head queries |
|
|
11305
11296
|
| R2 storage | Cloudflare dashboard | Folder path sanitization prevents duplicates |
|
|
11306
11297
|
| R2 Class A writes | Cloudflare dashboard | Single direct-upload via presigned URL (vs through server) |
|
|
@@ -11411,7 +11402,7 @@ graph TB
|
|
|
11411
11402
|
| Review Vercel log stream | Daily / on-alert | Vercel console |
|
|
11412
11403
|
| Review Supabase Advisors | Weekly | Supabase console |
|
|
11413
11404
|
| Review feedback inbox | Daily | `feedback@nextblock.dev` |
|
|
11414
|
-
| Sandbox reset validation | Automated | `/api/cron/reset-sandbox`
|
|
11405
|
+
| Sandbox reset validation | Automated | `/api/cron/reset-sandbox` every 15 minutes |
|
|
11415
11406
|
| FX rate sync | Automated | `/api/cron/sync-currencies` daily at 18:00 UTC |
|
|
11416
11407
|
| Dependency audit | Per release | `npm audit`, manual review |
|
|
11417
11408
|
| Security patch review | On advisory | `npm update` + regression testing |
|
|
@@ -11543,12 +11534,12 @@ Operators should select tiers based on expected monthly active users, storage fo
|
|
|
11543
11534
|
- **Vercel-native, platform-delegated deployment**: no Docker, no Kubernetes, no Terraform, no GitHub Actions — all four absences are intentional ADRs documented in §5.3.7.3 and §3.7.1.
|
|
11544
11535
|
- **Three managed platform providers** compose the production footprint: Vercel (app + edge + cron + RUM), Supabase (PostgreSQL 17 + Auth + Storage metadata), Cloudflare R2 (S3-compatible object storage).
|
|
11545
11536
|
- **Hybrid CI/CD** combines Vercel Git integration (for application deployment) with three Node.js release scripts under `tools/scripts/` (for library/CLI/DB releases).
|
|
11546
|
-
- **Two Vercel cron schedules** in `vercel.json`: `/api/cron/reset-sandbox`
|
|
11537
|
+
- **Two Vercel cron schedules** in `vercel.json`: `/api/cron/reset-sandbox` every 15 minutes (60s max) and `/api/cron/sync-currencies` at 18:00 UTC (30s max).
|
|
11547
11538
|
- **Infrastructure as Code is declarative**, distributed across `vercel.json`, `nx.json`, `libs/db/src/supabase/{migrations/, config.toml, templates/}`, `.env.example`, and per-project `project.json` files.
|
|
11548
11539
|
- **Library publication uses a Twin Package Strategy** for `@nextblock-cms/ecom`: stub to public npm registry + real module to private GitHub Packages.
|
|
11549
11540
|
- **11 canonical SQL migrations** compose the database schema; re-running them from a fresh Supabase project deterministically reconstructs the system.
|
|
11550
11541
|
- **Monitoring is intentionally minimal**: Vercel Speed Insights for RUM, GTM for client analytics, structured `console.warn`/`console.error` logs for server-side events. No Prometheus/Grafana/Datadog/PagerDuty.
|
|
11551
|
-
- **Disaster recovery relies on four compounding mechanisms**: Supabase PITR, content revisions with JSON Patch diffs, schema reconstruction from migrations, and
|
|
11542
|
+
- **Disaster recovery relies on four compounding mechanisms**: Supabase PITR, content revisions with JSON Patch diffs, schema reconstruction from migrations, and 15-minute sandbox reset as a continuous reconstruction rehearsal.
|
|
11552
11543
|
- **Cost optimization is designed in**: zero egress on R2, platform-delegated scaling on Vercel, 1-year image cache TTL, daily (not per-request) FX sync.
|
|
11553
11544
|
|
|
11554
11545
|
### 8.11.2 Cross-References to Other Sections
|
|
@@ -11582,7 +11573,7 @@ Operators should select tiers based on expected monthly active users, storage fo
|
|
|
11582
11573
|
**Files Examined**
|
|
11583
11574
|
|
|
11584
11575
|
- `.env.example` — Authoritative inventory of 40+ environment variables across 7 categories (Platform, Secrets, FX, Supabase, R2, SMTP, Stripe, Freemius)
|
|
11585
|
-
- `vercel.json` — Declarative cron schedule definitions (2 crons: reset-sandbox
|
|
11576
|
+
- `vercel.json` — Declarative cron schedule definitions (2 crons: reset-sandbox every 15 minutes, sync-currencies at 18:00 UTC)
|
|
11586
11577
|
- `package.json` (root) — Workspace identity (`nextblock`), 51 npm scripts, Nx plugin versions, dependency overrides, `packageManager`
|
|
11587
11578
|
- `nx.json` — Workspace orchestration: 6 plugins, `defaultBase: master`, production named-input exclusions, `release.version.preVersionCommand`
|
|
11588
11579
|
- `apps/nextblock/next.config.js` — Image pipeline config, `compiler.removeConsole`, `transpilePackages`, dynamic `remotePatterns`, `turbopack.resolveAlias`
|
|
@@ -11702,15 +11693,15 @@ The following enum types are defined in the eleven canonical SQL migrations loca
|
|
|
11702
11693
|
|
|
11703
11694
|
| Enum Type | Allowed Values | Migration |
|
|
11704
11695
|
|:--|:--|:--|
|
|
11705
|
-
| `user_role` | `ADMIN`, `WRITER`, `USER` | `
|
|
11706
|
-
| `page_status` | `draft`, `published`, `archived` | `
|
|
11707
|
-
| `menu_location` | `header`, `footer`, `sidebar` | `
|
|
11708
|
-
| `revision_type` | `snapshot`, `diff` | `
|
|
11709
|
-
| `product_type` | `physical`, `digital` | `
|
|
11710
|
-
| `payment_provider` | `stripe`, `freemius` | `
|
|
11711
|
-
| `order_status` | `pending`, `paid`, `shipped`, `delivered`, `refunded`, `cancelled` | `
|
|
11712
|
-
| `tax_calculation_mode` | `manual`, `automatic` | `
|
|
11713
|
-
| `inventory_deduction_method` | `rpc`, `sql-fallback` | `
|
|
11696
|
+
| `user_role` | `ADMIN`, `WRITER`, `USER` | `02001_baseline_schema.sql` |
|
|
11697
|
+
| `page_status` | `draft`, `published`, `archived` | `02001_baseline_schema.sql` |
|
|
11698
|
+
| `menu_location` | `header`, `footer`, `sidebar` | `02001_baseline_schema.sql` |
|
|
11699
|
+
| `revision_type` | `snapshot`, `diff` | `02001_baseline_schema.sql` |
|
|
11700
|
+
| `product_type` | `physical`, `digital` | `02001_baseline_schema.sql` |
|
|
11701
|
+
| `payment_provider` | `stripe`, `freemius` | `02001_baseline_schema.sql` |
|
|
11702
|
+
| `order_status` | `pending`, `paid`, `shipped`, `delivered`, `refunded`, `cancelled` | `02001_baseline_schema.sql` |
|
|
11703
|
+
| `tax_calculation_mode` | `manual`, `automatic` | `02001_baseline_schema.sql` |
|
|
11704
|
+
| `inventory_deduction_method` | `rpc`, `sql-fallback` | `02001_baseline_schema.sql` |
|
|
11714
11705
|
|
|
11715
11706
|
Cross-reference: Section 6.2 (Database Design), Section 4.11 (Validation Rules and Compliance Checkpoints).
|
|
11716
11707
|
|
|
@@ -11771,7 +11762,7 @@ Reproduced from Section 4.12 for quick reference during operational work. Values
|
|
|
11771
11762
|
| Sync-currencies `maxDuration` | 30 seconds | `api/cron/sync-currencies` |
|
|
11772
11763
|
| Reset-sandbox `maxDuration` | 60 seconds | `api/cron/reset-sandbox` |
|
|
11773
11764
|
| Currency sync schedule | `0 18 * * *` (18:00 UTC daily) | `vercel.json` |
|
|
11774
|
-
| Sandbox reset schedule |
|
|
11765
|
+
| Sandbox reset schedule | `*/15 * * * *` (every 15 minutes) | `vercel.json` |
|
|
11775
11766
|
| Max source image width | 2560 pixels | `api/process-image` |
|
|
11776
11767
|
| Image derivative widths | 1920, 1280, 768, 384, 128 | `api/process-image` |
|
|
11777
11768
|
| Lighthouse performance target | 100/100 | `README.md` |
|
|
@@ -12149,7 +12140,7 @@ The glossary defines domain-specific, product-specific, and platform-specific te
|
|
|
12149
12140
|
|
|
12150
12141
|
**Sandbox Mode** — The demonstration environment activated by `NEXT_PUBLIC_IS_SANDBOX=true`. The `cms.nextblock.dev` deployment operates in sandbox mode with demo credentials `demo@nextblock.dev` / `password`.
|
|
12151
12142
|
|
|
12152
|
-
**Sandbox Reset** — The
|
|
12143
|
+
**Sandbox Reset** — The 15-minute cron job at `/api/cron/reset-sandbox` that clears R2, bootstraps SQL, normalizes media, and re-seeds content.
|
|
12153
12144
|
|
|
12154
12145
|
**Scope Tag** — An Nx project tag (`scope:public` or `scope:premium`) validated by the `@nx/enforce-module-boundaries` ESLint rule. See Section 9.1.5.
|
|
12155
12146
|
|
|
@@ -12430,10 +12421,10 @@ The appendices above synthesize material from the following sections of this spe
|
|
|
12430
12421
|
|
|
12431
12422
|
- `libs/environment.d.ts` — Typed `NodeJS.ProcessEnv` augmentation used to enumerate every environment variable listed in Section 9.1.1
|
|
12432
12423
|
- `.env.example` — Environment variable inventory and sample values cross-checked against the typed augmentation
|
|
12433
|
-
- `libs/db/src/supabase/migrations/
|
|
12434
|
-
- `libs/db/src/supabase/migrations/
|
|
12435
|
-
- `libs/db/src/supabase/migrations/
|
|
12436
|
-
- `libs/db/src/supabase/migrations/
|
|
12424
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `user_role` enum definition
|
|
12425
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `page_status`, `menu_location`, `revision_type` enum definitions
|
|
12426
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `product_type`, `payment_provider` enum definitions
|
|
12427
|
+
- `libs/db/src/supabase/migrations/02001_baseline_schema.sql` — `order_status`, `tax_calculation_mode`, `inventory_deduction_method` enum definitions
|
|
12437
12428
|
- `libs/db/src/supabase/config.toml` — Supabase local port allocation reproduced in Section 9.1.9
|
|
12438
12429
|
- `apps/nextblock/proxy.ts` — Security header set (Section 9.1.12), prefetch priority mapping (Section 9.1.13), CSP nonce, structured cache observability log schema
|
|
12439
12430
|
- `apps/nextblock/app/layout.tsx` — `PUBLIC_LAYOUT_REVALIDATE_SECONDS` constant reproduced in SLA ledger
|