Skip to content
Draft
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
2 changes: 1 addition & 1 deletion .github/workflows/dev-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
required: false
type: string
push:
branches: ["main"]
branches: ["main", "infra/*"]

permissions:
contents: read
Expand Down
2 changes: 2 additions & 0 deletions apps/app/.env.dev3
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Development environment variables for the Doenet app.
# This file is intentionally committed — all VITE_ vars are public.
VITE_DISCOURSE_URL=https://dev3-community.doenet.org/
VITE_UMAMI_SCRIPT_URL=https://umami.dev3.doenet.org/script.js
VITE_UMAMI_WEBSITE_ID=9c76c8c9-9a83-47f1-80ce-85865a0e5c0d
14 changes: 0 additions & 14 deletions apps/app/index.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
<!doctype html>
<html lang="en">
<head>
<!-- Google tag (gtag.js) -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=G-2NFXB5BB07"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());

gtag("config", "G-2NFXB5BB07");
</script>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Doenet</title>
Expand Down
3 changes: 3 additions & 0 deletions apps/app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ import { RawViewer, loader as rawViewerLoader } from "./paths/RawViewer";
import { GetInvolved } from "./paths/GetInvolved";
import { Events } from "./paths/Events";
import { QuickLinks } from "./paths/QuickLinks";
import { initializeAnalytics } from "./utils/analytics";

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -436,6 +437,8 @@ const router = createBrowserRouter([
},
]);

initializeAnalytics();

const root = createRoot(document.getElementById("root")!);
root.render(<RouterProvider router={router} />);

Expand Down
20 changes: 20 additions & 0 deletions apps/app/src/utils/analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const umamiScriptUrl = import.meta.env.VITE_UMAMI_SCRIPT_URL?.trim();
const umamiWebsiteId = import.meta.env.VITE_UMAMI_WEBSITE_ID?.trim();

export function initializeAnalytics() {
if (!umamiScriptUrl || !umamiWebsiteId) {
return;
}

if (document.querySelector('script[data-doenet-analytics="umami"]')) {
return;
}

const script = document.createElement("script");
script.defer = true;
script.src = umamiScriptUrl;
script.dataset.doenetAnalytics = "umami";
script.setAttribute("data-website-id", umamiWebsiteId);

document.head.append(script);
}
10 changes: 10 additions & 0 deletions apps/app/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// <reference types="vite/client" />

interface ImportMetaEnv {
readonly VITE_UMAMI_SCRIPT_URL?: string;
readonly VITE_UMAMI_WEBSITE_ID?: string;
}

interface ImportMeta {
readonly env: ImportMetaEnv;
}
66 changes: 66 additions & 0 deletions infra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,69 @@ To deploy changes to AWS, run the `aws-deploy` script.

To lint CloudFormation templates without deploying them, use `cfn-lint`.
https://github.com/aws-cloudformation/cfn-lint

## dev3 Umami services

The `dev3` environment now includes two additional ECS service stacks:

- `dev3-doenet-umami-db` - internal Postgres for Umami
- `dev3-doenet-umami` - public Umami app at `umami.dev3.doenet.org`

These stacks are deployed through the existing `infra\dev3.aws` stack order.

The Umami listener rule must have a **higher precedence** than the generic Doenet `/api` listener rule. In the current `dev3` params, that means Umami uses priority `1` and the generic Doenet API service uses priority `10`.

### Required SSM parameters before deploying the services

Create these Parameter Store entries in `us-east-2`:

- `/${EnvironmentName}/umami/DBPassword` - SecureString used by the Postgres container
- `/${EnvironmentName}/umami/DatabaseUrl` - SecureString used by the Umami app container
- `/${EnvironmentName}/umami/AppSecret` - SecureString used by Umami

For `dev3`, that means:

- `/dev3/umami/DBPassword`
- `/dev3/umami/DatabaseUrl`
- `/dev3/umami/AppSecret`

`DatabaseUrl` should point at the internal Postgres service. With the current `dev3` Cloud Map namespace, use:

`postgresql://umami:<password>@umami-db.dev3.doenet.internal:5432/umami`

Do not use the short host `umami-db` here; the Umami task needs the full Cloud Map hostname.

### Frontend analytics config after Umami bootstrap

Frontend Umami settings are committed in `apps/app/.env.dev3`, not stored in SSM.

The committed defaults should look like:

- `VITE_UMAMI_SCRIPT_URL=https://umami.dev3.doenet.org/script.js`
- `VITE_UMAMI_WEBSITE_ID=<website id>`

If `VITE_UMAMI_WEBSITE_ID` is blank, the `dev3` app builds without loading Umami.

### First Umami login and website setup

On a fresh Umami database, the default login is:

