@percepta/create 3.0.1 → 3.1.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.
Files changed (47) hide show
  1. package/README.md +16 -9
  2. package/dist/{chunk-GEVZERMP.js → chunk-CG7IJSB4.js} +33 -2
  3. package/dist/{chunk-R4FWPE4A.js → chunk-DCM7JOSC.js} +2 -2
  4. package/dist/index.js +281 -82
  5. package/dist/{init-Z4VGBHAK.js → init-XDWSYHYK.js} +1 -1
  6. package/dist/{status-MITGDLTT.js → status-BTHGN6QH.js} +1 -1
  7. package/dist/{sync-J4SFZHDX.js → sync-3Q27L7XZ.js} +1 -1
  8. package/dist/{upstream-AQI7P4EU.js → upstream-C5KFAHVR.js} +1 -1
  9. package/package.json +3 -2
  10. package/templates/monorepo/gitignore.template +1 -0
  11. package/templates/webapp/.github/workflows/__APP_NAME__-ryvn-release.yaml +3 -2
  12. package/templates/webapp/AGENTS.md +8 -2
  13. package/templates/webapp/Dockerfile +0 -1
  14. package/templates/webapp/README.md +1 -0
  15. package/templates/webapp/agent-skills/database.md +1 -0
  16. package/templates/webapp/agent-skills/deploy.md +45 -32
  17. package/templates/webapp/agent-skills/oneshot.md +3 -3
  18. package/templates/webapp/deploy/README.md +32 -6
  19. package/templates/webapp/deploy/ryvn/__APP_NAME__.service.yaml +0 -2
  20. package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml +28 -31
  21. package/templates/webapp/drizzle.config.ts +15 -6
  22. package/templates/webapp/env.example.template +1 -0
  23. package/templates/webapp/eslint.config.mjs +8 -0
  24. package/templates/webapp/gitignore.template +1 -0
  25. package/templates/webapp/package.json.template +6 -6
  26. package/templates/webapp/scripts/open-ryvn-deploy-pr.ts +495 -0
  27. package/templates/webapp/scripts/seed.ts +1 -1
  28. package/templates/webapp/scripts/setup-database.ts +16 -1
  29. package/templates/webapp/scripts/start.sh +3 -2
  30. package/templates/webapp/src/app/(app)/layout.tsx +1 -5
  31. package/templates/webapp/src/app/(auth)/auth/signin/CredentialsSignInForm.tsx +11 -1
  32. package/templates/webapp/src/app/(auth)/auth/signup/CredentialsSignUpForm.tsx +113 -0
  33. package/templates/webapp/src/app/(auth)/auth/signup/page.tsx +30 -0
  34. package/templates/webapp/src/app/global-error.tsx +3 -1
  35. package/templates/webapp/src/components/FaroProvider.tsx +2 -4
  36. package/templates/webapp/src/components/form/FormItem.tsx +2 -2
  37. package/templates/webapp/src/config/getEnvConfig.ts +1 -0
  38. package/templates/webapp/src/drizzle/db.ts +5 -1
  39. package/templates/webapp/src/drizzle/migrations/0000_eager_grandmaster.sql +3 -3
  40. package/templates/webapp/src/drizzle/migrations/meta/0000_snapshot.json +7 -19
  41. package/templates/webapp/src/drizzle/searchPath.test.ts +21 -0
  42. package/templates/webapp/src/drizzle/searchPath.ts +16 -0
  43. package/templates/webapp/src/drizzle/ssl.ts +5 -0
  44. package/templates/webapp/src/lib/auth/index.ts +1 -1
  45. package/templates/webapp/src/lib/auth-client.ts +1 -1
  46. package/templates/webapp/src/services/observability/initFaro.ts +1 -1
  47. package/templates/webapp/src/styles/globals.css +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percepta/create",
3
- "version": "3.0.1",
3
+ "version": "3.1.2",
4
4
  "description": "Scaffold a new Mosaic package",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,7 +27,7 @@
27
27
  "tsup": "^8.4.0",
28
28
  "typescript": "^5.7.3",
29
29
  "vitest": "^4.0.0",
30
- "@percepta/build": "0.4.0"
30
+ "@percepta/build": "0.4.1"
31
31
  },
