@percepta/create 3.6.2 → 4.0.0
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/README.md +37 -6
- package/dist/{git-ops-C2CIjuce.js → git-ops-BD7JNnal.js} +1 -1
- package/dist/{git-ops-C2CIjuce.js.map → git-ops-BD7JNnal.js.map} +1 -1
- package/dist/github-RCIMUq70.js +131 -0
- package/dist/github-RCIMUq70.js.map +1 -0
- package/dist/index.js +68 -125
- package/dist/index.js.map +1 -1
- package/dist/{init-sI9aIrkU.js → init-COp0nGdk.js} +4 -2
- package/dist/{init-sI9aIrkU.js.map → init-COp0nGdk.js.map} +1 -1
- package/dist/manifest-CqIDnbgs.js +58 -0
- package/dist/manifest-CqIDnbgs.js.map +1 -0
- package/dist/register-app-C7ZBpAaZ.js +103 -0
- package/dist/register-app-C7ZBpAaZ.js.map +1 -0
- package/dist/register-os-blueprint-DGjBUZYa.js +90 -0
- package/dist/register-os-blueprint-DGjBUZYa.js.map +1 -0
- package/dist/{status-CKe4aKso.js → status-BXYaQ4a2.js} +3 -3
- package/dist/{status-CKe4aKso.js.map → status-BXYaQ4a2.js.map} +1 -1
- package/dist/{sync-D1vkoofl.js → sync-BayU4w1j.js} +3 -3
- package/dist/{sync-D1vkoofl.js.map → sync-BayU4w1j.js.map} +1 -1
- package/dist/template-versions-CEIP9vhl.js +35 -0
- package/dist/template-versions-CEIP9vhl.js.map +1 -0
- package/dist/{upstream-gUHLWSR1.js → upstream-CZEzLrS4.js} +3 -3
- package/dist/{upstream-gUHLWSR1.js.map → upstream-CZEzLrS4.js.map} +1 -1
- package/dist/validate-dssldJAj.js +14 -0
- package/dist/validate-dssldJAj.js.map +1 -0
- package/package.json +1 -1
- package/template-versions.json +2 -2
- package/templates/infra/os.blueprint.yaml.template +138 -0
- package/templates/library/README.md +5 -2
- package/templates/library/gitignore.template +1 -0
- package/templates/library/package.json.template +17 -13
- package/templates/library/src/index.test.ts +8 -0
- package/templates/library/tsconfig.json +1 -17
- package/templates/library/tsdown.config.ts +3 -0
- package/templates/library/vitest.config.ts +3 -0
- package/templates/monorepo/.dockerignore +1 -0
- package/templates/monorepo/.github/CODEOWNERS +67 -0
- package/templates/monorepo/.github/actions/ci/action.yml +56 -0
- package/templates/monorepo/.github/workflows/build-and-publish.yml +22 -0
- package/templates/monorepo/.github/workflows/pr-build.yml +21 -0
- package/templates/monorepo/.node-version +1 -0
- package/templates/monorepo/README.md +41 -3
- package/templates/monorepo/auth/README.md +6 -3
- package/templates/monorepo/auth/package.json +5 -7
- package/templates/monorepo/auth/src/auth.ts +0 -1
- package/templates/monorepo/auth/src/config/database.ts +1 -1
- package/templates/monorepo/auth/tsconfig.json +1 -10
- package/templates/{webapp → monorepo}/docker-compose.yml +2 -2
- package/templates/monorepo/gitignore.template +1 -0
- package/templates/monorepo/oxfmt.config.ts.template +3 -0
- package/templates/monorepo/oxlint.config.ts.template +3 -0
- package/templates/monorepo/package.json.template +22 -11
- package/templates/monorepo/scripts/setup-local-databases.mjs +183 -0
- package/templates/monorepo/turbo.json +20 -0
- package/templates/webapp/.node-version +0 -1
- package/templates/webapp/AGENTS.md +33 -35
- package/templates/webapp/README.md +34 -38
- package/templates/webapp/agent-skills/database.md +21 -21
- package/templates/webapp/agent-skills/langfuse.md +7 -7
- package/templates/webapp/agent-skills/llm.md +4 -2
- package/templates/webapp/agent-skills/oneshot.md +7 -6
- package/templates/webapp/agent-skills/ryvn.md +12 -16
- package/templates/webapp/deploy/README.md +10 -51
- package/templates/webapp/drizzle.config.ts +2 -23
- package/templates/webapp/env.example.template +8 -14
- package/templates/webapp/globals.d.ts +1 -0
- package/templates/webapp/oxfmt.config.ts.template +5 -0
- package/templates/webapp/package.json.template +18 -33
- package/templates/webapp/scripts/seed.ts +1 -1
- package/templates/webapp/scripts/start.sh +12 -16
- package/templates/webapp/src/app/global-error.tsx +1 -1
- package/templates/webapp/src/config/getEnvConfig.ts +4 -10
- package/templates/webapp/src/config/isDev.ts +0 -2
- package/templates/webapp/src/drizzle/db.ts +6 -21
- package/templates/webapp/src/lib/auth-client.ts +6 -3
- package/templates/webapp/src/startup-checks.ts +28 -7
- package/templates/webapp/tsconfig.json +1 -12
- package/templates/webapp/vitest.config.ts +3 -7
- package/templates/library/eslint.config.js +0 -10
- package/templates/monorepo/auth/scripts/setup-database.ts +0 -11
- package/templates/monorepo/eslint.config.js +0 -10
- package/templates/monorepo/tsconfig.json +0 -16
- package/templates/webapp/.github/workflows/__APP_NAME__-terraform-ryvn-release.yaml +0 -92
- package/templates/webapp/.github/workflows/ci.yml +0 -149
- package/templates/webapp/.prettierrc.mjs +0 -5
- package/templates/webapp/agent-skills/deploy.md +0 -92
- package/templates/webapp/deploy/ryvn/__APP_NAME__-terraform.service.yaml +0 -10
- package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__-terraform.env.percepta-test.serviceinstallation.yaml +0 -11
- package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml +0 -154
- package/templates/webapp/eslint.config.mjs +0 -100
- package/templates/webapp/npmrc.template +0 -4
- package/templates/webapp/terraform/README.md +0 -147
- package/templates/webapp/terraform/deploy.sh +0 -97
- package/templates/webapp/terraform/main.tf +0 -101
- package/templates/webapp/terraform/modules/cloudtrail/main.tf +0 -27
- package/templates/webapp/terraform/modules/cloudtrail/outputs.tf +0 -10
- package/templates/webapp/terraform/modules/cloudtrail/variables.tf +0 -15
- package/templates/webapp/terraform/modules/networking/main.tf +0 -118
- package/templates/webapp/terraform/modules/networking/outputs.tf +0 -38
- package/templates/webapp/terraform/modules/networking/variables.tf +0 -24
- package/templates/webapp/terraform/modules/rds/main.tf +0 -227
- package/templates/webapp/terraform/modules/rds/outputs.tf +0 -73
- package/templates/webapp/terraform/modules/rds/variables.tf +0 -61
- package/templates/webapp/terraform/modules/s3-logging/main.tf +0 -148
- package/templates/webapp/terraform/modules/s3-logging/outputs.tf +0 -10
- package/templates/webapp/terraform/modules/s3-logging/variables.tf +0 -16
- package/templates/webapp/terraform/modules/secrets/main.tf +0 -39
- package/templates/webapp/terraform/modules/secrets/outputs.tf +0 -9
- package/templates/webapp/terraform/modules/secrets/variables.tf +0 -51
- package/templates/webapp/terraform/outputs.tf +0 -102
- package/templates/webapp/terraform/providers.tf +0 -32
- package/templates/webapp/terraform/schema/main.tf +0 -4
- package/templates/webapp/terraform/schema/outputs.tf +0 -9
- package/templates/webapp/terraform/schema/variables.tf +0 -19
- package/templates/webapp/terraform/schema/versions.tf +0 -38
- package/templates/webapp/terraform/terraform.tfvars.example +0 -65
- package/templates/webapp/terraform/variables.tf +0 -129
|
@@ -142,8 +142,7 @@ Once all chunks are implemented, verify the app runs end-to-end locally.
|
|
|
142
142
|
### Step 1: Start dependencies
|
|
143
143
|
|
|
144
144
|
```bash
|
|
145
|
-
pnpm
|
|
146
|
-
pnpm db:setup-and-migrate
|
|
145
|
+
pnpm run setup
|
|
147
146
|
```
|
|
148
147
|
|
|
149
148
|
If the app uses Inngest functions, start the local Inngest dev server in a separate terminal:
|
|
@@ -192,19 +191,21 @@ git init
|
|
|
192
191
|
git add -A
|
|
193
192
|
git commit -m "Initial implementation of <app-name>"
|
|
194
193
|
|
|
195
|
-
# Create the repo
|
|
196
|
-
gh repo create
|
|
194
|
+
# Create and push the repo in the target GitHub org
|
|
195
|
+
gh repo create <org>/<app-name> --internal --source=. --push
|
|
197
196
|
```
|
|
198
197
|
|
|
199
198
|
If `gh` is not authenticated, tell the user to run `gh auth login` and then continue.
|
|
200
199
|
|
|
201
200
|
---
|
|
202
201
|
|
|
203
|
-
## Phase 6: Deploy
|
|
202
|
+
## Phase 6: Deploy (When Requested)
|
|
204
203
|
|
|
205
204
|
Only do this when the user explicitly asks to deploy.
|
|
206
205
|
|
|
207
|
-
|
|
206
|
+
Deployment is stack-specific. Confirm the target environment and use the
|
|
207
|
+
customer infra repo or deployment guide for that stack. Blueberry does not
|
|
208
|
+
generate environment-specific installation YAML.
|
|
208
209
|
|
|
209
210
|
For Ryvn CLI operations (checking status, logs, troubleshooting), use the `/use-ryvn` skill.
|
|
210
211
|
|
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
# Ryvn
|
|
1
|
+
# Ryvn
|
|
2
2
|
|
|
3
|
-
Ryvn
|
|
3
|
+
Ryvn can be used to register and release this app as a service. Blueberry does
|
|
4
|
+
not generate a target environment installation because those details are
|
|
5
|
+
customer and stack specific.
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## Generated Files
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
| `percepta-test` | Internal dev/test | `<app>.percepta-test.aitco.dev` |
|
|
9
|
+
- `deploy/ryvn/__APP_NAME__.service.yaml` declares the app service and Docker build context.
|
|
10
|
+
- `.github/workflows/__APP_NAME__-ryvn-release.yaml` builds the image and creates a Ryvn release.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
## Environment Installations
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Environment installations belong in the infra repo. A customer blueprint should
|
|
15
|
+
compose the required base infrastructure, monorepo infrastructure, app database
|
|
16
|
+
registration, runtime services, ingress, secrets, and the app service
|
|
17
|
+
installation for the target stack.
|
|
16
18
|
|
|
17
19
|
## Ryvn CLI
|
|
18
20
|
|
|
19
21
|
For all Ryvn CLI operations (checking status, viewing logs, troubleshooting, managing installations), use the **`/use-ryvn`** skill. It has comprehensive CLI reference docs and handles authentication, deployment, configuration, and operations.
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
# Quick status check
|
|
23
|
-
ryvn get installation __APP_NAME__ -e percepta-test
|
|
24
|
-
ryvn logs __APP_NAME__ -e percepta-test
|
|
25
|
-
```
|
|
@@ -1,66 +1,25 @@
|
|
|
1
1
|
# Deploy
|
|
2
2
|
|
|
3
|
-
This directory
|
|
3
|
+
This directory contains environment-neutral deployment metadata for __APP_TITLE__.
|
|
4
|
+
It intentionally does not include customer or environment installation files.
|
|
4
5
|
|
|
5
6
|
```
|
|
6
7
|
deploy/
|
|
7
8
|
└── ryvn/
|
|
8
|
-
|
|
9
|
-
├── __APP_NAME__-terraform.service.yaml
|
|
10
|
-
└── environments/
|
|
11
|
-
└── percepta-test/
|
|
12
|
-
└── installations/
|
|
13
|
-
├── __APP_NAME__.env.percepta-test.serviceinstallation.yaml
|
|
14
|
-
└── __APP_NAME__-terraform.env.percepta-test.serviceinstallation.yaml
|
|
9
|
+
└── __APP_NAME__.service.yaml
|
|
15
10
|
```
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
The `pnpm deploy:percepta-test` script delegates to the versioned `@percepta/deploy` CLI. The app owns only the Ryvn service/installation YAML and secrets env file. The helper talks directly to Ryvn: it preflights the existing platform services, creates/updates the services, runs the GitHub Actions release workflows, creates the schema installation, approves the schema Terraform plan, creates or updates app-scoped Ryvn secrets, creates the web installation, waits for health, and verifies the health and app routes.
|
|
22
|
-
|
|
23
|
-
## Deploying
|
|
24
|
-
|
|
25
|
-
Tell Claude "deploy this app to percepta-test" or run:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pnpm deploy:percepta-test -- --yes
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The helper expects a clean, committed git worktree because GitHub Actions builds from the pushed repo. It can create `Percepta-Core/__REPO_NAME__` if it does not exist yet, and it pushes the current branch to `main` before triggering releases.
|
|
12
|
+
The generated app owns its buildable service identity. The infra repo owns
|
|
13
|
+
customer blueprints, environment installations, app database registration,
|
|
14
|
+
runtime dependencies, ingress, secrets, and rollout policy.
|
|
32
15
|
|
|
33
16
|
## What's in these files
|
|
34
17
|
|
|
35
18
|
**`__APP_NAME__.service.yaml`** — Ryvn server service for the web app. It points at `Percepta-Core/__REPO_NAME__` and builds from `packages/__APP_NAME__/`.
|
|
36
19
|
|
|
37
|
-
**`__APP_NAME__-terraform.service.yaml`** — Ryvn Terraform service that owns the per-app Postgres schema in the shared `demos` database.
|
|
38
|
-
|
|
39
|
-
**`__APP_NAME__.env.percepta-test.serviceinstallation.yaml`** — web app installation for `percepta-test`. It wires the shared platform services, ingress, health probes, database connection, Inngest, OTEL/LGTM telemetry, the Langfuse base URL, and the shared demo variable group.
|
|
40
|
-
|
|
41
|
-
**`__APP_NAME__-terraform.env.percepta-test.serviceinstallation.yaml`** — schema installation for `percepta-test`.
|
|
42
|
-
|
|
43
|
-
**`percepta-test.secrets.env`** — generated locally and ignored by git. The deploy helper injects app-specific auth/encryption secrets into the Ryvn installation create manifest so the first pod starts with auth configured; shared Langfuse and LLM demo keys are inherited from a Ryvn variable group.
|
|
44
|
-
|
|
45
|
-
## Platform Wiring
|
|
46
|
-
|
|
47
|
-
`pnpm deploy:percepta-test` checks these existing `percepta-test` installations before it mutates GitHub or Ryvn app resources:
|
|
48
|
-
|
|
49
|
-
- `percepta-internal-terraform` for the shared Postgres instance.
|
|
50
|
-
- `inngest-test` for background jobs and function callbacks.
|
|
51
|
-
- `otel-collector` for trace, metric, and log collection.
|
|
52
|
-
- `lgtm-stack-helm` for Loki, Grafana, Tempo, and Mimir.
|
|
53
|
-
- `langfuse` for LLM tracing and eval observability.
|
|
54
|
-
- `demos-commons` variable group for shared demo configuration, including the Anthropic API key and Langfuse demo project keys.
|
|
55
|
-
|
|
56
|
-
The service installation sets `LANGFUSE_BASE_URL` to the shared `percepta-test` Langfuse URL, sets `LLM_PROVIDER=anthropic`, and attaches `demos-commons` for `ANTHROPIC_API_KEY`, `LANGFUSE_PUBLIC_KEY`, and sensitive `LANGFUSE_SECRET_KEY`. Individual demo apps do not need LLM or Langfuse keys in `percepta-test.secrets.env`.
|
|
57
|
-
|
|
58
20
|
## Notes
|
|
59
21
|
|
|
60
|
-
The release
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
## Adding More Environments
|
|
65
|
-
|
|
66
|
-
Copy the two `percepta-test` installation manifests to `environments/<env>/installations/`, then change the `environment:`, host, and environment-specific config.
|
|
22
|
+
The release workflow lives at the repo root under `.github/workflows/` after
|
|
23
|
+
scaffolding. It creates a Ryvn service release from the current app image.
|
|
24
|
+
Installing that release into any environment is a customer/stack-specific
|
|
25
|
+
infra concern and should be modeled in the infra repo.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as nextEnvModule from "@next/env";
|
|
2
|
-
import { getPgSearchPathOption } from "@percepta/database";
|
|
3
2
|
import type { Config } from "drizzle-kit";
|
|
4
3
|
import { getEnvConfig } from "./src/config/getEnvConfig";
|
|
5
4
|
|
|
@@ -9,34 +8,14 @@ const nextEnv =
|
|
|
9
8
|
|
|
10
9
|
nextEnv.loadEnvConfig(process.cwd());
|
|
11
10
|
|
|
12
|
-
const {
|
|
13
|
-
DATABASE_HOST: host,
|
|
14
|
-
DATABASE_PORT: port,
|
|
15
|
-
DATABASE_USERNAME: user,
|
|
16
|
-
DATABASE_PASSWORD: password,
|
|
17
|
-
DATABASE_NAME: database,
|
|
18
|
-
DATABASE_SCHEMA: databaseSchema,
|
|
19
|
-
DATABASE_USE_SSL: useSSL,
|
|
20
|
-
} = getEnvConfig();
|
|
21
|
-
|
|
22
|
-
const schemaFilter = databaseSchema?.trim() || undefined;
|
|
23
|
-
const searchPathOption = getPgSearchPathOption(schemaFilter);
|
|
24
|
-
const connectionParams = new URLSearchParams();
|
|
25
|
-
if (useSSL) connectionParams.set("sslmode", "require");
|
|
26
|
-
if (searchPathOption) connectionParams.set("options", searchPathOption);
|
|
27
|
-
|
|
28
|
-
const connectionString =
|
|
29
|
-
`postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}` +
|
|
30
|
-
`@${host}:${port}/${encodeURIComponent(database)}` +
|
|
31
|
-
(connectionParams.size > 0 ? `?${connectionParams.toString()}` : "");
|
|
11
|
+
const { DATABASE_URL: databaseUrl } = getEnvConfig();
|
|
32
12
|
|
|
33
13
|
const config: Config = {
|
|
34
14
|
schema: "./src/drizzle/schema",
|
|
35
15
|
out: "./src/drizzle/migrations",
|
|
36
16
|
dialect: "postgresql",
|
|
37
|
-
...(schemaFilter ? { schemaFilter: [schemaFilter] } : {}),
|
|
38
17
|
dbCredentials: {
|
|
39
|
-
url:
|
|
18
|
+
url: databaseUrl,
|
|
40
19
|
},
|
|
41
20
|
};
|
|
42
21
|
|
|
@@ -2,21 +2,16 @@
|
|
|
2
2
|
NODE_ENV=development
|
|
3
3
|
APP_BASE_URL=http://localhost:3000
|
|
4
4
|
|
|
5
|
-
# Database
|
|
6
|
-
|
|
7
|
-
DATABASE_PORT=5434
|
|
8
|
-
DATABASE_USERNAME=postgres
|
|
9
|
-
DATABASE_PASSWORD=postgres
|
|
10
|
-
DATABASE_NAME=__DB_NAME__
|
|
11
|
-
# DATABASE_SCHEMA=
|
|
12
|
-
DATABASE_USE_SSL=false
|
|
5
|
+
# App Database
|
|
6
|
+
DATABASE_URL=postgresql://postgres:postgres@localhost:5434/__DB_NAME__
|
|
13
7
|
|
|
14
8
|
# Authentication (Better Auth)
|
|
15
9
|
BETTER_AUTH_SECRET=generate-with-openssl-rand-base64-32
|
|
16
10
|
BETTER_AUTH_URL=http://localhost:3000
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
#
|
|
11
|
+
|
|
12
|
+
# Shared Auth Database
|
|
13
|
+
# Deployed apps should set this from the customer monorepo auth database Secret.
|
|
14
|
+
# Local development can leave it empty and use the shared auth package defaults.
|
|
20
15
|
# AUTH_DATABASE_URL=
|
|
21
16
|
|
|
22
17
|
# Security
|
|
@@ -46,9 +41,8 @@ NEXT_PUBLIC_FARO_APP_ENVIRONMENT=development
|
|
|
46
41
|
# LANGFUSE_SECRET_KEY=
|
|
47
42
|
|
|
48
43
|
# LLM providers
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# shell profile or ~/.config/percepta/create.env.
|
|
44
|
+
# For local LLM testing, set ANTHROPIC_API_KEY once in your shell profile or
|
|
45
|
+
# ~/.config/percepta/create.env.
|
|
52
46
|
# ANTHROPIC_API_KEY=
|
|
53
47
|
# OPENAI_API_KEY=
|
|
54
48
|
# LLM_PROVIDER=anthropic
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "*.css";
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "__APP_NAME__",
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
|
+
"type": "module",
|
|
5
6
|
"engines": {
|
|
6
7
|
"node": ">=18.0.0"
|
|
7
8
|
},
|
|
@@ -9,23 +10,17 @@
|
|
|
9
10
|
"dev": "tsx ./scripts/with-local-env.ts next dev --turbopack",
|
|
10
11
|
"build": "next build",
|
|
11
12
|
"start": "next start",
|
|
12
|
-
"
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
13
14
|
"setup": "pnpm --dir ../.. run setup",
|
|
14
|
-
"docker:up": "docker compose up -d --wait",
|
|
15
|
-
"docker:down": "docker compose down",
|
|
16
15
|
"access:validate": "percepta-access-control validate",
|
|
17
16
|
"access:apply-local": "pnpm --dir ../.. run access:apply-local",
|
|
18
|
-
"auth:db:
|
|
17
|
+
"auth:db:migrate": "pnpm --dir ../.. run auth:db:migrate",
|
|
19
18
|
"inngest:dev": "pnpm dlx inngest-cli@latest dev -u http://localhost:3000/api/inngest",
|
|
20
19
|
"db:generate": "percepta-db generate-migrations",
|
|
21
|
-
"db:migrate": "percepta-db migrate
|
|
22
|
-
"db:setup": "percepta-db setup
|
|
23
|
-
"db:
|
|
24
|
-
"db:setup-readonly": "percepta-db setup-readonly --database __DB_NAME__",
|
|
25
|
-
"db:studio": "pnpm db:setup-and-migrate && drizzle-kit studio",
|
|
20
|
+
"db:migrate": "percepta-db migrate",
|
|
21
|
+
"db:setup-readonly": "percepta-db setup-readonly",
|
|
22
|
+
"db:studio": "pnpm db:migrate && drizzle-kit studio",
|
|
26
23
|
"db:seed": "tsx ./scripts/seed.ts",
|
|
27
|
-
"deploy:percepta-test": "percepta-deploy percepta-test --app __APP_NAME__ --repo __REPO_NAME__",
|
|
28
|
-
"deploy:percepta-test:pr": "percepta-deploy percepta-test pr --app __APP_NAME__ --database-schema __APP_NAME_SNAKE__",
|
|
29
24
|
"test": "vitest run",
|
|
30
25
|
"test:e2e": "pnpm run setup && playwright test",
|
|
31
26
|
"test:e2e:install": "playwright install chromium",
|
|
@@ -46,20 +41,20 @@
|
|
|
46
41
|
"@grafana/faro-web-tracing": "^1.14.0",
|
|
47
42
|
"@hookform/resolvers": "^5.2.2",
|
|
48
43
|
"@mantine/hooks": "^8.3.1",
|
|
49
|
-
"@next/env": "^
|
|
44
|
+
"@next/env": "^16.2.6",
|
|
50
45
|
"@opentelemetry/api": "^1.9.0",
|
|
51
46
|
"@opentelemetry/auto-instrumentations-node": "^0.75.0",
|
|
52
47
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.217.0",
|
|
53
48
|
"@opentelemetry/sdk-node": "^0.217.0",
|
|
54
49
|
"@__REPO_NAME__/auth": "workspace:*",
|
|
55
|
-
"@percepta/access-control": "0.
|
|
56
|
-
"@percepta/ai": "0.1.0",
|
|
57
|
-
"@percepta/database": "0.1.
|
|
58
|
-
"@percepta/design": "0.4.
|
|
59
|
-
"@percepta/inngest": "0.1.0",
|
|
60
|
-
"@percepta/logger": "0.1.0",
|
|
61
|
-
"@percepta/next-utils": "0.2.
|
|
62
|
-
"@percepta/utils": "0.1.
|
|
50
|
+
"@percepta/access-control": "^1.0.0",
|
|
51
|
+
"@percepta/ai": "^0.1.0",
|
|
52
|
+
"@percepta/database": "^0.1.2",
|
|
53
|
+
"@percepta/design": "^0.4.1",
|
|
54
|
+
"@percepta/inngest": "^0.1.0",
|
|
55
|
+
"@percepta/logger": "^0.1.0",
|
|
56
|
+
"@percepta/next-utils": "^0.2.2",
|
|
57
|
+
"@percepta/utils": "^0.1.11",
|
|
63
58
|
"@radix-ui/react-slot": "^1.2.3",
|
|
64
59
|
"@tanstack/react-query": "^5.81.5",
|
|
65
60
|
"@tanstack/react-virtual": "^3.13.12",
|
|
@@ -79,7 +74,7 @@
|
|
|
79
74
|
"lodash-es": "^4.17.21",
|
|
80
75
|
"lucide-react": "^0.542.0",
|
|
81
76
|
"mime-types": "^3.0.1",
|
|
82
|
-
"next": "^
|
|
77
|
+
"next": "^16.2.6",
|
|
83
78
|
"numeral": "^2.0.6",
|
|
84
79
|
"pg": "^8.16.3",
|
|
85
80
|
"pluralize": "^8.0.0",
|
|
@@ -98,11 +93,8 @@
|
|
|
98
93
|
"zod": "^4.1.5"
|
|
99
94
|
},
|
|
100
95
|
"devDependencies": {
|
|
101
|
-
"@eslint/js": "^9.18.0",
|
|
102
|
-
"@next/eslint-plugin-next": "^15.3.5",
|
|
103
96
|
"@playwright/test": "^1.58.2",
|
|
104
|
-
"@percepta/build": "0.
|
|
105
|
-
"@percepta/deploy": "0.1.0",
|
|
97
|
+
"@percepta/build": "^1.0.0",
|
|
106
98
|
"@tailwindcss/postcss": "^4.1.11",
|
|
107
99
|
"@types/formidable": "^3.4.5",
|
|
108
100
|
"@types/he": "^1.2.3",
|
|
@@ -116,16 +108,9 @@
|
|
|
116
108
|
"@types/react-dom": "^19.0.3",
|
|
117
109
|
"@types/yargs": "^17.0.33",
|
|
118
110
|
"drizzle-kit": "^0.31.4",
|
|
119
|
-
"eslint": "^9.18.0",
|
|
120
|
-
"eslint-plugin-n": "^17.23.1",
|
|
121
|
-
"eslint-plugin-react": "^7.37.4",
|
|
122
|
-
"eslint-plugin-react-hooks": "^5.2.0",
|
|
123
|
-
"globals": "^15.14.0",
|
|
124
111
|
"husky": "^9.1.7",
|
|
125
112
|
"tailwindcss": "^4.0.12",
|
|
126
|
-
"
|
|
127
|
-
"typescript-eslint": "^8.33.0",
|
|
128
|
-
"vitest": "^3.2.1",
|
|
113
|
+
"vitest": "^4.0.0",
|
|
129
114
|
"yargs": "^17.7.2"
|
|
130
115
|
}
|
|
131
116
|
}
|
|
@@ -49,7 +49,7 @@ const SEEDED_USERS = [
|
|
|
49
49
|
|
|
50
50
|
async function main(): Promise<void> {
|
|
51
51
|
nextEnv.loadEnvConfig(process.cwd());
|
|
52
|
-
//
|
|
52
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
53
53
|
(globalThis as any).AsyncLocalStorage = AsyncLocalStorage;
|
|
54
54
|
|
|
55
55
|
const { auth } = await import("@__REPO_NAME__/auth");
|
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
# Check if database connection variables are set
|
|
2
|
-
if [ -z "$
|
|
3
|
-
echo "⚠️
|
|
4
|
-
echo "Required environment
|
|
5
|
-
echo "❌ Error: Missing required database environment variables."
|
|
1
|
+
# Check if app database connection variables are set
|
|
2
|
+
if [ -z "$DATABASE_URL" ]; then
|
|
3
|
+
echo "⚠️ App database connection not configured. Skipping migration."
|
|
4
|
+
echo "Required environment variable: DATABASE_URL"
|
|
5
|
+
echo "❌ Error: Missing required app database environment variables."
|
|
6
6
|
exit 1
|
|
7
7
|
else
|
|
8
|
-
echo "
|
|
9
|
-
echo " HOST: $DATABASE_HOST"
|
|
10
|
-
echo " USER: $DATABASE_USERNAME"
|
|
11
|
-
echo " DATABASE: $DATABASE_NAME"
|
|
12
|
-
echo " SSL: ${DATABASE_USE_SSL:-false}"
|
|
8
|
+
echo "App database configuration found."
|
|
13
9
|
fi
|
|
14
10
|
|
|
15
|
-
# Run database migrations only if database is configured
|
|
16
|
-
echo "Running database migrations..."
|
|
17
|
-
if pnpm db:
|
|
18
|
-
echo "✅
|
|
11
|
+
# Run app database migrations only if database is configured
|
|
12
|
+
echo "Running app database migrations..."
|
|
13
|
+
if pnpm db:migrate; then
|
|
14
|
+
echo "✅ App database migrations completed successfully"
|
|
19
15
|
else
|
|
20
|
-
echo "❌
|
|
21
|
-
echo "Check your database configuration and connectivity."
|
|
16
|
+
echo "❌ App database migration failed. App will not start."
|
|
17
|
+
echo "Check your app database configuration and connectivity."
|
|
22
18
|
exit 1
|
|
23
19
|
fi
|
|
24
20
|
|
|
@@ -8,7 +8,7 @@ export default function GlobalError({
|
|
|
8
8
|
reset: () => void;
|
|
9
9
|
}) {
|
|
10
10
|
try {
|
|
11
|
-
//
|
|
11
|
+
// oxlint-disable-next-line typescript/no-require-imports
|
|
12
12
|
const { faro } = require("@grafana/faro-web-sdk");
|
|
13
13
|
faro.api?.pushError(error);
|
|
14
14
|
} catch {
|
|
@@ -10,17 +10,10 @@ export const { getEnvConfig, schema: ENV_CONFIG_SCHEMA } = createEnvConfig(
|
|
|
10
10
|
// Application:
|
|
11
11
|
APP_BASE_URL: z.string().optional(),
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
DATABASE_PORT: z.coerce.number().int().default(5434),
|
|
16
|
-
DATABASE_USERNAME: z.string().default("postgres"),
|
|
17
|
-
DATABASE_PASSWORD: z.string().default("postgres"),
|
|
18
|
-
DATABASE_NAME: z.string().default("__DB_NAME__"),
|
|
19
|
-
DATABASE_SCHEMA: z.string().optional(),
|
|
20
|
-
DATABASE_USE_SSL: z
|
|
13
|
+
// App database:
|
|
14
|
+
DATABASE_URL: z
|
|
21
15
|
.string()
|
|
22
|
-
.
|
|
23
|
-
.default(false),
|
|
16
|
+
.default("postgresql://postgres:postgres@localhost:5434/__DB_NAME__"),
|
|
24
17
|
|
|
25
18
|
// AWS:
|
|
26
19
|
AWS_REGION: z.string().default("us-east-1"),
|
|
@@ -28,6 +21,7 @@ export const { getEnvConfig, schema: ENV_CONFIG_SCHEMA } = createEnvConfig(
|
|
|
28
21
|
// Authentication (Better Auth):
|
|
29
22
|
BETTER_AUTH_SECRET: z.string().optional(),
|
|
30
23
|
BETTER_AUTH_URL: z.string().default("http://localhost:3000"),
|
|
24
|
+
AUTH_DATABASE_URL: z.string().optional(),
|
|
31
25
|
|
|
32
26
|
// Inngest:
|
|
33
27
|
INNGEST_BASE_URL: z.string().optional(),
|
|
@@ -1,30 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createPgPool, readDatabaseConfig } from "@percepta/database";
|
|
2
2
|
import { type NodePgDatabase, drizzle } from "drizzle-orm/node-postgres";
|
|
3
|
-
import { Pool } from "pg";
|
|
3
|
+
import type { Pool } from "pg";
|
|
4
4
|
import { getEnvConfig } from "../config/getEnvConfig";
|
|
5
5
|
|
|
6
6
|
export const { client, db } = createDb();
|
|
7
7
|
|
|
8
8
|
function createDb(): { client: Pool; db: NodePgDatabase } {
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
DATABASE_PASSWORD: password,
|
|
14
|
-
DATABASE_NAME: database,
|
|
15
|
-
DATABASE_SCHEMA: databaseSchema,
|
|
16
|
-
DATABASE_USE_SSL: useSSL,
|
|
17
|
-
} = getEnvConfig();
|
|
18
|
-
|
|
19
|
-
const pool = new Pool({
|
|
20
|
-
host,
|
|
21
|
-
port,
|
|
22
|
-
user,
|
|
23
|
-
password,
|
|
24
|
-
database,
|
|
25
|
-
ssl: getPgSslConfig(useSSL),
|
|
26
|
-
options: getPgSearchPathOption(databaseSchema),
|
|
27
|
-
});
|
|
9
|
+
const { DATABASE_URL: databaseUrl, NODE_ENV: nodeEnv } = getEnvConfig();
|
|
10
|
+
const pool = createPgPool(
|
|
11
|
+
readDatabaseConfig({ env: { DATABASE_URL: databaseUrl, NODE_ENV: nodeEnv } }),
|
|
12
|
+
);
|
|
28
13
|
|
|
29
14
|
return { client: pool, db: drizzle(pool) };
|
|
30
15
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { BetterAuthClientOptions } from "better-auth";
|
|
1
2
|
import { adminClient } from "better-auth/client/plugins";
|
|
2
3
|
import { createAuthClient } from "better-auth/react";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const adminPlugin: ReturnType<typeof adminClient> = adminClient();
|
|
6
|
+
const options = {
|
|
7
|
+
plugins: [adminPlugin],
|
|
8
|
+
} satisfies BetterAuthClientOptions;
|
|
9
|
+
export const authClient: ReturnType<typeof createAuthClient<typeof options>> = createAuthClient(options);
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { client as authClient } from "@__REPO_NAME__/auth/db";
|
|
1
2
|
import { getEnvConfig } from "./config/getEnvConfig";
|
|
2
3
|
import { client } from "./drizzle/db";
|
|
3
4
|
import { getLogger } from "./services/logger/AppLogger";
|
|
4
5
|
|
|
5
6
|
export async function checkStartup(): Promise<boolean> {
|
|
6
|
-
return
|
|
7
|
+
return (
|
|
8
|
+
validateEnvironment() &&
|
|
9
|
+
(await validateDatabaseConnection()) &&
|
|
10
|
+
(await validateAuthDatabaseConnection())
|
|
11
|
+
);
|
|
7
12
|
}
|
|
8
13
|
|
|
9
14
|
function validateEnvironment(): boolean {
|
|
@@ -18,15 +23,31 @@ function validateEnvironment(): boolean {
|
|
|
18
23
|
|
|
19
24
|
async function validateDatabaseConnection(): Promise<boolean> {
|
|
20
25
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const timeoutPromise = new Promise((_, reject) =>
|
|
24
|
-
setTimeout(() => reject(new Error("Database check timeout")), 5000),
|
|
25
|
-
);
|
|
26
|
-
await Promise.race([dbCheckPromise, timeoutPromise]);
|
|
26
|
+
await checkDatabaseClient(client, "Database check timeout");
|
|
27
27
|
} catch {
|
|
28
28
|
getLogger().warn(undefined, "Database connection failed");
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
31
|
return true;
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
async function validateAuthDatabaseConnection(): Promise<boolean> {
|
|
35
|
+
try {
|
|
36
|
+
await checkDatabaseClient(authClient, "Auth database check timeout");
|
|
37
|
+
} catch {
|
|
38
|
+
getLogger().warn(undefined, "Auth database connection failed");
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function checkDatabaseClient(
|
|
45
|
+
databaseClient: Pick<typeof client, "query">,
|
|
46
|
+
timeoutMessage: string,
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
const dbCheckPromise = databaseClient.query("SELECT 1");
|
|
49
|
+
const timeoutPromise = new Promise((_, reject) =>
|
|
50
|
+
setTimeout(() => reject(new Error(timeoutMessage)), 5000),
|
|
51
|
+
);
|
|
52
|
+
await Promise.race([dbCheckPromise, timeoutPromise]);
|
|
53
|
+
}
|
|
@@ -1,14 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "@percepta/build/tsconfig/web"
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"declaration": false,
|
|
5
|
-
"declarationMap": false,
|
|
6
|
-
"plugins": [{ "name": "next" }],
|
|
7
|
-
"lib": ["dom", "dom.iterable", "esnext"],
|
|
8
|
-
"allowJs": true,
|
|
9
|
-
"noEmit": true,
|
|
10
|
-
"isolatedModules": true,
|
|
11
|
-
"jsx": "preserve"
|
|
12
|
-
},
|
|
13
|
-
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"]
|
|
2
|
+
"extends": "@percepta/build/tsconfig/web"
|
|
14
3
|
}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createVitestConfig } from "@percepta/build/vitest";
|
|
2
2
|
|
|
3
|
-
export default
|
|
4
|
-
|
|
5
|
-
environment: "node",
|
|
6
|
-
include: ["src/**/__tests__/**/*.test.ts"],
|
|
7
|
-
setupFiles: ["./vitest.setup.ts"],
|
|
8
|
-
},
|
|
3
|
+
export default createVitestConfig({
|
|
4
|
+
additionalSetupFiles: ["./vitest.setup.ts"],
|
|
9
5
|
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { setupAuthDatabase } from "@percepta/auth";
|
|
2
|
-
import { getAuthDatabaseConfig } from "../src/config/database";
|
|
3
|
-
|
|
4
|
-
async function main(): Promise<void> {
|
|
5
|
-
await setupAuthDatabase({ config: getAuthDatabaseConfig() });
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
void main().catch((error) => {
|
|
9
|
-
console.error("Shared auth database setup failed:", error);
|
|
10
|
-
process.exit(1);
|
|
11
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"lib": ["ES2022"],
|
|
5
|
-
"module": "NodeNext",
|
|
6
|
-
"moduleResolution": "NodeNext",
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"declarationMap": true,
|
|
13
|
-
"sourceMap": true,
|
|
14
|
-
"resolveJsonModule": true
|
|
15
|
-
}
|
|
16
|
-
}
|