@percepta/create 3.1.0 → 3.1.3
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 +15 -10
- package/dist/{chunk-7NPWSTCY.js → chunk-CO3YWUD6.js} +31 -2
- package/dist/{chunk-WMJT7CB5.js → chunk-V5EJIUBJ.js} +5 -2
- package/dist/index.js +93 -73
- package/dist/{init-NP6GRXLL.js → init-EQZ2TCSJ.js} +2 -2
- package/dist/{status-BTHGN6QH.js → status-QW5TQDYY.js} +1 -1
- package/dist/{sync-3Q27L7XZ.js → sync-RLBZDOFB.js} +1 -1
- package/dist/{upstream-C5KFAHVR.js → upstream-TQFVPMEG.js} +1 -1
- package/package.json +3 -2
- package/templates/monorepo/.dockerignore +18 -0
- package/templates/monorepo/gitignore.template +1 -0
- package/templates/webapp/.github/workflows/__APP_NAME__-ryvn-release.yaml +6 -2
- package/templates/webapp/.github/workflows/__APP_NAME__-terraform-ryvn-release.yaml +98 -0
- package/templates/webapp/AGENTS.md +17 -5
- package/templates/webapp/Dockerfile +16 -7
- package/templates/webapp/README.md +64 -2
- package/templates/webapp/agent-skills/deploy.md +50 -51
- package/templates/webapp/agent-skills/inngest.md +4 -4
- package/templates/webapp/agent-skills/langfuse.md +15 -14
- package/templates/webapp/agent-skills/llm.md +59 -0
- package/templates/webapp/agent-skills/oneshot.md +14 -1
- package/templates/webapp/agent-skills/ryvn.md +1 -1
- package/templates/webapp/deploy/README.md +41 -16
- package/templates/webapp/deploy/ryvn/__APP_NAME__-terraform.service.yaml +10 -0
- package/templates/webapp/deploy/ryvn/__APP_NAME__.service.yaml +2 -2
- package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__-terraform.env.percepta-test.serviceinstallation.yaml +11 -0
- package/templates/webapp/deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml +60 -11
- package/templates/webapp/env.example.template +20 -2
- package/templates/webapp/eslint.config.mjs +7 -0
- package/templates/webapp/gitignore.template +1 -0
- package/templates/webapp/next.config.ts +9 -0
- package/templates/webapp/package.json.template +6 -2
- package/templates/webapp/scripts/deploy-percepta-test.ts +837 -0
- package/templates/webapp/scripts/migrate.ts +3 -0
- package/templates/webapp/scripts/open-ryvn-deploy-pr.ts +152 -32
- package/templates/webapp/scripts/seed.ts +1 -1
- package/templates/webapp/scripts/setup-database.ts +2 -1
- package/templates/webapp/scripts/start.sh +3 -2
- package/templates/webapp/scripts/with-local-env.ts +75 -0
- package/templates/webapp/src/app/(app)/layout.tsx +1 -5
- package/templates/webapp/src/app/(auth)/auth/signin/CredentialsSignInForm.tsx +11 -1
- package/templates/webapp/src/app/(auth)/auth/signup/CredentialsSignUpForm.tsx +113 -0
- package/templates/webapp/src/app/(auth)/auth/signup/page.tsx +30 -0
- package/templates/webapp/src/app/global-error.tsx +1 -1
- package/templates/webapp/src/components/FaroProvider.tsx +2 -4
- package/templates/webapp/src/components/form/FormItem.tsx +2 -2
- package/templates/webapp/src/config/getEnvConfig.ts +14 -0
- package/templates/webapp/src/drizzle/db.ts +2 -1
- package/templates/webapp/src/drizzle/migrations/0000_eager_grandmaster.sql +3 -3
- package/templates/webapp/src/drizzle/migrations/meta/0000_snapshot.json +7 -19
- package/templates/webapp/src/drizzle/ssl.ts +5 -0
- package/templates/webapp/src/instrumentation.ts +102 -10
- package/templates/webapp/src/lib/auth/index.ts +1 -1
- package/templates/webapp/src/lib/auth-client.ts +1 -1
- package/templates/webapp/src/services/llm/LLMService.ts +88 -0
- package/templates/webapp/src/services/llm/LlmProviderService.ts +85 -0
- package/templates/webapp/src/services/observability/initFaro.ts +1 -1
- package/templates/webapp/terraform/schema/main.tf +4 -0
- package/templates/webapp/terraform/schema/outputs.tf +9 -0
- package/templates/webapp/terraform/schema/variables.tf +19 -0
- package/templates/webapp/terraform/schema/versions.tf +38 -0
- package/templates/webapp/.github/workflows/__APP_NAME__-terraform.yml +0 -28
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: Build & Release __APP_NAME__-terraform
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- "main"
|
|
7
|
+
paths:
|
|
8
|
+
- "packages/__APP_NAME__/terraform/schema/**"
|
|
9
|
+
- ".github/workflows/__APP_NAME__-terraform-ryvn-release.yaml"
|
|
10
|
+
pull_request:
|
|
11
|
+
branches:
|
|
12
|
+
- "main"
|
|
13
|
+
paths:
|
|
14
|
+
- "packages/__APP_NAME__/terraform/schema/**"
|
|
15
|
+
- ".github/workflows/__APP_NAME__-terraform-ryvn-release.yaml"
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
env:
|
|
19
|
+
SERVICE_NAME: __APP_NAME__-terraform
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build-and-release:
|
|
23
|
+
name: Build and Release
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
permissions:
|
|
26
|
+
contents: write
|
|
27
|
+
id-token: write
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
- name: Checkout code
|
|
31
|
+
uses: actions/checkout@v4
|
|
32
|
+
with:
|
|
33
|
+
fetch-depth: 0
|
|
34
|
+
|
|
35
|
+
- name: Install Ryvn CLI
|
|
36
|
+
uses: ryvn-technologies/install-ryvn-cli@v1.0.0
|
|
37
|
+
|
|
38
|
+
- name: Generate Release Tag
|
|
39
|
+
id: generate-tag
|
|
40
|
+
env:
|
|
41
|
+
RYVN_CLIENT_ID: ${{ secrets.RYVN_CLIENT_ID }}
|
|
42
|
+
RYVN_CLIENT_SECRET: ${{ secrets.RYVN_CLIENT_SECRET }}
|
|
43
|
+
run: |
|
|
44
|
+
tag_info=$(ryvn generate-release-tag "$SERVICE_NAME" --prefix="${SERVICE_NAME}@" -o json --default-bump-minor)
|
|
45
|
+
|
|
46
|
+
version=$(echo "$tag_info" | jq -r '.version')
|
|
47
|
+
new_tag=$(echo "$tag_info" | jq -r '.tag')
|
|
48
|
+
channel=$(echo "$tag_info" | jq -r '.channel')
|
|
49
|
+
isPreview=$(echo "$tag_info" | jq -r '.isPreview')
|
|
50
|
+
|
|
51
|
+
echo "version=$version" >> $GITHUB_OUTPUT
|
|
52
|
+
echo "new_tag=$new_tag" >> $GITHUB_OUTPUT
|
|
53
|
+
echo "channel=$channel" >> $GITHUB_OUTPUT
|
|
54
|
+
echo "isPreview=$isPreview" >> $GITHUB_OUTPUT
|
|
55
|
+
|
|
56
|
+
- name: Create Ryvn Release
|
|
57
|
+
if: |
|
|
58
|
+
!contains(github.event.head_commit.message, '[skip-release]') &&
|
|
59
|
+
!contains(github.event.pull_request.title, '[skip-release]') &&
|
|
60
|
+
(steps.generate-tag.outputs.isPreview == 'true' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|
|
61
|
+
env:
|
|
62
|
+
RYVN_CLIENT_ID: ${{ secrets.RYVN_CLIENT_ID }}
|
|
63
|
+
RYVN_CLIENT_SECRET: ${{ secrets.RYVN_CLIENT_SECRET }}
|
|
64
|
+
run: |
|
|
65
|
+
version="${{ steps.generate-tag.outputs.new_tag }}"
|
|
66
|
+
version="${version#"${SERVICE_NAME}@"}"
|
|
67
|
+
version="${version#@}"
|
|
68
|
+
channel="${{ steps.generate-tag.outputs.channel }}"
|
|
69
|
+
|
|
70
|
+
if [ -n "$channel" ] && [ "$channel" != "null" ]; then
|
|
71
|
+
ryvn create release "$SERVICE_NAME" "$version" --channel "$channel"
|
|
72
|
+
else
|
|
73
|
+
ryvn create release "$SERVICE_NAME" "$version"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
- name: Create GitHub Tag
|
|
77
|
+
if: |
|
|
78
|
+
github.ref == format('refs/heads/{0}', github.event.repository.default_branch) &&
|
|
79
|
+
!contains(github.event.head_commit.message, '[skip-release]') &&
|
|
80
|
+
!contains(github.event.pull_request.title, '[skip-release]')
|
|
81
|
+
run: |
|
|
82
|
+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
83
|
+
git config --global user.name "github-actions[bot]"
|
|
84
|
+
git tag "${{ steps.generate-tag.outputs.new_tag }}"
|
|
85
|
+
git push origin "${{ steps.generate-tag.outputs.new_tag }}"
|
|
86
|
+
|
|
87
|
+
- name: Create GitHub Release
|
|
88
|
+
if: |
|
|
89
|
+
github.ref == format('refs/heads/{0}', github.event.repository.default_branch) &&
|
|
90
|
+
!contains(github.event.head_commit.message, '[skip-release]') &&
|
|
91
|
+
!contains(github.event.pull_request.title, '[skip-release]')
|
|
92
|
+
uses: softprops/action-gh-release@v1
|
|
93
|
+
with:
|
|
94
|
+
tag_name: ${{ steps.generate-tag.outputs.new_tag }}
|
|
95
|
+
name: ${{ steps.generate-tag.outputs.new_tag }}
|
|
96
|
+
generate_release_notes: true
|
|
97
|
+
draft: false
|
|
98
|
+
prerelease: false
|
|
@@ -9,6 +9,7 @@ Next.js 15 full-stack application scaffolded from the Mosaic webapp template via
|
|
|
9
9
|
- `pnpm lint` — run ESLint
|
|
10
10
|
- `pnpm test` — run Vitest tests
|
|
11
11
|
- `pnpm docker:up` / `pnpm docker:down` — start/stop PostgreSQL
|
|
12
|
+
- `pnpm inngest:dev` — start local Inngest dev server when working on background jobs
|
|
12
13
|
- `pnpm db:generate` — generate Drizzle migrations
|
|
13
14
|
- `pnpm db:migrate` — apply migrations
|
|
14
15
|
- `pnpm db:setup-and-migrate` — create DB + migrate
|
|
@@ -17,6 +18,8 @@ Next.js 15 full-stack application scaffolded from the Mosaic webapp template via
|
|
|
17
18
|
|
|
18
19
|
**Package manager**: Always use `pnpm`, never `npm` or `yarn`.
|
|
19
20
|
|
|
21
|
+
Local development only requires Postgres by default. Run Inngest locally when a workflow needs it. Do not run a local LGTM/Langfuse stack unless you are specifically debugging telemetry; those are wired by the Ryvn environment for deploys. If local LLM calls are needed, `pnpm dev` loads shared provider keys from `~/.config/percepta/create.env` when it exists.
|
|
22
|
+
|
|
20
23
|
## Code Style
|
|
21
24
|
|
|
22
25
|
- Double quotes for strings
|
|
@@ -44,14 +47,18 @@ src/ # Application source
|
|
|
44
47
|
├── services/
|
|
45
48
|
│ ├── inngest/ # Background job definitions
|
|
46
49
|
│ ├── langfuse/ # LLM observability
|
|
50
|
+
│ ├── llm/ # LLM provider selection and call helpers
|
|
47
51
|
│ ├── logger/ # App logger setup (wraps @percepta/logger)
|
|
48
52
|
│ └── observability/ # OpenTelemetry setup
|
|
49
53
|
└── utils/ # Helpers (cn, pathEncryption, etc.)
|
|
50
54
|
|
|
51
55
|
deploy/ # Infrastructure-as-code for Ryvn deployments
|
|
52
56
|
└── ryvn/
|
|
53
|
-
├── __APP_NAME__.service.yaml # Ryvn
|
|
54
|
-
|
|
57
|
+
├── __APP_NAME__.service.yaml # Ryvn web service
|
|
58
|
+
├── __APP_NAME__-terraform.service.yaml # Ryvn schema service
|
|
59
|
+
└── environments/<env>/installations/
|
|
60
|
+
├── __APP_NAME__.env.<env>.serviceinstallation.yaml
|
|
61
|
+
└── __APP_NAME__-terraform.env.<env>.serviceinstallation.yaml
|
|
55
62
|
```
|
|
56
63
|
|
|
57
64
|
## @percepta Packages
|
|
@@ -184,6 +191,7 @@ Detailed how-to guides for each major stack component. Read the relevant guide w
|
|
|
184
191
|
| Guide | File | When to read |
|
|
185
192
|
|-------|------|-------------|
|
|
186
193
|
| Background Jobs (Inngest) | [agent-skills/inngest.md](agent-skills/inngest.md) | Adding async tasks, scheduled jobs, or agent workflows |
|
|
194
|
+
| LLM Calls | [agent-skills/llm.md](agent-skills/llm.md) | Adding backend model calls, streaming, or structured generation |
|
|
187
195
|
| LLM Observability (Langfuse) | [agent-skills/langfuse.md](agent-skills/langfuse.md) | App uses LLMs and needs trace/eval monitoring |
|
|
188
196
|
| Database (Drizzle) | [agent-skills/database.md](agent-skills/database.md) | Adding tables, writing migrations, querying data |
|
|
189
197
|
| Deployment (Ryvn) | [agent-skills/ryvn.md](agent-skills/ryvn.md) | Ryvn overview and Percepta environment context |
|
|
@@ -220,19 +228,23 @@ Better Auth configured in `src/lib/auth/`. Email/password credentials enabled by
|
|
|
220
228
|
|
|
221
229
|
Inngest for async task processing. Define functions in `src/services/inngest/`. Configure via `INNGEST_*` env vars.
|
|
222
230
|
|
|
231
|
+
### LLM Calls
|
|
232
|
+
|
|
233
|
+
Use `LLMService` from `src/services/llm/LLMService.ts` for backend model calls. It chooses the configured provider, enables AI SDK telemetry, and attaches provider/model metadata for Langfuse.
|
|
234
|
+
|
|
223
235
|
### Database
|
|
224
236
|
|
|
225
237
|
PostgreSQL with Drizzle ORM. Schema in `src/drizzle/schema/`, migrations in `src/drizzle/migrations/`. Connection managed by `src/services/DatabaseService.ts`.
|
|
226
238
|
|
|
227
239
|
### Observability
|
|
228
240
|
|
|
229
|
-
OpenTelemetry initialized in `src/instrumentation.ts`. Langfuse for LLM tracking in `src/services/langfuse
|
|
241
|
+
OpenTelemetry initialized in `src/instrumentation.ts`. Server traces and metrics export to the configured OTEL collector; platform logs are collected from stdout. Langfuse for LLM tracking in `src/services/langfuse/` activates when `LANGFUSE_*` env vars are configured, but only AI SDK spans are forwarded to Langfuse by default. Faro for frontend monitoring via `@percepta/next-utils/faro`.
|
|
230
242
|
|
|
231
243
|
## Deployment
|
|
232
244
|
|
|
233
|
-
To deploy this app to percepta-test, follow [agent-skills/deploy.md](agent-skills/deploy.md). The
|
|
245
|
+
To deploy this app to percepta-test, follow [agent-skills/deploy.md](agent-skills/deploy.md). The direct deploy helper treats percepta-test as an existing platform environment: it preflights the shared Postgres, Inngest, OTEL collector, and LGTM installations, then creates/updates this app's Ryvn services and installations.
|
|
234
246
|
|
|
235
|
-
The release CI/CD
|
|
247
|
+
The release CI/CD workflows are already included under `.github/workflows/`.
|
|
236
248
|
|
|
237
249
|
For Ryvn CLI operations, use the `/use-ryvn` skill.
|
|
238
250
|
|
|
@@ -6,6 +6,8 @@ RUN npm install -g pnpm
|
|
|
6
6
|
|
|
7
7
|
# Build stage:
|
|
8
8
|
FROM base AS builder
|
|
9
|
+
WORKDIR /repo
|
|
10
|
+
ENV CI=true
|
|
9
11
|
|
|
10
12
|
COPY . .
|
|
11
13
|
|
|
@@ -20,7 +22,7 @@ ENV BASE_PATH=${BASE_PATH}
|
|
|
20
22
|
|
|
21
23
|
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
|
22
24
|
|
|
23
|
-
RUN NODE_ENV=production NODE_OPTIONS="--max-old-space-size=4096" pnpm build
|
|
25
|
+
RUN NODE_ENV=production NODE_OPTIONS="--max-old-space-size=4096" pnpm --filter ./packages/__APP_NAME__ build
|
|
24
26
|
|
|
25
27
|
# Remove .npmrc for security (contains auth token):
|
|
26
28
|
RUN rm -f .npmrc
|
|
@@ -43,21 +45,28 @@ ENV NEXT_TELEMETRY_DISABLED=1
|
|
|
43
45
|
ENV BASE_PATH=${BASE_PATH}
|
|
44
46
|
|
|
45
47
|
# Copy built app from builder stage
|
|
46
|
-
COPY --from=builder /
|
|
47
|
-
COPY --from=builder /
|
|
48
|
+
COPY --from=builder /repo/packages/__APP_NAME__/.next/standalone ./
|
|
49
|
+
COPY --from=builder /repo/packages/__APP_NAME__/.next/static ./packages/__APP_NAME__/.next/static
|
|
48
50
|
|
|
49
51
|
# Copy scripts and source files needed for start.sh and runtime
|
|
50
|
-
COPY --from=builder /
|
|
51
|
-
COPY --from=builder /
|
|
52
|
-
COPY --from=builder /
|
|
52
|
+
COPY --from=builder /repo/package.json ./package.json
|
|
53
|
+
COPY --from=builder /repo/pnpm-lock.yaml ./pnpm-lock.yaml
|
|
54
|
+
COPY --from=builder /repo/pnpm-workspace.yaml ./pnpm-workspace.yaml
|
|
55
|
+
COPY --from=builder /repo/node_modules ./node_modules
|
|
56
|
+
COPY --from=builder /repo/packages/__APP_NAME__/package.json ./packages/__APP_NAME__/package.json
|
|
57
|
+
COPY --from=builder /repo/packages/__APP_NAME__/tsconfig.json ./packages/__APP_NAME__/tsconfig.json
|
|
58
|
+
COPY --from=builder /repo/packages/__APP_NAME__/node_modules ./packages/__APP_NAME__/node_modules
|
|
59
|
+
COPY --from=builder /repo/packages/__APP_NAME__/scripts ./packages/__APP_NAME__/scripts
|
|
60
|
+
COPY --from=builder /repo/packages/__APP_NAME__/src ./packages/__APP_NAME__/src
|
|
53
61
|
|
|
54
62
|
|
|
55
63
|
# Expose the port:
|
|
56
64
|
EXPOSE 3000
|
|
57
65
|
|
|
58
66
|
# Set correct permissions and user:
|
|
59
|
-
RUN chown -R 1000:1000 /app && chmod +x /app/scripts/start.sh
|
|
67
|
+
RUN chown -R 1000:1000 /app && chmod +x /app/packages/__APP_NAME__/scripts/start.sh
|
|
60
68
|
USER 1000
|
|
69
|
+
WORKDIR /app/packages/__APP_NAME__
|
|
61
70
|
|
|
62
71
|
# Start the application:
|
|
63
72
|
CMD ["./scripts/start.sh"]
|
|
@@ -9,7 +9,8 @@ A production-ready Next.js application with authentication, database, logging, b
|
|
|
9
9
|
- **Database** with PostgreSQL, Drizzle ORM, and migrations
|
|
10
10
|
- **Logging** with Pino and structured safe/unsafe data separation
|
|
11
11
|
- **Background Jobs** with Inngest
|
|
12
|
-
- **
|
|
12
|
+
- **LLM Calls** with a provider-backed `LLMService`
|
|
13
|
+
- **Observability** with OpenTelemetry, LGTM-compatible traces/metrics/logs, and Langfuse integration
|
|
13
14
|
- **Infrastructure** with Terraform modules for AWS (RDS, S3, IAM)
|
|
14
15
|
- **Type Safety** with TypeScript and Zod schemas
|
|
15
16
|
|
|
@@ -31,7 +32,15 @@ pnpm db:setup-and-migrate
|
|
|
31
32
|
|
|
32
33
|
Copy `.env.example` to `.env.local` and configure your environment variables.
|
|
33
34
|
|
|
34
|
-
### 4. Start
|
|
35
|
+
### 4. Start Inngest When Using Background Jobs
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pnpm inngest:dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Run this in a separate terminal when the app has Inngest functions or you want the local Inngest dashboard.
|
|
42
|
+
|
|
43
|
+
### 5. Start Development Server
|
|
35
44
|
|
|
36
45
|
```bash
|
|
37
46
|
pnpm dev
|
|
@@ -39,6 +48,16 @@ pnpm dev
|
|
|
39
48
|
|
|
40
49
|
Open [http://localhost:3000](http://localhost:3000) to see your app.
|
|
41
50
|
|
|
51
|
+
OpenTelemetry, Faro, and Langfuse are optional in local development. Leave their env vars empty unless you are actively debugging telemetry; production deploys wire server traces, metrics, logs, and shared Langfuse demo credentials into the target Ryvn environment. General HTTP and database spans go to the OTEL/LGTM pipeline; Langfuse receives only AI SDK spans by default.
|
|
52
|
+
|
|
53
|
+
If you need local LLM calls, set provider keys once in your shell profile or in `~/.config/percepta/create.env`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`pnpm dev` loads that shared file before starting Next.js, so you do not need to copy the same provider key into every generated app.
|
|
60
|
+
|
|
42
61
|
## Project Structure
|
|
43
62
|
|
|
44
63
|
```
|
|
@@ -53,6 +72,7 @@ src/
|
|
|
53
72
|
├── services/ # Business logic services
|
|
54
73
|
│ ├── inngest/ # Background job definitions
|
|
55
74
|
│ ├── langfuse/ # LLM observability
|
|
75
|
+
│ ├── llm/ # LLM provider selection and call helpers
|
|
56
76
|
│ └── logger/ # Structured logging
|
|
57
77
|
└── utils/ # Utility functions
|
|
58
78
|
```
|
|
@@ -67,6 +87,7 @@ src/
|
|
|
67
87
|
| `pnpm lint` | Run ESLint |
|
|
68
88
|
| `pnpm docker:up` | Start PostgreSQL container |
|
|
69
89
|
| `pnpm docker:down` | Stop PostgreSQL container |
|
|
90
|
+
| `pnpm inngest:dev` | Start the local Inngest dev server for this app |
|
|
70
91
|
| `pnpm db:generate` | Generate Drizzle migrations |
|
|
71
92
|
| `pnpm db:migrate` | Run database migrations |
|
|
72
93
|
| `pnpm db:setup` | Create database and user |
|
|
@@ -164,6 +185,47 @@ node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"
|
|
|
164
185
|
| `LANGFUSE_PUBLIC_KEY` | Langfuse public key |
|
|
165
186
|
| `LANGFUSE_SECRET_KEY` | Langfuse secret key |
|
|
166
187
|
|
|
188
|
+
`deploy:percepta-test` sets the shared Langfuse URL and inherits the demo project keys from the `demos-commons` Ryvn variable group.
|
|
189
|
+
|
|
190
|
+
### LLM Providers
|
|
191
|
+
|
|
192
|
+
| Variable | Description |
|
|
193
|
+
|----------|-------------|
|
|
194
|
+
| `ANTHROPIC_API_KEY` | Anthropic API key. Inherited from `demos-commons` for `percepta-test` deploys |
|
|
195
|
+
| `OPENAI_API_KEY` | OpenAI API key for local or non-demo deployments |
|
|
196
|
+
| `LLM_PROVIDER` | Optional provider override: `anthropic` or `openai` |
|
|
197
|
+
| `LLM_MODEL` | Optional model override |
|
|
198
|
+
|
|
199
|
+
Use `LLMService` for backend model calls:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { LLMService } from "@/services/llm/LLMService";
|
|
203
|
+
|
|
204
|
+
const result = await LLMService.create().generateText({
|
|
205
|
+
telemetryFunctionId: "summarize-note",
|
|
206
|
+
system: "You summarize notes for internal users.",
|
|
207
|
+
prompt: "Summarize this note...",
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
For local development, `pnpm dev` also loads `~/.config/percepta/create.env` when that file exists. Production deploys do not use that local file; they inherit provider keys from the target Ryvn environment.
|
|
212
|
+
|
|
213
|
+
### OpenTelemetry / LGTM
|
|
214
|
+
|
|
215
|
+
| Variable | Description |
|
|
216
|
+
|----------|-------------|
|
|
217
|
+
| `OTEL_SERVICE_NAME` | Service name attached to traces and metrics |
|
|
218
|
+
| `OTEL_RESOURCE_ATTRIBUTES` | Extra resource labels such as deployment environment |
|
|
219
|
+
| `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP protocol, usually `http/protobuf` |
|
|
220
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP HTTP collector endpoint |
|
|
221
|
+
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Optional trace-specific OTLP endpoint |
|
|
222
|
+
| `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` | Optional metric-specific OTLP endpoint |
|
|
223
|
+
| `OTEL_TRACES_EXPORTER` | Set to `otlp` to export server traces |
|
|
224
|
+
| `OTEL_METRICS_EXPORTER` | Set to `otlp` to export server metrics |
|
|
225
|
+
| `OTEL_METRIC_EXPORT_INTERVAL` | Metrics export interval in milliseconds |
|
|
226
|
+
|
|
227
|
+
`deploy:percepta-test` configures these for the existing percepta-test OTEL collector and LGTM stack. Application logs are written to stdout and collected by the platform collector.
|
|
228
|
+
|
|
167
229
|
## Local AWS Development
|
|
168
230
|
|
|
169
231
|
This application uses the default AWS SDK credential provider chain:
|
|
@@ -1,91 +1,90 @@
|
|
|
1
1
|
# Deploying to Percepta Test
|
|
2
2
|
|
|
3
|
-
This guide deploys __APP_TITLE__ to `https://__APP_NAME__.percepta-test.aitco.dev` using Ryvn. Tell Claude "deploy this app to percepta-test" and it
|
|
3
|
+
This guide deploys __APP_TITLE__ to `https://__APP_NAME__.percepta-test.aitco.dev` using Ryvn. Tell Claude "deploy this app to percepta-test" and it should run the direct deploy helper below.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This is the existing-environment deploy motion: `percepta-test` already owns the shared platform services, and this app is wired into them. Fresh-environment platform bootstrap is separate and should use a Ryvn blueprint or environment-specific platform rollout before app deploys run.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## What's Already Scaffolded
|
|
8
8
|
|
|
9
|
-
- `deploy/ryvn/__APP_NAME__.service.yaml` — Ryvn
|
|
10
|
-
- `deploy/ryvn/
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
- `deploy/ryvn/__APP_NAME__.service.yaml` — Ryvn server service for the web app.
|
|
10
|
+
- `deploy/ryvn/__APP_NAME__-terraform.service.yaml` — Ryvn Terraform service that creates the app's Postgres schema.
|
|
11
|
+
- `deploy/ryvn/environments/percepta-test/installations/__APP_NAME__.env.percepta-test.serviceinstallation.yaml` — web installation.
|
|
12
|
+
- `deploy/ryvn/environments/percepta-test/installations/__APP_NAME__-terraform.env.percepta-test.serviceinstallation.yaml` — schema installation.
|
|
13
|
+
- `.github/workflows/__APP_NAME__-ryvn-release.yaml` — builds the Docker image and creates the web Ryvn release.
|
|
14
|
+
- `.github/workflows/__APP_NAME__-terraform-ryvn-release.yaml` — creates the schema Terraform Ryvn release.
|
|
15
|
+
- `deploy/ryvn/percepta-test.secrets.env` — generated locally and ignored by git; patched into Ryvn by the deploy helper.
|
|
14
16
|
|
|
15
17
|
See [`deploy/README.md`](../deploy/README.md) for the file-by-file breakdown.
|
|
16
18
|
|
|
17
19
|
## Prerequisites
|
|
18
20
|
|
|
19
|
-
-
|
|
20
|
-
- The
|
|
21
|
-
- The
|
|
22
|
-
-
|
|
23
|
-
- The
|
|
21
|
+
- `git`, `gh`, and `ryvn` are installed and authenticated.
|
|
22
|
+
- The worktree is clean and committed. The helper pushes the current branch to `main` because GitHub Actions builds from GitHub.
|
|
23
|
+
- The Percepta-Core org has `RYVN_CLIENT_ID`, `RYVN_CLIENT_SECRET`, and `NPM_TOKEN` available as org-level GitHub secrets.
|
|
24
|
+
- These shared platform installations are already deployed and healthy in `percepta-test`: `percepta-internal-terraform`, `inngest-test`, `otel-collector`, `lgtm-stack-helm`, and `langfuse`.
|
|
25
|
+
- The `demos-commons` Ryvn variable group exists in `percepta-test` and provides `LANGFUSE_PUBLIC_KEY` plus sensitive `ANTHROPIC_API_KEY` and `LANGFUSE_SECRET_KEY` for shared demo LLM calls and Langfuse tracing.
|
|
24
26
|
|
|
25
27
|
## Deploy
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Run the generated deploy helper from this package directory:
|
|
29
|
+
From this package directory:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
pnpm deploy:percepta-test -- --yes
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
The helper:
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
1. Checks the existing platform installations and shared demo variable group in `percepta-test`.
|
|
38
|
+
2. Creates `Percepta-Core/__REPO_NAME__` if needed.
|
|
39
|
+
3. Pushes the current branch to `main`.
|
|
40
|
+
4. Creates or replaces the Ryvn web and schema services.
|
|
41
|
+
5. Runs the schema Terraform release workflow.
|
|
42
|
+
6. Creates or replaces the schema installation and approves the Terraform plan.
|
|
43
|
+
7. Runs the web release workflow.
|
|
44
|
+
8. Creates or replaces the web installation.
|
|
45
|
+
9. Patches `BETTER_AUTH_SECRET` and `ENCRYPTION_SECRET_KEY` from `deploy/ryvn/percepta-test.secrets.env`.
|
|
46
|
+
10. Waits for Ryvn health and checks `/api/healthz`, `/api/readyz`, and the protected app route.
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
### Step 2: Set Ryvn secrets
|
|
48
|
+
The app will be available at **https://__APP_NAME__.percepta-test.aitco.dev**.
|
|
46
49
|
|
|
47
|
-
|
|
50
|
+
## Useful Variants
|
|
48
51
|
|
|
49
52
|
```bash
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
pnpm deploy:percepta-test -- --skip-workflows --yes
|
|
54
|
+
pnpm deploy:percepta-test -- --skip-push --yes
|
|
55
|
+
pnpm deploy:percepta-test -- --timeout-minutes 30 --yes
|
|
52
56
|
```
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
Use `--skip-workflows` when the required Ryvn releases already exist. Use `--skip-push` only when the target ref is already pushed.
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
The legacy infra-PR path is still available:
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
```bash
|
|
63
|
+
pnpm deploy:percepta-test:pr -- --phase service --yes
|
|
64
|
+
pnpm deploy:percepta-test:pr -- --phase installation --yes
|
|
65
|
+
```
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
## Verify
|
|
63
68
|
|
|
64
69
|
```bash
|
|
65
70
|
ryvn get installation __APP_NAME__ -e percepta-test
|
|
66
71
|
ryvn logs __APP_NAME__ -e percepta-test
|
|
67
72
|
curl -s https://__APP_NAME__.percepta-test.aitco.dev/api/healthz
|
|
68
73
|
curl -s https://__APP_NAME__.percepta-test.aitco.dev/api/readyz
|
|
74
|
+
curl -I https://__APP_NAME__.percepta-test.aitco.dev/
|
|
69
75
|
```
|
|
70
76
|
|
|
71
|
-
The app will be available at **https://__APP_NAME__.percepta-test.aitco.dev**.
|
|
72
|
-
|
|
73
77
|
## Troubleshooting
|
|
74
78
|
|
|
75
|
-
- **
|
|
76
|
-
- **
|
|
77
|
-
- **
|
|
78
|
-
- **
|
|
79
|
-
- **
|
|
79
|
+
- **Image build fails fetching @percepta packages** → check the Percepta-Core org-level `NPM_TOKEN` secret. Do not add a repo-level token unless the org secret is unavailable.
|
|
80
|
+
- **Ryvn release already exists** → commit a new change or re-run with `--skip-workflows` if the current releases are already present.
|
|
81
|
+
- **Terraform plan needs approval** → the helper approves it when run with `--yes`; without `--yes`, approve the prompt.
|
|
82
|
+
- **Auth/sign-in routes fail after install** → verify the deploy helper patched `BETTER_AUTH_SECRET` and `ENCRYPTION_SECRET_KEY`.
|
|
83
|
+
- **Pod crash-looping** → check `ryvn logs`; migration or database connectivity failures are the most common fresh-deploy causes.
|
|
84
|
+
- **Database schema missing** → check `ryvn get installation __APP_NAME__-terraform -e percepta-test`.
|
|
85
|
+
- **Inngest can't reach the app** → `INNGEST_APP_URL` must use the k8s service name `__APP_NAME__-web-server`.
|
|
86
|
+
- **Platform preflight fails** → deploy or repair the missing shared installation first. This helper only wires apps into an existing environment.
|
|
87
|
+
- **No Langfuse traces** → verify the target environment has Langfuse deployed and that the `demos-commons` variable group has `LANGFUSE_PUBLIC_KEY` and sensitive `LANGFUSE_SECRET_KEY`.
|
|
88
|
+
- **LLM calls fail after deploy** → verify `demos-commons` has sensitive `ANTHROPIC_API_KEY` and the installation has `LLM_PROVIDER=anthropic`.
|
|
80
89
|
|
|
81
90
|
For Ryvn CLI operations, use the `/use-ryvn` skill.
|
|
82
|
-
|
|
83
|
-
## Updating shared platform values
|
|
84
|
-
|
|
85
|
-
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:
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
grep -rl "inngest.percepta-test.svc.cluster.local:8288" ryvn/environments/percepta-test/installations/
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
A future improvement would be a shared ConfigMap or Ryvn output reference; for now the scaffolded literals are the convention.
|
|
@@ -102,13 +102,13 @@ await inngest.client.send({
|
|
|
102
102
|
|
|
103
103
|
## Running Inngest Locally
|
|
104
104
|
|
|
105
|
-
### 1.
|
|
105
|
+
### 1. Start the Inngest Dev Server
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
|
-
pnpm
|
|
108
|
+
pnpm inngest:dev
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
This starts the Inngest Dev Server
|
|
111
|
+
This starts the Inngest Dev Server for `http://localhost:3000/api/inngest` with a dashboard UI.
|
|
112
112
|
|
|
113
113
|
### 2. Set environment variables
|
|
114
114
|
|
|
@@ -126,7 +126,7 @@ INNGEST_EVENT_KEY=local # any value works locally
|
|
|
126
126
|
pnpm dev
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
The Inngest Dev Server auto-discovers functions by calling the serve endpoint at `/api/inngest`. Open `
|
|
129
|
+
The Inngest Dev Server auto-discovers functions by calling the serve endpoint at `/api/inngest`. Open the dashboard URL printed by `pnpm inngest:dev` to see registered functions, trigger events manually, and inspect runs.
|
|
130
130
|
|
|
131
131
|
## Environment Variables
|
|
132
132
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Langfuse is an open-source LLM observability platform. It captures traces, spans, and generations from LLM calls so you can debug prompt behavior, monitor latency/cost, and run evaluations. Think of it as "Datadog for LLM apps."
|
|
4
4
|
|
|
5
|
-
**Our opinionated setup:** We integrate Langfuse via OpenTelemetry (OTEL), not the Langfuse SDK directly. OTEL auto-instruments the app (HTTP, DB, etc.), and Langfuse
|
|
5
|
+
**Our opinionated setup:** We integrate Langfuse via OpenTelemetry (OTEL), not the Langfuse SDK directly. OTEL auto-instruments the app (HTTP, DB, etc.), exports general traces to the environment's OTEL collector, and adds Langfuse as a span processor when `LANGFUSE_*` values are configured. This gives us unified tracing while still letting the app run when Langfuse is not available in an environment.
|
|
6
6
|
|
|
7
7
|
## When to Use Langfuse
|
|
8
8
|
|
|
@@ -18,24 +18,28 @@ Langfuse is an open-source LLM observability platform. It captures traces, spans
|
|
|
18
18
|
|
|
19
19
|
### OpenTelemetry + Langfuse Span Processor
|
|
20
20
|
|
|
21
|
-
The template uses Next.js's instrumentation hook (called on server startup) to bootstrap OTEL with Langfuse:
|
|
21
|
+
The template uses Next.js's instrumentation hook (called on server startup) to bootstrap OTEL with both the environment collector and optional Langfuse:
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
import { LangfuseSpanProcessor } from "@langfuse/otel";
|
|
25
|
-
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
25
|
+
import { NodeSDK, tracing } from "@opentelemetry/sdk-node";
|
|
26
26
|
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
|
|
27
27
|
|
|
28
28
|
const sdk = new NodeSDK({
|
|
29
|
-
spanProcessors: [
|
|
29
|
+
spanProcessors: [
|
|
30
|
+
new tracing.BatchSpanProcessor(otlpTraceExporter),
|
|
31
|
+
new LangfuseSpanProcessor({ baseUrl, publicKey, secretKey }),
|
|
32
|
+
],
|
|
30
33
|
instrumentations: [getNodeAutoInstrumentations()],
|
|
31
34
|
});
|
|
32
35
|
sdk.start();
|
|
33
36
|
```
|
|
34
37
|
|
|
35
38
|
- `getNodeAutoInstrumentations()` automatically instruments HTTP calls, database queries, and other standard Node.js operations.
|
|
36
|
-
-
|
|
39
|
+
- The OTLP span processor forwards general server traces to the environment collector.
|
|
40
|
+
- `LangfuseSpanProcessor` forwards only AI SDK spans to Langfuse when all `LANGFUSE_*` variables are set. General HTTP, DB, and server spans stay in the OTEL/LGTM pipeline and are not sent to Langfuse by default.
|
|
37
41
|
|
|
38
|
-
**You do not need to manually instrument LLM calls.**
|
|
42
|
+
**You do not need to manually instrument LLM calls.** Use `LLMService` from `src/services/llm/LLMService.ts`; it calls the Vercel AI SDK with telemetry enabled and provider/model metadata attached.
|
|
39
43
|
|
|
40
44
|
### LangfuseService (Direct API)
|
|
41
45
|
|
|
@@ -58,12 +62,9 @@ This is a singleton — `create()` returns the same instance every time. It grac
|
|
|
58
62
|
|
|
59
63
|
### Percepta's Internal Instance
|
|
60
64
|
|
|
61
|
-
Percepta runs a shared Langfuse instance.
|
|
65
|
+
Percepta runs a shared Langfuse instance. For `percepta-test` deploys, the generated Ryvn installation uses the shared demo project by inheriting `LANGFUSE_PUBLIC_KEY` and sensitive `LANGFUSE_SECRET_KEY` from the `demos-commons` variable group.
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
2. Log into the Langfuse dashboard
|
|
65
|
-
3. Go to **Settings → API Keys** and create a new key pair
|
|
66
|
-
4. You'll get a **public key** and **secret key**
|
|
67
|
+
For non-demo environments, verify the target Ryvn environment has a Langfuse installation or shared Langfuse project, then store the project keys in an environment-scoped variable group or installation secrets.
|
|
67
68
|
|
|
68
69
|
### Self-Hosted / Langfuse Cloud
|
|
69
70
|
|
|
@@ -75,10 +76,10 @@ For external projects, you can:
|
|
|
75
76
|
|
|
76
77
|
### Option 1: Use Percepta's Langfuse (recommended)
|
|
77
78
|
|
|
78
|
-
Set the keys in `.env.local`
|
|
79
|
+
Set the keys in `.env.local` if you want local traces to go to the shared instance:
|
|
79
80
|
|
|
80
81
|
```bash
|
|
81
|
-
LANGFUSE_BASE_URL=https://langfuse.
|
|
82
|
+
LANGFUSE_BASE_URL=https://langfuse.percepta-test.aitco.dev
|
|
82
83
|
LANGFUSE_PUBLIC_KEY=pk-lf-...
|
|
83
84
|
LANGFUSE_SECRET_KEY=sk-lf-...
|
|
84
85
|
```
|
|
@@ -104,7 +105,7 @@ LANGFUSE_SECRET_KEY=sk-lf-...
|
|
|
104
105
|
|
|
105
106
|
### Option 3: Skip Langfuse entirely
|
|
106
107
|
|
|
107
|
-
Simply don't set the `LANGFUSE_*` env vars. The instrumentation gracefully skips the Langfuse span processor, and `LangfuseService.isConfigured()` returns `false`. OTEL still instruments the app for general tracing.
|
|
108
|
+
Simply don't set the `LANGFUSE_*` env vars. This is the default local development path unless you are specifically debugging LLM telemetry. The instrumentation gracefully skips the Langfuse span processor, and `LangfuseService.isConfigured()` returns `false`. OTEL still instruments the app for general tracing when an OTLP collector endpoint is configured.
|
|
108
109
|
|
|
109
110
|
## Environment Variables
|
|
110
111
|
|