32
32
  "engines": {
33
33
  "node": ">=18.0.0"
@@ -47,6 +47,7 @@
47
47
  "license": "MIT",
48
48
  "scripts": {
49
49
  "build": "tsup src/index.ts --format esm --dts --clean",
50
+ "create:local": "pnpm build && node dist/index.js",
50
51
  "dev": "tsup src/index.ts --format esm --watch",
51
52
  "typecheck": "tsc --noEmit",
52
53
  "sync-template": "tsx scripts/sync-template.ts",
@@ -21,6 +21,7 @@ Thumbs.db
21
21
  .env
22
22
  .env.local
23
23
  .env.*.local
24
+ **/deploy/ryvn/*.secrets.env
24
25
 
25
26
  # Logs
26
27
  *.log
@@ -9,7 +9,7 @@ on:
9
9
  - "packages/__APP_NAME__/scripts/**"
10
10
  - "packages/__APP_NAME__/Dockerfile"
11
11
  - "packages/__APP_NAME__/package.json"
12
- - "pnpm-lock.yaml"
12
+ - "packages/__APP_NAME__/pnpm-lock.yaml"
13
13
  - ".github/workflows/__APP_NAME__-ryvn-release.yaml"
14
14
  pull_request:
15
15
  branches:
@@ -19,7 +19,7 @@ on:
19
19
  - "packages/__APP_NAME__/scripts/**"
20
20
  - "packages/__APP_NAME__/Dockerfile"
21
21
  - "packages/__APP_NAME__/package.json"
22
- - "pnpm-lock.yaml"
22
+ - "packages/__APP_NAME__/pnpm-lock.yaml"
23
23
  workflow_dispatch:
24
24
 
25
25
  env:
@@ -66,6 +66,7 @@ jobs:
66
66
  service_name: ${{ env.SERVICE_NAME }}
67
67
  version: ${{ steps.generate-tag.outputs.version }}
68
68
  build_only: ${{ !(github.ref == format('refs/heads/{0}', github.event.repository.default_branch) || steps.generate-tag.outputs.isPreview == 'true') }}
69
+ build_args: NPM_TOKEN=${{ secrets.NPM_TOKEN }}
69
70
  ryvn_client_id: ${{ secrets.RYVN_CLIENT_ID }}
70
71
  ryvn_client_secret: ${{ secrets.RYVN_CLIENT_SECRET }}
71
72
 
@@ -24,7 +24,7 @@ Next.js 15 full-stack application scaffolded from the Mosaic webapp template via
24
24
  - Logger messages must be plain string literals, not variables or templates
25
25
  - `no-process-env` is enforced — use `getEnvConfig()` from `src/config/`
26
26
  - Use `@percepta/design` components before writing custom UI
27
- - Use `AsyncContent` from `@percepta/components` for loading/error states
27
+ - For loading/error states, use local UI or add `@percepta/components` if you want `AsyncContent`
28
28
  - Tailwind CSS for all styling; icons from `lucide-react`
29
29
 
30
30
  ## Project Structure
@@ -114,10 +114,16 @@ export default [
114
114
 
115
115
  Vitest config is also available via `@percepta/build/vitest`.
116
116
 
117
- ### @percepta/components — React Utilities
117
+ ### @percepta/components — Optional React Utilities
118
118
 
119
119
  Async data handling and hooks for React Query:
120
120
 
121
+ Install this package first if you want these helpers:
122
+
123
+ ```bash
124
+ pnpm add @percepta/components
125
+ ```
126
+
121
127
  - **`AsyncContent<T>`** — renders loading spinner, error state, or children based on a React Query result. Use this for all data-fetching UI.
122
128
  - **`AsyncArrayContent<T[]>`** — same but for multiple parallel queries
123
129
  - **`ErrorContainer`** — consistent error display
@@ -45,7 +45,6 @@ ENV BASE_PATH=${BASE_PATH}
45
45
  # Copy built app from builder stage
46
46
  COPY --from=builder /app/.next/standalone ./
47
47
  COPY --from=builder /app/.next/static ./.next/static
48
- COPY --from=builder /app/public ./public
49
48
 
50
49
  # Copy scripts and source files needed for start.sh and runtime
51
50
  COPY --from=builder /app/scripts ./scripts
@@ -134,6 +134,7 @@ pnpm db:seed
134
134
  | `DATABASE_USERNAME` | Database user | `postgres` |
135
135
  | `DATABASE_PASSWORD` | Database password | `postgres` |
136
136
  | `DATABASE_NAME` | Database name | `__DB_NAME__` |
137
+ | `DATABASE_SCHEMA` | Optional Postgres schema/search path | - |
137
138
  | `DATABASE_USE_SSL` | Enable SSL | `false` |
138
139
 
139
140
  ### Security
@@ -130,6 +130,7 @@ pnpm docker:down
130
130
  | `DATABASE_USERNAME` | `postgres` | Database user |
131
131
  | `DATABASE_PASSWORD` | `postgres` | Database password |
132
132
  | `DATABASE_NAME` | `__DB_NAME__` | Database name |
133
+ | `DATABASE_SCHEMA` | - | Optional Postgres schema/search path |
133
134
  | `DATABASE_USE_SSL` | `false` | Enable SSL connections |
134
135
 
135
136
  ## Key Concepts
@@ -10,7 +10,7 @@ When this app was created with `@percepta/create`, the IaC files were generated
10
10
  - `deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml` — percepta-test installation
11
11
  - `.github/workflows/__APP_NAME__-ryvn-release.yaml` (at the repo root) — release workflow that builds the Docker image and creates a Ryvn release on push to `main`. Path filter scoped to `packages/__APP_NAME__/` so unrelated changes don't trigger builds.
12
12
 
13
- Per-app values (URLs, k8s service names, database name) are substituted at create-time. Shared platform values (Inngest, Langfuse, OTel endpoints) are baked in as literals they're stable across percepta-test apps. Three secrets stay in the Ryvn UI.
13
+ Per-app values (URLs, k8s service names, database schema) are substituted at create-time. The Better Auth and encryption secrets are written to `deploy/ryvn/percepta-test.secrets.env`, which is ignored by git and intended for Ryvn UI import. Shared platform values (Inngest and OTel endpoints) are baked in as literals because they're stable across percepta-test apps.
14
14
 
15
15
  See [`deploy/README.md`](../deploy/README.md) for the file-by-file breakdown.
16
16
 
@@ -19,51 +19,62 @@ See [`deploy/README.md`](../deploy/README.md) for the file-by-file breakdown.
19
19
  - The app repo is under the `Percepta-Core` GitHub org. If not yet, run `gh repo create Percepta-Core/__APP_NAME__ --private --source=. --push` from the monorepo root.
20
20
  - The Percepta-Core org has `RYVN_CLIENT_ID`, `RYVN_CLIENT_SECRET`, and `NPM_TOKEN` as org-level GitHub secrets (already in place).
21
21
  - The `percepta-internal-terraform` installation provides the shared PostgreSQL — already deployed on percepta-test.
22
- - The infra repo (`Percepta-Core/infra`) is checked out locally, typically at `../../infra` relative to this package.
22
+ - `git` and `gh` are installed and authenticated.
23
+ - The infra repo (`Percepta-Core/infra`) is checked out locally or can be cloned by the deploy script.
23
24
 
24
25
  ## Deploy
25
26
 
26
- ### Step 1: Open the infra PR
27
+ ### Step 1: Open the service/schema infra PR
27
28
 
28
- Copy the two scaffolded files into the infra repo and open a PR:
29
+ Run the generated deploy helper from this package directory:
29
30
 
30
31
  ```bash
31
- INFRA=../../infra # adjust to your local path
32
- NAME=__APP_NAME__
33
-
34
- cp deploy/ryvn/$NAME.service.yaml \
35
- $INFRA/ryvn/$NAME.service.yaml
32
+ pnpm deploy:percepta-test -- --phase service --yes
33
+ ```
36
34
 
37
- cp deploy/ryvn/environments/percepta-test/installations/$NAME.env.percepta-test.serviceinstallation.yaml \
38
- $INFRA/ryvn/environments/percepta-test/installations/$NAME.env.percepta-test.serviceinstallation.yaml
35
+ This script:
39
36
 
40
- cd $INFRA
41
- git checkout -b deploy/$NAME-percepta-test
42
- git add ryvn/$NAME.service.yaml ryvn/environments/percepta-test/installations/$NAME.env.percepta-test.serviceinstallation.yaml
43
- git commit -m "Add $NAME service + percepta-test installation"
44
- git push -u origin deploy/$NAME-percepta-test
45
- gh pr create --fill
46
- ```
37
+ - uses `INFRA_REPO` or `--infra <path>` when provided
38
+ - otherwise uses a sibling `../infra` checkout, cloning `Percepta-Core/infra` there if needed
39
+ - copies the Ryvn service YAML into infra
40
+ - appends a `postgresql_schema "__APP_NAME_SNAKE__"` resource to `terraform/percepta-internal/databases.tf`
41
+ - opens the first PR against `Percepta-Core/infra`
47
42
 
48
43
  Get the PR reviewed and merged.
49
44
 
50
- ### Step 2: Set the three secrets in the Ryvn UI
45
+ ### Step 2: Wait for service/schema import
51
46
 
52
- After the infra PR merges, Ryvn creates the installation. Open the Ryvn UI for the `__APP_NAME__` installation in `percepta-test` and set:
47
+ After the service/schema PR merges, wait for Ryvn GitOps to import the service. If Ryvn creates a `percepta-internal-terraform` task for the database schema, approve/apply it in Ryvn.
53
48
 
54
- | Secret | Value |
55
- |--------|-------|
56
- | `BETTER_AUTH_SECRET` | `openssl rand -base64 32` |
57
- | `ENCRYPTION_SECRET_KEY` | `openssl rand -hex 16` |
58
- | `LANGFUSE_SECRET_KEY` | from 1Password: "Percepta Test Secrets" |
49
+ ### Step 3: Create the first release
59
50
 
60
- ### Step 3: Trigger the first deploy
61
-
62
- Push to `main` in the app repo (or `gh workflow run "Build & Release __APP_NAME__"`). The release workflow builds the Docker image and creates a Ryvn release; Ryvn deploys it to percepta-test.
51
+ Push to `main` in the app repo (or `gh workflow run "Build & Release __APP_NAME__"`). The release workflow builds the Docker image and creates a Ryvn release. Do this before creating the ServiceInstallation, otherwise GitOps can fail with `ReleaseNotFound`.
63
52
 
64
53
  The workflow lives at `.github/workflows/__APP_NAME__-ryvn-release.yaml` (at the repo root, where GitHub Actions picks it up). It only fires on changes under `packages/__APP_NAME__/`, so unrelated edits to other packages in the monorepo won't trigger it.
65
54
 
66
- ### Step 4: Verify
55
+ ### Step 4: Open the installation infra PR
56
+
57
+ After the first release exists, open the installation PR:
58
+
59
+ ```bash
60
+ pnpm deploy:percepta-test -- --phase installation --yes
61
+ ```
62
+
63
+ The `--` is the pnpm argument delimiter; it passes `--phase` and `--yes` through to the deploy helper script.
64
+
65
+ Get the PR reviewed and merged. Ryvn GitOps will import the ServiceInstallation and the Staging channel should deploy the latest release.
66
+
67
+ ### Step 5: Import Ryvn secrets
68
+
69
+ After GitOps imports the installation, import this generated file in the Ryvn UI for the installation secrets:
70
+
71
+ ```bash
72
+ deploy/ryvn/percepta-test.secrets.env
73
+ ```
74
+
75
+ Also set any app-specific secrets the implementation added, such as `OPENAI_API_KEY`.
76
+
77
+ ### Step 6: Verify
67
78
 
68
79
  ```bash
69
80
  ryvn get installation __APP_NAME__ -e percepta-test
@@ -76,16 +87,18 @@ The app will be available at **https://__APP_NAME__.percepta-test.aitco.dev**.
76
87
 
77
88
  ## Troubleshooting
78
89
 
79
- - **Pod crash-looping** → secrets probably aren't set yet (Step 2). Check `ryvn logs`.
90
+ - **Auth/sign-in routes fail after install** → import `deploy/ryvn/percepta-test.secrets.env` in the Ryvn UI, then let Ryvn update/restart the installation.
91
+ - **Pod crash-looping** → check `ryvn logs`; migration or database connectivity failures are the most common fresh-deploy causes.
80
92
  - **Database connection refused** → verify `DATABASE_USE_SSL=true` and that `percepta-internal-terraform` is deployed.
93
+ - **Database schema missing** → verify the infra PR added `postgresql_schema "__APP_NAME_SNAKE__"` and Ryvn applied `percepta-internal-terraform`.
81
94
  - **Inngest can't reach the app** → `INNGEST_APP_URL` must use the k8s service name `__APP_NAME__-web-server`. The scaffolded YAML gets this right; if you renamed anything, double-check.
82
- - **Image build fails** → check `NPM_TOKEN` in the service definition is current. Build context is `packages/__APP_NAME__`.
95
+ - **Image build fails fetching @percepta packages** → check the `NPM_TOKEN` GitHub org secret. The workflow passes it as a build arg.
83
96
 
84
97
  For Ryvn CLI operations, use the `/use-ryvn` skill.
85
98
 
86
99
  ## Updating shared platform values
87
100
 
88
- The Inngest/Langfuse/OTel URLs are baked as literals in every webapp's installation YAML. If percepta-test infra ever changes those endpoints, update them with a single grep across the infra repo:
101
+ The Inngest and OTel URLs are baked as literals in every webapp's installation YAML. If percepta-test infra ever changes those endpoints, update them with a single grep across the infra repo:
89
102
 
90
103
  ```bash
91
104
  grep -rl "inngest.percepta-test.svc.cluster.local:8288" ryvn/environments/percepta-test/installations/
@@ -122,7 +122,7 @@ If it fails, fix the errors before moving to the next chunk. Do not accumulate b
122
122
  ### Implementation Rules
123
123
 
124
124
  - **Use `@percepta/design` components.** Do not write custom UI for things that exist in the design system (Button, Dialog, Table, Card, Input, etc.). Read `node_modules/@percepta/design/dist/src/index.d.ts` to see what's available.
125
- - **Use `AsyncContent` for loading states.** Every data-fetching UI should use `AsyncContent` from `@percepta/components`.
125
+ - **Use robust loading states.** `@percepta/components` is optional; add it first if you want `AsyncContent`.
126
126
  - **Use `getEnvConfig()` for env vars.** Never use `process.env` directly.
127
127
  - **Use `getLogger()` for logging.** Never use `console.log`. Use safe/unsafe field separation.
128
128
  - **Follow the singleton pattern** for new services. Follow the existing `DatabaseService` singleton pattern in the codebase.
@@ -179,8 +179,8 @@ git init
179
179
  git add -A
180
180
  git commit -m "Initial implementation of <app-name>"
181
181
 
182
- # Create the repo under percepta-ai org
183
- gh repo create percepta-ai/<app-name> --private --source=. --push
182
+ # Create the repo under the Percepta-Core org
183
+ gh repo create Percepta-Core/<app-name> --private --source=. --push
184
184
  ```
185
185
 
186
186
  If `gh` is not authenticated, tell the user to run `gh auth login` and then continue.
@@ -12,21 +12,47 @@ deploy/
12
12
  └── __APP_NAME__.env.percepta-test.serviceinstallation.yaml # percepta-test installation
13
13
  ```
14
14
 
15
- These files are pre-filled with all values needed to deploy to `https://__APP_NAME__.percepta-test.aitco.dev`. The only manual steps are: open a PR in `Percepta-Core/infra` to copy them in, and set three secrets in the Ryvn UI.
15
+ These files are pre-filled with all base values needed to deploy to `https://__APP_NAME__.percepta-test.aitco.dev`. The generated deploy helper opens the required `Percepta-Core/infra` PRs in two phases.
16
16
 
17
17
  ## Deploying
18
18
 
19
- Tell Claude "deploy this app to percepta-test" — it'll follow [`agent-skills/deploy.md`](../agent-skills/deploy.md), which walks through copying these files into the infra repo, opening the PR, and the manual Ryvn UI step.
19
+ Tell Claude "deploy this app to percepta-test" — it'll follow [`agent-skills/deploy.md`](../agent-skills/deploy.md), which runs the generated PR helper and then verifies Ryvn.
20
20
 
21
21
  ## What's in these files
22
22
 
23
- **`__APP_NAME__.service.yaml`** — tells Ryvn how to build the Docker image. Points at `Percepta-Core/__APP_NAME__` (change the repo if you've named the GitHub repo differently). The `NPM_TOKEN` build arg is a read-only npm token shared across all Percepta apps for installing `@percepta/*` packages — it's not a secret.
23
+ **`__APP_NAME__.service.yaml`** — tells Ryvn how to build the Docker image. Points at `Percepta-Core/__APP_NAME__` (change the repo if you've named the GitHub repo differently). The release workflow passes `NPM_TOKEN` as a build arg from GitHub org secrets.
24
24
 
25
25
  **`__APP_NAME__.env.percepta-test.serviceinstallation.yaml`** — configures the deployment on `percepta-test`. Three categories of values are baked in:
26
26
 
27
- 1. **Per-app values** that vary by app name (URLs, k8s service names) — substituted at create-time.
28
- 2. **Shared platform values** (Inngest, Langfuse, OTel endpoints) — copied as literals from the `tc-emo` reference installation. These are stable across percepta-test apps.
29
- 3. **Secrets** (`BETTER_AUTH_SECRET`, `ENCRYPTION_SECRET_KEY`, `LANGFUSE_SECRET_KEY`) declared in the YAML, value entered once in the Ryvn UI.
27
+ 1. **Per-app values** that vary by app name (URLs, k8s service names, database schema) — substituted at create-time.
28
+ 2. **Shared platform values** (Inngest and OTel endpoints) — copied as literals from existing percepta-test installations. These are stable across percepta-test apps.
29
+ 3. **Database wiring** points at the shared `demos` database and a per-app schema created by the infra PR.
30
+
31
+ **`percepta-test.secrets.env`** — generated locally and ignored by git. Import it in the Ryvn UI for `BETTER_AUTH_SECRET` and `ENCRYPTION_SECRET_KEY`; deployment secret values are intentionally not committed to GitOps IaC.
32
+
33
+ ## Deployment order
34
+
35
+ Use two infra PRs. The Service must exist before the first release can be created, and the first release must exist before the ServiceInstallation can be imported.
36
+
37
+ 1. Open and merge the service/schema PR:
38
+
39
+ ```bash
40
+ pnpm deploy:percepta-test -- --phase service --yes
41
+ ```
42
+
43
+ 2. Wait for GitOps to import the service. If the schema change creates a `percepta-internal-terraform` task in Ryvn, approve/apply it.
44
+
45
+ 3. Push the app to `main` or run the release workflow so Ryvn has a first release for `__APP_NAME__`.
46
+
47
+ 4. Open and merge the installation PR:
48
+
49
+ ```bash
50
+ pnpm deploy:percepta-test -- --phase installation --yes
51
+ ```
52
+
53
+ 5. After GitOps imports the installation, import `deploy/ryvn/percepta-test.secrets.env` into the Ryvn UI for the `__APP_NAME__` installation secrets.
54
+
55
+ The `--` is the pnpm argument delimiter; it passes the flags after it through to `scripts/open-ryvn-deploy-pr.ts`.
30
56
 
31
57
  ## Repo layout note
32
58
 
@@ -5,7 +5,5 @@ spec:
5
5
  type: server
6
6
  repo: Percepta-Core/__APP_NAME__
7
7
  build:
8
- args:
9
- NPM_TOKEN: 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
10
8
  context: packages/__APP_NAME__
11
9
  dockerfile: packages/__APP_NAME__/Dockerfile
@@ -10,8 +10,23 @@ spec:
10
10
  service:
11
11
  port: 3000
12
12
 
13
+ startupEnabled: true
14
+ startupProbe:
15
+ httpGet:
16
+ path: /api/healthz
17
+ port: 3000
18
+ failureThreshold: 30
19
+ periodSeconds: 10
13
20
  livenessEnabled: true
21
+ livenessProbe:
22
+ httpGet:
23
+ path: /api/healthz
24
+ port: 3000
14
25
  readinessEnabled: true
26
+ readinessProbe:
27
+ httpGet:
28
+ path: /api/readyz
29
+ port: 3000
15
30
 
16
31
  resources:
17
32
  requests:
@@ -38,29 +53,33 @@ spec:
38
53
  - __APP_NAME__.percepta-test.aitco.dev
39
54
 
40
55
  env:
41
- # Database (shared percepta-test RDS, provisioned by percepta-internal-terraform)
56
+ # Database shared `demos` DB on the percepta-internal Postgres instance.
57
+ # Tables live under a per-app schema created by the infra PR. DATABASE_SCHEMA
58
+ # pins the connection search_path so Drizzle migrations + queries land there.
42
59
  - name: DATABASE_HOST
43
60
  valueFrom:
44
61
  secretKeyRef:
45
- name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.postgresql_secret_name }}"
62
+ name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.percepta_internal_postgresql_secret_name }}"
46
63
  key: host
47
64
  - name: DATABASE_PORT
48
65
  valueFrom:
49
66
  secretKeyRef:
50
- name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.postgresql_secret_name }}"
67
+ name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.percepta_internal_postgresql_secret_name }}"
51
68
  key: port
52
69
  - name: DATABASE_USERNAME
53
70
  valueFrom:
54
71
  secretKeyRef:
55
- name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.postgresql_secret_name }}"
72
+ name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.percepta_internal_postgresql_secret_name }}"
56
73
  key: username
57
74
  - name: DATABASE_PASSWORD
58
75
  valueFrom:
59
76
  secretKeyRef:
60
- name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.postgresql_secret_name }}"
77
+ name: "{{ .ryvn.installations.percepta_internal_terraform.outputs.percepta_internal_postgresql_secret_name }}"
61
78
  key: password
62
79
  - name: DATABASE_NAME
63
- value: "__DB_NAME__"
80
+ value: "demos"
81
+ - name: DATABASE_SCHEMA
82
+ value: "__APP_NAME_SNAKE__"
64
83
  - name: DATABASE_USE_SSL
65
84
  value: "true"
66
85
 
@@ -74,14 +93,9 @@ spec:
74
93
  value: https://__APP_NAME__.percepta-test.aitco.dev
75
94
  - key: BETTER_AUTH_URL
76
95
  value: https://__APP_NAME__.percepta-test.aitco.dev
77
-
78
- # Auth generated random, set in Ryvn UI (openssl rand -base64 32)
79
- - key: BETTER_AUTH_SECRET
80
- isSecret: true
81
-
82
- # Encryption — generated random, set in Ryvn UI (openssl rand -hex 16)
83
- - key: ENCRYPTION_SECRET_KEY
84
- isSecret: true
96
+ # Import BETTER_AUTH_SECRET and ENCRYPTION_SECRET_KEY from
97
+ # deploy/ryvn/percepta-test.secrets.env in the Ryvn UI after the installation
98
+ # exists. Secret values are intentionally not declared in GitOps IaC.
85
99
 
86
100
  # Inngest (shared percepta-test instance)
87
101
  - key: INNGEST_BASE_URL
@@ -95,14 +109,6 @@ spec:
95
109
  - key: INNGEST_SERVE_HOST
96
110
  value: http://__APP_NAME__-web-server.percepta-test.svc.cluster.local:3000/api/inngest
97
111
 
98
- # Langfuse (shared percepta-test instance) — secret key set in Ryvn UI from 1Password
99
- - key: LANGFUSE_BASE_URL
100
- value: https://percepta-test.aitco.dev/evals
101
- - key: LANGFUSE_PUBLIC_KEY
102
- value: pk-lf-cc45f2c9-5286-4966-849b-42fd45059390
103
- - key: LANGFUSE_SECRET_KEY
104
- isSecret: true
105
-
106
112
  # OpenTelemetry
107
113
  - key: OTEL_METRICS_EXPORTER_OTLP_ENDPOINT
108
114
  value: http://otel-collector-opentelemetry-collector.percepta-test.svc.cluster.local:4318/v1/metrics
@@ -110,12 +116,3 @@ spec:
110
116
  value: "60000"
111
117
  - key: LOG_LEVEL
112
118
  value: debug
113
-
114
- # Set the values for these in the Ryvn UI after the infra PR merges:
115
- # BETTER_AUTH_SECRET — generate: openssl rand -base64 32
116
- # ENCRYPTION_SECRET_KEY — generate: openssl rand -hex 16
117
- # LANGFUSE_SECRET_KEY — copy from 1Password "Percepta Test Secrets"
118
- secrets:
119
- - name: BETTER_AUTH_SECRET
120
- - name: ENCRYPTION_SECRET_KEY
121
- - name: LANGFUSE_SECRET_KEY
@@ -1,6 +1,7 @@
1
1
  import { loadEnvConfig } from "@next/env";
2
2
  import type { Config } from "drizzle-kit";
3
3
  import { getEnvConfig } from "./src/config/getEnvConfig";
4
+ import { getPgSearchPathOption } from "./src/drizzle/searchPath";
4
5
 
5
6
  loadEnvConfig(process.cwd());
6
7
 
@@ -10,20 +11,28 @@ const {
10
11
  DATABASE_USERNAME: user,
11
12
  DATABASE_PASSWORD: password,
12
13
  DATABASE_NAME: database,
14
+ DATABASE_SCHEMA: databaseSchema,
13
15
  DATABASE_USE_SSL: useSSL,
14
16
  } = getEnvConfig();
15
17
 
18
+ const schemaFilter = databaseSchema?.trim() || undefined;
19
+ const searchPathOption = getPgSearchPathOption(schemaFilter);
20
+ const connectionParams = new URLSearchParams();
21
+ if (useSSL) connectionParams.set("sslmode", "require");
22
+ if (searchPathOption) connectionParams.set("options", searchPathOption);
23
+
24
+ const connectionString =
25
+ `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}` +
26
+ `@${host}:${port}/${encodeURIComponent(database)}` +
27
+ (connectionParams.size > 0 ? `?${connectionParams.toString()}` : "");
28
+
16
29
  const config: Config = {
17
30
  schema: "./src/drizzle/schema",
18
31
  out: "./src/drizzle/migrations",
19
32
  dialect: "postgresql",
33
+ ...(schemaFilter ? { schemaFilter: [schemaFilter] } : {}),
20
34
  dbCredentials: {
21
- host,
22
- port,
23
- user,
24
- password,
25
- database,
26
- ssl: useSSL ? "require" : false,
35
+ url: connectionString,
27
36
  },
28
37
  };
29
38
 
@@ -8,6 +8,7 @@ DATABASE_PORT=5434
8
8
  DATABASE_USERNAME=postgres
9
9
  DATABASE_PASSWORD=postgres
10
10
  DATABASE_NAME=__DB_NAME__
11
+ # DATABASE_SCHEMA=
11
12
  DATABASE_USE_SSL=false
12
13
 
13
14
  # Authentication (Better Auth)
@@ -11,6 +11,7 @@ export default [
11
11
  {
12
12
  ignores: [
13
13
  "pnpm-lock.yaml",
14
+ "package.json",
14
15
  ".next/**",
15
16
  "next-env.d.ts",
16
17
  "public/**",
@@ -24,6 +25,7 @@ export default [
24
25
  rules: {
25
26
  ...nextPlugin.configs.recommended.rules,
26
27
  ...nextPlugin.configs["core-web-vitals"].rules,
28
+ "react/react-in-jsx-scope": "off",
27
29
  },
28
30
  },
29
31
  {
@@ -49,4 +51,10 @@ export default [
49
51
  "n/no-process-env": "error",
50
52
  },
51
53
  },
54
+ {
55
+ files: ["src/config/clientEnvConfig.ts"],
56
+ rules: {
57
+ "n/no-process-env": "off",
58
+ },
59
+ },
52
60
  ];
@@ -33,6 +33,7 @@ yarn-error.log*
33
33
  # env files (can opt-in for committing if needed)
34
34
  .env*
35
35
  !.env.example
36
+ deploy/ryvn/*.secrets.env
36
37
 
37
38
  # vercel
38
39
  .vercel
@@ -21,6 +21,7 @@
21
21
  "db:studio": "drizzle-kit studio",
22
22
  "db:create-user": "tsx ./scripts/create-user.ts",
23
23
  "db:seed": "tsx ./scripts/seed.ts",
24
+ "deploy:percepta-test": "tsx ./scripts/open-ryvn-deploy-pr.ts",
24
25
  "test": "vitest run",
25
26
  "test:watch": "vitest"
26
27
  },
@@ -47,11 +48,10 @@
47
48
  "@opentelemetry/api": "^1.9.0",
48
49
  "@opentelemetry/auto-instrumentations-node": "^0.62.1",
49
50
  "@opentelemetry/sdk-node": "^0.203.0",
50
- "@percepta/design": "^0.1.6",
51
- "@percepta/components": "^0.0.6",
52
- "@percepta/logger": "^0.0.4",
53
- "@percepta/next-utils": "^0.1.0",
54
- "@percepta/utils": "^0.1.5",
51
+ "@percepta/design": "0.3.2",
52
+ "@percepta/logger": "0.0.6",
53
+ "@percepta/next-utils": "0.1.0",
54
+ "@percepta/utils": "0.1.10",
55
55
  "@radix-ui/react-slot": "^1.2.3",
56
56
  "@tanstack/react-query": "^5.81.5",
57
57
  "@tanstack/react-virtual": "^3.13.12",
@@ -95,7 +95,7 @@
95
95
  },
96
96
  "devDependencies": {
97
97
  "@next/eslint-plugin-next": "^15.3.5",
98
- "@percepta/build": "^0.1.3",
98
+ "@percepta/build": "0.4.0",
99
99
  "@tailwindcss/postcss": "^4.1.11",
100
100
  "@types/formidable": "^3.4.5",
101
101
  "@types/he": "^1.2.3",