feat(core-analytics): scaffold @repo/core-analytics via generator
Add the `pnpm turbo gen core-package analytics` generator template and run it to scaffold the @repo/core-analytics workspace package. The package lands in placeholder state (empty barrel export) ready for the IAnalytics + NoopAnalytics implementation in the next commit. Includes: - turbo/generators/templates/core-package/analytics/ templates - turbo/generators/config.ts analytics generator registration - packages/core-analytics/ placeholder scaffold - apps/web-next/next.config.mjs transpilePackages entry Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -764,17 +764,35 @@ import noRealtimeHandlerReexport from "./rules/no-realtime-handler-reexport.js";
|
||||
},
|
||||
printAuditNextSteps,
|
||||
],
|
||||
analytics: () => [
|
||||
() => {
|
||||
assertOptionalPackageNotPresent("core-analytics");
|
||||
return "Guard passed — packages/core-analytics does not exist yet.";
|
||||
},
|
||||
...emitTemplateTree(
|
||||
"core-package/analytics",
|
||||
"packages/core-analytics",
|
||||
),
|
||||
() => {
|
||||
addToTranspilePackages(
|
||||
"apps/web-next/next.config.mjs",
|
||||
"@repo/core-analytics",
|
||||
);
|
||||
return "Added @repo/core-analytics to transpilePackages.";
|
||||
},
|
||||
printAnalyticsNextSteps,
|
||||
],
|
||||
};
|
||||
|
||||
plop.setGenerator("core-package", {
|
||||
description:
|
||||
"Scaffold an optional core package (realtime, events, trpc, ui, audit)",
|
||||
"Scaffold an optional core package (realtime, events, trpc, ui, audit, analytics)",
|
||||
prompts: [
|
||||
{
|
||||
type: "list",
|
||||
name: "name",
|
||||
message: "Which optional core package?",
|
||||
choices: ["realtime", "events", "trpc", "ui", "audit"],
|
||||
choices: ["analytics", "audit", "events", "realtime", "trpc", "ui"],
|
||||
},
|
||||
],
|
||||
actions: (answers) => {
|
||||
@@ -1475,6 +1493,30 @@ function printAuditNextSteps(): string {
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function printAnalyticsNextSteps(): string {
|
||||
return [
|
||||
"─────────────────────────────────────────────────────────────",
|
||||
"@repo/core-analytics scaffolded into packages/core-analytics/.",
|
||||
"",
|
||||
"Next steps:",
|
||||
"",
|
||||
" 1. pnpm install # link the new workspace package",
|
||||
"",
|
||||
" 2. Implement IAnalytics + NoopAnalytics in packages/core-analytics/src/",
|
||||
" (see story 01-scaffold-core-analytics-package bullet 2)",
|
||||
"",
|
||||
" 3. Add @repo/core-analytics to feature package.json files that need analytics",
|
||||
"",
|
||||
" 4. Wire IAnalytics into apps/web-next/src/server/bind-production.ts:",
|
||||
' - import { NoopAnalytics, type IAnalytics } from "@repo/core-analytics";',
|
||||
" - add analytics field to BindAllDeps and BindProductionContext",
|
||||
" - pass NoopAnalytics (or a vendor adapter) into each feature binder",
|
||||
"",
|
||||
" 5. pnpm typecheck && pnpm lint && pnpm test",
|
||||
"─────────────────────────────────────────────────────────────",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function coreUiComponentActions(a: {
|
||||
tier: "atom" | "molecule" | "organism";
|
||||
name: string;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# @repo/core-analytics
|
||||
|
||||
Optional core package providing a vendor-neutral product analytics interface. Scaffold via `pnpm turbo gen core-package analytics`.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
src/
|
||||
analytics.interface.ts # IAnalytics — track, identify, pageView, flush
|
||||
noop-analytics.ts # NoopAnalytics (default no-op implementation)
|
||||
index.ts # Barrel export
|
||||
```
|
||||
|
||||
## Design
|
||||
|
||||
`IAnalytics` exposes four methods:
|
||||
|
||||
- `track(event, attributes?)` — record a named event with optional attributes
|
||||
- `identify(user)` — associate subsequent events with a user
|
||||
- `pageView(path, attributes?)` — record a page-view event
|
||||
- `flush()` — drain any in-flight queued events (returns `Promise<void>`)
|
||||
|
||||
The interface is vendor-neutral: no third-party analytics SDK is bundled. Feature
|
||||
packages depend on `IAnalytics` only; concrete implementations (e.g. a PostHog
|
||||
or Segment adapter) are wired at DI bind time in `bind-production`.
|
||||
|
||||
`NoopAnalytics` is the default implementation — all methods are no-ops and
|
||||
`flush()` resolves immediately via `Promise.resolve()`. Use it in dev-seed
|
||||
bindings and unit tests.
|
||||
|
||||
See `docs/architecture/agent-first-workflow-and-conformance.md` for the
|
||||
dependency-injection conventions.
|
||||
@@ -0,0 +1,3 @@
|
||||
import baseConfig from "@repo/core-eslint/base";
|
||||
|
||||
export default baseConfig;
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@repo/core-analytics",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc --noEmit",
|
||||
"lint": "eslint .",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run --passWithNoTests"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@repo/core-eslint": "workspace:*",
|
||||
"@repo/core-testing": "workspace:*",
|
||||
"@repo/core-typescript": "workspace:*",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"typescript": "^5.8.0",
|
||||
"vitest": "^3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// placeholder — populated by story 01-scaffold-core-analytics-package
|
||||
export {};
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "@repo/core-typescript/base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": ["//"],
|
||||
"tags": ["core"]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import path from "node:path";
|
||||
import { mergeConfig } from "vitest/config";
|
||||
import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node";
|
||||
|
||||
export default mergeConfig(nodeVitestConfig, {
|
||||
resolve: {
|
||||
alias: { "@": path.resolve(__dirname, "./src") },
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user