Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Move analytics to drizzle #153

Merged
merged 3 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
ENV_FILE_NAME=LOCAL
VERCEL_URL=localhost:4200
PROVIDER_POSTGRES_ANALYTICS_PRISMA_URL="postgres://default:this0is0a0secret0password@localhost:5432/verceldb"
PROVIDER_POSTGRES_ANALYTICS_URL_NON_POOLING="postgres://default:this0is0a0secret0password@localhost:5432/verceldb"
PROVIDER_POSTGRES_ANALYTICS="postgres://default:this0is0a0secret0password@localhost:5432/verceldb"
PROVIDER_GITHUB_TOKEN=<Generate Github token>
PROVIDER_GITHUB_PROJECT_UPSTREAM_OWNER=PupoSDC
PROVIDER_GITHUB_PROJECT_UPSTREAM_REPO=chair-flight
Expand Down
58 changes: 31 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Built with
[`Next`](https://nextjs.org/),
[`Vitest`](https://vitest.dev/),
[`Storybook`](https://storybook.js.org/),
[`Prisma`](https://www.prisma.io/),
[`Drizzle`](https://orm.drizzle.team/),
[`Trpc`](https://trpc.io/),
[`Zustand`](https://github.com/pmndrs/zustand),
and [`MDX`](https://mdxjs.com/).
Expand Down Expand Up @@ -59,27 +59,31 @@ can and will be introduced in patch releases.

### Libs

| Name | Desc |
| -------------------------- | ----------------------------------------------------------- |
| base-env | Utility to safely access env variables |
| base-errors | Errors that can be handled in the front or in the backend |
| base-types | Base Business types used across the app |
| content-blog | Blog posts |
| content-question-bank-prep | Content bank for the interview prep module |
| content-question-bank-type | Content bank for the Type Rating module |
| content-question-bank-atpl | Content bank for the ATPL theory module |
| core-analytics | Analytics provider (currently a custom solution) |
| core-app | Business logic blocks sharable between React SPA/SSR and RN |
| core-blog | Blog posts compiler and core functions |
| core-github | Github related functionalities |
| core-schemas | Zod Schemas shared across our application (from base-types) |
| react-analytics | React hooks to interact with our analytics provider |
| react-components | Shared react (DOM) components |
| react-containers | Next.js specific components |
| react-games | Shared react (three.js) components |
| trpc-client | trpc next js specific client |
| trpc-mock | trpc mock server, for storybook and RTL tests |
| trpc-server | main trpc server. All our backend logic starts here |
| Name | Desc |
| -------------------------- | --------------------------------------------------------- |
| base-env | Utility to safely access env variables |
| base-errors | Errors that can be handled in the front or in the backend |
| base-utils | Common JS utilities |
| content-blog | Blog posts |
| content-question-bank-prep | Content bank for the interview prep module |
| content-question-bank-type | Content bank for the Type Rating module |
| content-question-bank-atpl | Content bank for the ATPL theory module |
| core-github | Github related functionalities |
| core-question-bank | Question Bank entities and functions |
| core-search | Search API entities |
| core-tests | Test related entities and functions |
| providers-analytics | Provides analytics postgres DB interactions |
| providers-blog | Blog Pages compiler and server side provider |
| providers-github | Github API provider using octokit |
| providers-question-bank | Question Bank compiler and server side provider |
| providers-search | Minisearch powered search provider |
| react-analytics | React hooks to interact with our analytics provider |
| react-components | Shared react (DOM) components |
| react-containers | Next.js specific components |
| react-games | Shared react (three.js) components |
| trpc-client | trpc next js specific client |
| trpc-mock | trpc mock server, for storybook and RTL tests |
| trpc-server | main trpc server. All our backend logic starts here |

### .env

Expand All @@ -94,16 +98,16 @@ If you create the required services remotely, you can create other env files to
point to those services. For example:

```sh
cp .env.example .env.production
cp .env.example .env.prod
```

You can then run specific configurations using the nx `-c` flag:

```sh
pnpm run dev -c production
pnpm run build -c production
pnpm run migrate -c production
pnpm run generate -c production
pnpm run dev -c prod
pnpm run build -c prod
pnpm run migrate -c prod
pnpm run generate -c prod
```

For more information on managing `.env` variables within an `nx` project you can
Expand Down
1 change: 1 addition & 0 deletions apps/next-app/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const nextConfig = {
emotion: true,
},
pageExtensions: ["page.tsx", "api.ts"],
transpilePackages: ["@mui/x-charts"],
async rewrites() {
const aboutUsRewrite = [
{
Expand Down
6 changes: 5 additions & 1 deletion apps/next-app/pages/_app.page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React, { StrictMode } from "react";
import { default as Head } from "next/head";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { AnalyticsProvider } from "@chair-flight/react/analytics";
import {
AnalyticsProvider,
AnalyticsPageLogger,
} from "@chair-flight/react/analytics";
import { ThemeProvider, Toaster } from "@chair-flight/react/components";
import { trpc } from "@chair-flight/trpc/client";
import type { AppProps } from "next/app";
Expand All @@ -16,6 +19,7 @@ const App: FunctionComponent<AppProps> = ({ Component, pageProps }) => {
return (
<StrictMode>
<AnalyticsProvider>
<AnalyticsPageLogger />
<ReactQueryDevtools position="bottom-right" />
<Head>
<title>Welcome to chair-flight!</title>
Expand Down
44 changes: 44 additions & 0 deletions apps/next-app/pages/analytics/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as fs from "node:fs/promises";
import { GlobalStyles } from "@mui/joy";
import { LineChart } from "@mui/x-charts/LineChart";
import { AppHead, BackgroundFadedImage } from "@chair-flight/react/components";
import { BlogIndex, LayoutPublic } from "@chair-flight/react/containers";
import { trpc } from "@chair-flight/trpc/client";
import { staticHandler } from "@chair-flight/trpc/server";
import type { NextPage } from "next";

const Page: NextPage = () => {
const { data = [] } = trpc.common.analytics.getDailyUsers.useQuery();

return (
<LayoutPublic background={<BackgroundFadedImage img="article" />}>
<AppHead />
<GlobalStyles
styles={(t) => ({
".MuiChartsTooltip-table": {
backgroundColor: t.vars.palette.background.surface,
},
})}
/>

<LineChart
series={[
{
data: data.map((v) => v.uniqueVisitors),
label: "Unique Visitors",
color: "primary",
},
]}
width={500}
height={300}
/>
</LayoutPublic>
);
};

export const getStaticProps = staticHandler(async ({ helper }) => {
await BlogIndex.getData({ params: {}, helper });
return { props: {} };
}, fs);

export default Page;
7 changes: 6 additions & 1 deletion apps/next-app/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
"targets": {
"dev": {
"executor": "@nx/next:server",
"dependsOn": ["^deploy", "^compile", "^generate"],
"dependsOn": ["^compile", "^migrate"],
"options": {
"port": 4200,
"buildTarget": "next-app:build",
"dev": true
},
"configurations": {
"prod": {},
"dev": {},
"local": {}
}
},
"build": {
Expand Down
5 changes: 0 additions & 5 deletions libs/core/analytics/.eslintrc.json

This file was deleted.

22 changes: 0 additions & 22 deletions libs/core/analytics/project.json

This file was deleted.

23 changes: 0 additions & 23 deletions libs/core/analytics/src/entities/page-event.ts

This file was deleted.

27 changes: 0 additions & 27 deletions libs/core/analytics/src/entities/track-event.ts

This file was deleted.

2 changes: 0 additions & 2 deletions libs/core/analytics/src/index.ts

This file was deleted.

8 changes: 0 additions & 8 deletions libs/core/analytics/tsconfig.json

This file was deleted.

11 changes: 11 additions & 0 deletions libs/providers/analytics/drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { getEnvVariableOrThrow } from "@chair-flight/base/env";
import type { Config } from "drizzle-kit";

export default {
schema: "./drizzle/schema.ts",
out: "./drizzle",
driver: "pg",
dbCredentials: {
connectionString: getEnvVariableOrThrow("PROVIDER_POSTGRES_ANALYTICS"),
},
} satisfies Config;
6 changes: 6 additions & 0 deletions libs/providers/analytics/drizzle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as schema from "./schema";
import type { NodePgDatabase } from "drizzle-orm/node-postgres";

export const analyticsSchema = schema;
export type AnalyticsSchema = typeof schema;
export type AnalyticsDb = NodePgDatabase<AnalyticsSchema>;
36 changes: 36 additions & 0 deletions libs/providers/analytics/drizzle/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { randomUUID } from "crypto";
import { sql } from "drizzle-orm";
import { pgTable, timestamp, text, integer, jsonb } from "drizzle-orm/pg-core";
import { getEnvVariableOrThrow } from "@chair-flight/base/env";

const getEnv = () => getEnvVariableOrThrow("NODE_ENV");

export const pageEvent = pgTable("PageEvent", {
id: text("id").primaryKey().notNull().$defaultFn(randomUUID),
timestamp: timestamp("timestamp")
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
environment: text("environment").notNull().$default(getEnv),
anonymousId: text("anonymousId").notNull(),
title: text("title").notNull(),
height: integer("height").notNull(),
width: integer("width").notNull(),
path: text("path").notNull(),
resolvedPath: text("resolvedPath").notNull(),
});

export const trackEvent = pgTable("TrackEvent", {
id: text("id")
.primaryKey()
.notNull()
.$defaultFn(() => randomUUID()),
timestamp: timestamp("timestamp")
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
environment: text("environment").notNull().$default(getEnv),
anonymousId: text("anonymousId").notNull(),
eventName: text("eventName").notNull(),
properties: jsonb("properties").notNull(),
path: text("path").notNull(),
resolvedPath: text("resolvedPath").notNull(),
});

This file was deleted.

This file was deleted.

Loading
Loading