Skip to content
Open
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion apps/labrinth/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
- Use `ApiError` as the error type for API routes
- Prefer `ApiError::Internal` and `ApiError::Request` over `ApiError::InvalidInput`
- The return type of an HTTP route should not be `HttpResponse` if possible; always prefer more specific types
- Use `web::Json<T>` for JSON-encoded response
- Use `()` for no content
- Prefer `ApiError` variants:
- `ApiError::Request` instead of `ApiError::InvalidInput`
- `ApiError::Auth` instead of `ApiError::CustomAuthentication`
- `ApiError::Internal` for database errors, 3rd party service errors, anything else internal
- Use `eyre!` to construct a value for `Internal` and `Request` variants
- Error messages (both for errors and exceptions) must be formatted as per the Rust API guidelines:
- lowercase message
Expand Down
19 changes: 19 additions & 0 deletions apps/labrinth/fixtures/analytics-changes-clickhouse.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-- Dummy ClickHouse download rows for exercising v3 analytics download-source normalization.
-- Run this against the analytics ClickHouse database, for example:
-- curl -u default:default 'http://localhost:8123/?database=staging_ariadne' --data-binary @apps/labrinth/fixtures/analytics-changes-clickhouse.sql
--
-- Project 910000000000003 = 4AP3jpvKl

INSERT INTO downloads FORMAT JSONEachRow
{"recorded":"2026-05-13 00:05:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"modrinth/kyros/1.0.0 (support@modrinth.com)","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:10:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"modrinth/theseus/0.8.6 (support@modrinth.com)","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:15:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"Gradle/8.8","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:20:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"MultiMC/5.0","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:25:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"PrismLauncher/6.1","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:30:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"PolyMC/7.0","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:35:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) FeatherLauncher/2.6.12-c Chrome/144.0.7559.236 Electron/40.9.1 Safari/537.36 (hello@feathermc.com)","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:40:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"FeatherMC/Feather Client Rust Launcher/1.0.0 (hello@feathermc.com)","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:45:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Feather/9b6bb39d Safari/537.36","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:50:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"PandoraLauncher/1.2.3","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:55:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"Mozilla/5.0 AppleWebKit/605.1.15","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
{"recorded":"2026-05-13 00:59:00.0000","domain":"cdn.modrinth.com","site_path":"/data/analytics-fixture.jar","user_id":0,"project_id":910000000000003,"version_id":0,"ip":"::1","country":"US","user_agent":"curl/8.7.1","headers":[],"reason":"primary","game_version":"1.20.1","loader":"fabric"}
97 changes: 97 additions & 0 deletions apps/labrinth/fixtures/analytics-changes-postgres.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
-- Dummy analytics data for exercising v3 analytics events and project download analytics.
-- IDs are listed as integers, followed by their equivalent base62 representation.

-- User 103587649610509 = 1XZwx9qL
INSERT INTO users (
id, username, email, role, badges, balance, email_verified
)
VALUES (
103587649610509, 'Analytics Admin', 'analytics-admin@modrinth.com',
'admin', 0, 0, TRUE
)
ON CONFLICT (id) DO UPDATE SET
role = EXCLUDED.role;

INSERT INTO sessions (
id, session, user_id, expires, refresh_expires, ip, user_agent
)
VALUES (
103587649610510, 'mra_analytics_admin', 103587649610509,
'2030-01-01T00:00:00Z', '2030-01-01T00:00:00Z',
'127.0.0.1', 'analytics fixture'
)
ON CONFLICT (session) DO UPDATE SET
user_id = EXCLUDED.user_id,
expires = EXCLUDED.expires,
refresh_expires = EXCLUDED.refresh_expires;

-- Project 910000000000003 = 4AP3jpvKl
-- Team 910000000000001 = 4AP3jpvKj
-- Thread 910000000000004 = 4AP3jpvKm
INSERT INTO teams (id)
VALUES (910000000000001)
ON CONFLICT (id) DO NOTHING;

INSERT INTO team_members (
id, team_id, user_id, role, permissions, accepted, payouts_split, ordering,
organization_permissions, is_owner
)
VALUES (
910000000000002, 910000000000001, 103587649610509, 'Owner',
1023, TRUE, 100, 0, NULL, TRUE
)
ON CONFLICT (id) DO UPDATE SET
permissions = EXCLUDED.permissions,
accepted = EXCLUDED.accepted,
is_owner = EXCLUDED.is_owner;

INSERT INTO mods (
id, team_id, name, summary, downloads, slug, description, follows,
license, status, requested_status, monetization_status,
side_types_migration_review_status, components
)
VALUES (
910000000000003, 910000000000001, 'Analytics Fixture Project',
'Project used by analytics fixture data.', 0, 'analytics-fixture-project',
'', 0, 'LicenseRef-All-Rights-Reserved', 'approved', 'approved',
'monetized', 'reviewed', '{}'::jsonb
)
ON CONFLICT (id) DO UPDATE SET
team_id = EXCLUDED.team_id,
status = EXCLUDED.status,
requested_status = EXCLUDED.requested_status,
monetization_status = EXCLUDED.monetization_status;

INSERT INTO threads (id, thread_type, mod_id)
VALUES (910000000000004, 'project', 910000000000003)
ON CONFLICT (id) DO NOTHING;

-- Analytics events used to test /v3/analytics-event and Redis caching.
-- Event 910000000000101 = 4AP3jpvMR
-- Event 910000000000102 = 4AP3jpvMS
INSERT INTO analytics_events (id, meta, starts, ends)
VALUES
(
910000000000101,
'{
"title": "Downloads launch",
"announcement_url": "https://modrinth.com/news/downloads-launch",
"for_metric_kind": ["downloads"]
}'::jsonb,
'2026-05-13T00:00:00Z',
'2026-05-14T00:00:00Z'
),
(
910000000000102,
'{
"title": "Revenue promo",
"announcement_url": "https://modrinth.com/news/revenue-promo",
"for_metric_kind": ["revenue"]
}'::jsonb,
'2026-05-14T00:00:00Z',
'2026-05-15T00:00:00Z'
)
ON CONFLICT (id) DO UPDATE SET
meta = EXCLUDED.meta,
starts = EXCLUDED.starts,
ends = EXCLUDED.ends;
6 changes: 6 additions & 0 deletions apps/labrinth/migrations/20260513111617_analytics_events.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
create table analytics_events (
id bigint primary key,
meta jsonb not null,
starts timestamptz not null,
ends timestamptz not null
);
Loading
Loading