diff --git a/Dockerfile b/Dockerfile index 84752e17..aca314a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,10 +35,14 @@ ENV NEXT_TELEMETRY_DISABLED 1 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs +RUN yarn global add prisma + # You only need to copy next.config.js if you are NOT using the default configuration COPY --from=builder /app/next.config.js ./ COPY --from=builder /app/public ./public COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/prisma/schema.prisma ./prisma/schema.prisma +COPY --from=builder /app/prisma/migrations ./prisma/migrations # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing @@ -51,4 +55,4 @@ EXPOSE 3000 ENV PORT 3000 -CMD ["node", "server.js"] +CMD ["yarn", "production"] diff --git a/README.md b/README.md index fb2169c1..38958133 100644 --- a/README.md +++ b/README.md @@ -33,23 +33,10 @@ cd umami yarn install ``` -### Create database tables +### Database Umami supports [MySQL](https://www.mysql.com/) and [Postgresql](https://www.postgresql.org/). -Create a database for your Umami installation and install the tables with the included scripts. - -For MySQL: - -``` -mysql -u username -p databasename < sql/schema.mysql.sql -``` - -For Postgresql: - -``` -psql -h hostname -U username -d databasename -f sql/schema.postgresql.sql -``` - +The database structure will automatically be applied on the first start of Umami. This will also create a login account with username **admin** and password **umami**. ### Configure umami @@ -82,7 +69,7 @@ yarn build yarn start ``` -By default this will launch the application on `http://localhost:3000`. You will need to either +By default this will launch the application on `http://localhost:3000`. You will need to either [proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) requests from your web server or change the [port](https://nextjs.org/docs/api-reference/cli#production) to serve the application directly. diff --git a/app.json b/app.json index a27dc6fe..ef62e0e5 100644 --- a/app.json +++ b/app.json @@ -1,26 +1,16 @@ { - "name": "Umami", - "description": "Umami is a simple, fast, website analytics alternative to Google Analytics.", - "keywords": [ - "analytics", - "charts", - "statistics", - "web-analytics" - ], - "website": "https://umami.is", - "repository": "https://github.com/mikecao/umami", - "addons": [ - "heroku-postgresql" - ], - "env": { - "HASH_SALT": { - "description": "Used to generate unique values for your installation", - "required": true, - "generator": "secret" - } - }, - "scripts": { - "postdeploy": "psql $DATABASE_URL -f sql/schema.postgresql.sql" - }, - "success_url": "/" + "name": "Umami", + "description": "Umami is a simple, fast, website analytics alternative to Google Analytics.", + "keywords": ["analytics", "charts", "statistics", "web-analytics"], + "website": "https://umami.is", + "repository": "https://github.com/mikecao/umami", + "addons": ["heroku-postgresql"], + "env": { + "HASH_SALT": { + "description": "Used to generate unique values for your installation", + "required": true, + "generator": "secret" + } + }, + "success_url": "/" } diff --git a/package.json b/package.json index f30a307c..3fc489a6 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "build": "npm-run-all build-tracker build-geo build-db build-app", "start": "next start", "start-env": "node -r dotenv/config scripts/start-env.js", + "production": "prisma migrate deploy && node server.js", "build-app": "next build", "build-tracker": "rollup -c rollup.tracker.config.js", "build-db": "npm-run-all copy-db-schema build-db-client", @@ -68,7 +69,6 @@ "dotenv": "^10.0.0", "dotenv-cli": "^4.0.0", "formik": "^2.2.9", - "fs-extra": "^10.0.1", "immer": "^9.0.12", "ipaddr.js": "^2.0.1", "is-ci": "^3.0.1", @@ -107,6 +107,7 @@ "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.0.0", "extract-react-intl-messages": "^4.1.1", + "fs-extra": "^10.1.0", "husky": "^7.0.0", "lint-staged": "^11.0.0", "postcss": "^8.4.12", diff --git a/prisma/mysql/migrations/20210320112658_init/migration.sql b/prisma/mysql/migrations/20210320112658_init/migration.sql index 0bb75d64..653c5de0 100644 --- a/prisma/mysql/migrations/20210320112658_init/migration.sql +++ b/prisma/mysql/migrations/20210320112658_init/migration.sql @@ -97,3 +97,6 @@ ALTER TABLE `session` ADD FOREIGN KEY (`website_id`) REFERENCES `website`(`websi -- AddForeignKey ALTER TABLE `website` ADD FOREIGN KEY (`user_id`) REFERENCES `account`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- CreateAdminUser +INSERT INTO account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true); diff --git a/prisma/postgresql/migrations/20210320112717_init/migration.sql b/prisma/postgresql/migrations/20210320112717_init/migration.sql index 1567119d..cdabcd17 100644 --- a/prisma/postgresql/migrations/20210320112717_init/migration.sql +++ b/prisma/postgresql/migrations/20210320112717_init/migration.sql @@ -127,3 +127,6 @@ ALTER TABLE "session" ADD FOREIGN KEY ("website_id") REFERENCES "website"("websi -- AddForeignKey ALTER TABLE "website" ADD FOREIGN KEY ("user_id") REFERENCES "account"("user_id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- CreateAdminUser +INSERT INTO account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true); diff --git a/scripts/copy-db-schema.js b/scripts/copy-db-schema.js index 7773e696..9c4ed6db 100644 --- a/scripts/copy-db-schema.js +++ b/scripts/copy-db-schema.js @@ -1,5 +1,5 @@ require('dotenv').config(); -const fs = require('fs'); +const fse = require('fs-extra'); const path = require('path'); function getDatabase() { @@ -25,6 +25,13 @@ console.log(`Database type detected: ${databaseType}`); const src = path.resolve(__dirname, `../prisma/schema.${databaseType}.prisma`); const dest = path.resolve(__dirname, '../prisma/schema.prisma'); -fs.copyFileSync(src, dest); +fse.copyFileSync(src, dest); console.log(`Copied ${src} to ${dest}`); + +const srcMigrations = path.resolve(__dirname, `../prisma/${databaseType}/migrations`); +const destMigrations = path.resolve(__dirname, `../prisma/migrations`); + +fse.copySync(srcMigrations, destMigrations); + +console.log(`Copied ${srcMigrations} to ${destMigrations}`); diff --git a/sql/schema.mysql.sql b/sql/schema.mysql.sql deleted file mode 100644 index 0e05ec03..00000000 --- a/sql/schema.mysql.sql +++ /dev/null @@ -1,80 +0,0 @@ -drop table if exists event; -drop table if exists pageview; -drop table if exists session; -drop table if exists website; -drop table if exists account; - -create table account ( - user_id int unsigned not null auto_increment primary key, - username varchar(255) unique not null, - password varchar(60) not null, - is_admin bool not null default false, - created_at timestamp default current_timestamp, - updated_at timestamp default current_timestamp -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table website ( - website_id int unsigned not null auto_increment primary key, - website_uuid varchar(36) unique not null, - user_id int unsigned not null, - name varchar(100) not null, - domain varchar(500), - share_id varchar(64) unique, - created_at timestamp default current_timestamp, - foreign key (user_id) references account(user_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table session ( - session_id int unsigned not null auto_increment primary key, - session_uuid varchar(36) unique not null, - website_id int unsigned not null references website(website_id) on delete cascade, - created_at timestamp default current_timestamp, - hostname varchar(100), - browser varchar(20), - os varchar(20), - device varchar(20), - screen varchar(11), - language varchar(35), - country char(2), - foreign key (website_id) references website(website_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table pageview ( - view_id int unsigned not null auto_increment primary key, - website_id int unsigned not null, - session_id int unsigned not null, - created_at timestamp default current_timestamp, - url varchar(500) not null, - referrer varchar(500), - foreign key (website_id) references website(website_id) on delete cascade, - foreign key (session_id) references session(session_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create table event ( - event_id int unsigned not null auto_increment primary key, - website_id int unsigned not null, - session_id int unsigned not null, - created_at timestamp default current_timestamp, - url varchar(500) not null, - event_type varchar(50) not null, - event_value varchar(50) not null, - foreign key (website_id) references website(website_id) on delete cascade, - foreign key (session_id) references session(session_id) on delete cascade -) ENGINE=InnoDB COLLATE=utf8_general_ci; - -create index website_user_id_idx on website(user_id); - -create index session_created_at_idx on session(created_at); -create index session_website_id_idx on session(website_id); - -create index pageview_created_at_idx on pageview(created_at); -create index pageview_website_id_idx on pageview(website_id); -create index pageview_session_id_idx on pageview(session_id); -create index pageview_website_id_created_at_idx on pageview(website_id, created_at); -create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at); - -create index event_created_at_idx on event(created_at); -create index event_website_id_idx on event(website_id); -create index event_session_id_idx on event(session_id); - -insert into account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true); diff --git a/sql/schema.postgresql.sql b/sql/schema.postgresql.sql deleted file mode 100644 index 28297c4a..00000000 --- a/sql/schema.postgresql.sql +++ /dev/null @@ -1,74 +0,0 @@ -drop table if exists event; -drop table if exists pageview; -drop table if exists session; -drop table if exists website; -drop table if exists account; - -create table account ( - user_id serial primary key, - username varchar(255) unique not null, - password varchar(60) not null, - is_admin bool not null default false, - created_at timestamp with time zone default current_timestamp, - updated_at timestamp with time zone default current_timestamp -); - -create table website ( - website_id serial primary key, - website_uuid uuid unique not null, - user_id int not null references account(user_id) on delete cascade, - name varchar(100) not null, - domain varchar(500), - share_id varchar(64) unique, - created_at timestamp with time zone default current_timestamp -); - -create table session ( - session_id serial primary key, - session_uuid uuid unique not null, - website_id int not null references website(website_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - hostname varchar(100), - browser varchar(20), - os varchar(20), - device varchar(20), - screen varchar(11), - language varchar(35), - country char(2) -); - -create table pageview ( - view_id serial primary key, - website_id int not null references website(website_id) on delete cascade, - session_id int not null references session(session_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - url varchar(500) not null, - referrer varchar(500) -); - -create table event ( - event_id serial primary key, - website_id int not null references website(website_id) on delete cascade, - session_id int not null references session(session_id) on delete cascade, - created_at timestamp with time zone default current_timestamp, - url varchar(500) not null, - event_type varchar(50) not null, - event_value varchar(50) not null -); - -create index website_user_id_idx on website(user_id); - -create index session_created_at_idx on session(created_at); -create index session_website_id_idx on session(website_id); - -create index pageview_created_at_idx on pageview(created_at); -create index pageview_website_id_idx on pageview(website_id); -create index pageview_session_id_idx on pageview(session_id); -create index pageview_website_id_created_at_idx on pageview(website_id, created_at); -create index pageview_website_id_session_id_created_at_idx on pageview(website_id, session_id, created_at); - -create index event_created_at_idx on event(created_at); -create index event_website_id_idx on event(website_id); -create index event_session_id_idx on event(session_id); - -insert into account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index c6054736..d49dca19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3353,7 +3353,7 @@ fraction.js@^4.2.0: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== -fs-extra@10, fs-extra@^10.0.1: +fs-extra@10, fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==