- username: `admin`
- password: `umami`

After the first login:

1. Change the default admin password immediately.
2. Create a new website entry for the React app.
3. Set the website domain to the app hostname you want to track in `dev3`.
4. Copy the generated website ID from Umami.
5. Update `apps/app/.env.dev3`:
- `VITE_UMAMI_SCRIPT_URL=https://umami.dev3.doenet.org/script.js`
- `VITE_UMAMI_WEBSITE_ID=<copied website id>`
6. Commit that change and redeploy the frontend so the `dev3` app build picks up the website ID.

If the default admin account is not present, Umami may not have completed its first-run database initialization. Check the Umami container logs and the database connectivity/config first.

For additional Umami setup details, see the upstream docs:

- https://umami.is/docs
138 changes: 138 additions & 0 deletions infra/cloudformation/dev3-doenet-umami-db.params
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
[
{
"ParameterKey": "RedshiftSecretArn",
"ParameterValue": "notapplicable"
},
{
"ParameterKey": "DomainNames",
"ParameterValue": "notapplicable"
},
{
"ParameterKey": "EnvironmentName",
"ParameterValue": "dev3"
},
{
"ParameterKey": "ServiceName",
"ParameterValue": "umami-db"
},
{
"ParameterKey": "S3AppBucket",
"ParameterValue": "/dev3/S3Bucket"
},
{
"ParameterKey": "CloudMapPrivateNamespace",
"ParameterValue": "/dev3/CloudMapPrivateNamespace"
},
{
"ParameterKey": "Priority",
"ParameterValue": "2"
},
{
"ParameterKey": "EcsLaunchType",
"ParameterValue": "FARGATE"
},
{
"ParameterKey": "HealthCheckUrl",
"ParameterValue": "/health"
},
{
"ParameterKey": "UseLbForService",
"ParameterValue": "false"
},
{
"ParameterKey": "InstanceType",
"ParameterValue": "t3a.small"
},
{
"ParameterKey": "ECSAMI",
"ParameterValue": "/aws/service/ecs/optimized-ami/amazon-linux/recommended/image_id"
},
{
"ParameterKey": "ImageUrl",
"ParameterValue": "postgres:15-alpine"
},
{
"ParameterKey": "TaskDefIncludesFile",
"ParameterValue": "s3://doenet-cf-dev/dev3-doenet/dev3-umami-db-taskdef-includes.yml"
},
{
"ParameterKey": "TaskRoleIncludesFile",
"ParameterValue": "s3://doenet-cf-dev/dev3-doenet/service-taskrole-includes.yml"
},
{
"ParameterKey": "ContainerPort",
"ParameterValue": "5432"
},
{
"ParameterKey": "ContainerMemory",
"ParameterValue": "1024"
},
{
"ParameterKey": "ContainerCpu",
"ParameterValue": "512"
},
{
"ParameterKey": "HealthCheckGracePeriod",
"ParameterValue": "300"
},
{
"ParameterKey": "MaxCount",
"ParameterValue": "1"
},
{
"ParameterKey": "MinCount",
"ParameterValue": "1"
},
{
"ParameterKey": "SecurityGroup",
"ParameterValue": "/dev3/EcsInstanceSecurityGroup"
},
{
"ParameterKey": "PrivateSubnets",
"ParameterValue": "/dev3/PrivateSubnets"
},
{
"ParameterKey": "VPC",
"ParameterValue": "/dev3/VPC"
},
{
"ParameterKey": "EnvironmentKmsKey",
"ParameterValue": "/dev3/EnvironmentKmsKey"
},
{
"ParameterKey": "EcsCluster",
"ParameterValue": "/dev3/EcsCluster"
},
{
"ParameterKey": "LoadBalancerListener",
"ParameterValue": "/dev3/LoadBalancerHttpsListener"
},
{
"ParameterKey": "EfsFileSystemId",
"ParameterValue": "/dev3/EfsFileSystemId"
},
{
"ParameterKey": "PublicHostedZoneId",
"ParameterValue": "/dev3/PublicHostedZoneId"
},
{
"ParameterKey": "PublicHostedZoneName",
"ParameterValue": "/dev3/PublicHostedZoneName"
},
{
"ParameterKey": "LoadBalancerDnsName",
"ParameterValue": "/dev3/LoadBalancerDnsName"
},
{
"ParameterKey": "LoadBalancerHostedZoneId",
"ParameterValue": "/dev3/LoadBalancerHostedZoneId"
},
{
"ParameterKey": "RestrictedCIDRs",
"ParameterValue": "notapplicable"
},
{
"ParameterKey": "PathPattern",
"ParameterValue": "notapplicable"
}
]
Loading