Repository navigation
Technical Documentation
Prefer these focused guides for day-to-day onboarding; this page remains the longer install / Firebase / Git reference.
- Architecture · Sites · Firestore schema · Environment · Cloud Functions · Testing
- Private study ops: misinfo-dashboard-ops
Misinfo Dashboard is a Next.js project bootstrapped with create-next-app. Canonical setup steps also live in the README.
Clone engagingnewsproject/misinfo-dashboard to a directory on your local computer.
git clone https://github.com/engagingnewsproject/misinfo-dashboard.git
cd misinfo-dashboard
Production and CI use Node 20.20.0 and npm 11.15.0 (see .nvmrc and package.json engines). With engine-strict=true in .npmrc, use matching versions locally:
nvm install && nvm use
npm install -g npm@11.15.0
npm installAdd a root .env with Firebase credentials (ask the project lead).
Install Firebase CLI if needed: Emulator suite install.
With emulators (recommended):
npm run devOpens the Firebase Emulator UI and Next.js at http://localhost:3000. Use that URL for the app UI during local development—not a separate Hosting emulator port, which can conflict with API key HTTP referrer rules.
Emulator test accounts (password devPassword): user@user.com, agency@user.com, admin@user.com.
Against production Firebase:
npm run dev:liveRequires production Auth users and often an App Check debug token for localhost.
With emulators running and a gitignored service account JSON at the repo root:
npm run seed:emulator -- --limit=500 --with-settingsUse --dry-run to preview counts. After import, run Settings → Experiment & archive → Initialize experiment fields if reports lack experimentId / archived. Persist a snapshot: firebase emulators:export ./emulator-data.
- Chrome extension that adds React debugging tools to the Chrome Developer Tools.
VS Code ES7+ React/Redux/React-Native snippets
- JavaScript and React/Redux snippets in ES7+ with Babel plugin features for VS Code
VS Code Tailwind CSS IntelliSense
- Tailwind CSS IntelliSense enhances the Tailwind development experience by providing Visual Studio Code users with advanced features such as autocomplete, syntax highlighting, and linting.
This section provides an overview of the file and folder structure of the Misin project. It covers top-level files and folders, configuration files, and routing conventions.
| Files | |
|---|---|
.eslintrc.json |
Configuration file for ESLint |
.firebaserc |
Firebase settings for deploy targets |
.gitignore |
Git files and folders to ignore |
firebase.json |
Firebase project configuration |
firestore.indexes.json |
Firebase custom indexes |
firestore.rules |
Firebase security rules |
next.config.js |
Configuration file for Next.js |
package.json |
Project npm dependencies and scripts |
postcss.config.js |
PostCSS configuration |
utils/reports-queries.js |
Active experiment / archive query helpers |
utils/experiment-config.js |
Default cohort ids and archive cutoff constants |
functions/experiment.js |
Experiment/archive Cloud Functions (re-exported from functions/index.js) |
tailwind.config.js |
Tailwindcss configuration |
package-lock.json |
Project npm dependency lockfile |
| Files | |
|---|---|
/components |
React components (admin/, dashboard/, reports/, modals/, etc.) |
/config/firebase.js |
Firebase client SDK initialization |
/context/AuthContext.jsx |
Auth state and custom claims |
/pages |
Next.js Pages Router |
/public |
Static assets |
/functions |
Firebase Cloud Functions |
/utils |
Shared helpers (reports queries, experiment config) |
/styles |
Global styles |
Data is stored on the Firebase Firestore Database.
- Database configuration is initialized in config/firebase.js.
- Database authentication (signup, login, logout ext.) is setup in context/AuthContext.jsx.
Firebase authentication on pages and components.
| Files: | |
|---|---|
config/firebase.js |
Auth entry point |
context/AuthContext.jsx |
defines user authorization |
Rules in firestore.rules complement app-level agency filtering:
| Path | Behavior |
|---|---|
settings/experiment |
Any signed-in user may read; only admin custom claim may write |
reports/{id} |
Signed-in read; create requires archived == false and non-empty experimentId string |
reports/{id} update
|
Signed-in users may update; changing archived, archivedAt, or archivedBy requires admin
|
| Other collections | Signed-in read/write (legacy broad rule) |
Bulk archive and experiment config changes must run as an admin user (or via Admin SDK), matching the Cloud Functions in functions/experiment.js.
Deploy callable functions (including experiment/archive) after changing functions/:
firebase deploy --only functionsExperiment callables are implemented in functions/experiment.js and re-exported from functions/index.js (region us-central1).
Deployment is automated end-to-end: open a pull request, the CI build runs, and merging to main triggers Firebase App Hosting to build and ship the new version. There is no manual deploy step.
- Push your branch and open a PR into
main. - GitHub Actions runs the
buildworkflow against your PR (~2 minutes). - If
buildis green, the PR is mergeable. If it is red, the PR is blocked — branch protection onmainrequires this check. - After merge to
main, Firebase App Hosting picks up the new commit, runs its own build, and deploys to the live URL.
Live URL: https://truthsleuthlocal--misinfo-5d004.us-central1.hosted.app
PR → CI build (npm ci + npm run build) → merge → App Hosting build → live
The key promise: if your PR's build check is green, App Hosting will be green too. The two builds use the same toolchain, same install command, and same build script — so they cannot disagree in practice.
App Hosting builds with Node 20.20.0 and npm 11.15.0. The repo pins this for local dev so nobody can accidentally build with a different toolchain and produce a lock file that App Hosting can't install:
| File | Purpose |
|---|---|
.nvmrc |
Pins Node to 20.20.0. Run nvm use in the project root to switch. |
.npmrc |
Sets engine-strict=true so npm install refuses to run on the wrong Node or npm version. |
package.json → engines
|
Declares "node": "20.20.0" and "npm": "11.15.0". |
scripts/lockfile-ci.sh |
Regenerate or verify package-lock.json on Linux via Docker (npm run lockfile:*). |
If your local npm install is refused, upgrade:
nvm install 20.20.0 && nvm use 20.20.0
npm install -g npm@11.15.0Defined in .github/workflows/build.yml. Runs on every pull request and every push to main. Steps mirror App Hosting exactly:
# inside a node:20.20.0 container
npm install -g npm@11.15.0
npm ci # fails fast if package-lock.json is out of sync
npm run build # full Next build (with --webpack and Sentry plugin)Dummy NEXT_PUBLIC_* env values are set in the workflow so the build completes without coupling CI to real Firebase secrets. The real secrets live in apphosting.yaml and are injected by App Hosting at its own build/run time.
main requires the build check to pass before any PR can be merged. This is enforced by GitHub branch protection (configured via gh api). Effects:
- You cannot merge a PR with a failing
build. - You cannot push directly to
main. All changes go through PRs. -
strict: truemeans the PR's branch must also be up to date withmainat merge time.
If you change a dependency (add/update/remove in package.json), regenerate the lock file on Linux with the pinned Node/npm versions. Otherwise npm ci fails in CI and App Hosting with EUSAGE ("lock file out of sync") or "Missing: … from lock file".
Why macOS-only regen fails: npm can write a lockfile on Darwin that omits nested dependency entries (for example ajv@6 under @eslint/eslintrc) that Linux npm ci still requires. Local npm install may report "up to date" while GitHub Actions rejects the commit.
Required on macOS (and recommended everywhere):
npm run lockfile:regen # npm install inside node:20.20.0 on Linux
npm run lockfile:ci # npm ci in Linux — run before committing the lockfileFull regen (deletes existing lockfile first):
npm run lockfile:regen:fresh
npm run lockfile:ciScripts live in scripts/lockfile-ci.sh (Docker required). Do not hand-edit package-lock.json; resolve merge conflicts by re-running lockfile:regen after fixing package.json.
Linux-native developers may use the same npm versions without Docker if node -v / npm -v match the pins and npm ci succeeds—but npm run lockfile:ci remains the parity check before push.
Then commit and push package-lock.json. The PR's build check must pass before merge.
package.json lists @rollup/rollup-darwin-arm64 and @rollup/rollup-darwin-x64 as optionalDependencies (pinned to the same major as the nested rollup used by @sentry/nextjs) so macOS installs get the correct native Rollup binary even when npm mishandles nested optional dependencies (npm CLI issue #4828). On Apple Silicon, use arm64 Node (node -p process.arch should print arm64); if it prints x64, you are likely on Rosetta and builds may look for the wrong native packages.
| Thing | Where |
|---|---|
| CI workflow | .github/workflows/build.yml |
| Node version pin | .nvmrc |
| npm strictness | .npmrc |
| Engines declaration |
package.json → engines
|
| Lockfile verify/regen (Linux via Docker) |
scripts/lockfile-ci.sh, npm run lockfile:ci
|
| App Hosting config (secrets, env, region) | apphosting.yaml |
| App Hosting backend list (CLI) | firebase apphosting:backends:list --project misinfo-5d004 |
| Manual rollout (no commit) | firebase apphosting:rollouts:create truthsleuthlocal --project misinfo-5d004 |
See also the README – Deploy to Firebase Hosting section for the canonical setup steps.
pages/index.js — entry redirect; authenticated home is pages/dashboard.jsx.
| Files | |
|---|---|
components/dashboard/Home.jsx |
Home tab: headbar, graphs, reports list |
components/layout/Headbar.jsx |
Top title bar + search |
components/dashboard/TagGraph.jsx |
Overview vs comparison graph toggle |
components/reports/ReportsSection.jsx |
Reports table, filters, CSV import/export |
components/profile/Profile.jsx |
User profile |
components/admin/Settings.jsx |
Tag systems + Experiment & archive (admin) |
components/layout/Navbar.jsx |
Side navigation |
See Graphs for trending-topic charts and components/reports/ReportsSection.jsx for the report list.
Signup, login, logout & reset password.
| Files | |
|---|---|
pages/_app.js |
handles login functionality: |
components/layout/ProtectedRoute.jsx |
login validation |
context/AuthContext.jsx |
authorization validation |
styles/globalStyles.js |
shared style tokens |
Includes Home view, Tagging System, New Report, Profile, Help & Login/Logout.
| Files | |
|---|---|
pages/dashboard.jsx |
renders side navbar |
components/Navbar.jsx |
imports navbar elements |
components/modals/common/ConfirmModal.jsx |
confirmation modal for logout |
components/modals/reports/AgencyReportModal.jsx |
add new report modal |
components/modals/common/HelpModal.jsx |
dashboard help modal |
components/ReportsSection.jsx - the bulk of the report handling
- Filter reports - Filter the reports based on search text or filter dropdown selection
- Read/unread - Set report read status
- handleReadToggled, handleReadFilterChanged
- Infinite scroll - import InfiniteScroll from "react-infinite-scroll-component"
- Delete report
- handleReportDelete, handleDelete
components/modals/reports/AgencyReportModal.jsx (agency dashboard) and components/reports/ReportSystem.jsx (public /report flow) create reports with these fields:
| key | value |
|---|---|
userID |
user email |
state |
country-state-city package |
title |
report title |
link |
user input link |
secondLink |
user input second link |
images |
user uploaded images |
detail |
report description |
createdDate |
report created date (Firestore timestamp) |
isApproved |
?? |
read |
report viewed or toggled by user |
topic |
report selected label |
hearFrom |
Sources / Media |
experimentId |
Cohort id (e.g. 2026-main); set from settings/experiment.activeExperimentId on create |
archived |
When true, excluded from operational list/graph/export queries |
archivedAt |
Timestamp when bulk-archived (admin Cloud Function) |
archivedBy |
Admin Auth UID who ran bulk archive |
origin |
Submission channel: agency, public, or scrape (piped/scraped articles) |
Config document: settings/experiment
| Field | Purpose |
|---|---|
activeExperimentId |
Cohort used for new reports and default dashboard queries |
experiments |
Array of { id, label, startDate?, endDate? }
|
Operational filters:
-
Graphs and comparison charts:
archived == falseandexperimentId == <activeExperimentId>(viautils/reports-queries.js). - Agency report list: same as graphs, scoped to the user’s agency.
-
Admin reports table: all study waves (
allExperiments); defaultarchived == false; Show archived includes archived rows. - Admin CSV export: rows from the current table view (filters + Show archived), not the full Firestore collection.
Admin tooling: Settings tab → “Experiment & archive” (components/admin/ExperimentSettings.jsx).
Admin user guide: Archiving — step-by-step archiving and study-wave workflow (non-technical).
Cloud Functions (implemented in functions/experiment.js, exported from functions/index.js; region us-central1; admin custom claim required):
| Callable | Params | Returns |
|---|---|---|
setActiveExperiment |
{ experimentId } |
{ activeExperimentId } |
addExperiment |
{ id, label, setActive? } |
{ experiments, activeExperimentId, addedId } — slug id e.g. 2027-main
|
backfillReportExperimentFields |
{} |
{ updated } — sets missing archived / experimentId
|
previewBulkArchive |
{ cutoffISO } |
{ count, cutoffISO } |
bulkArchiveReports |
{ cutoffISO } |
{ updated, cutoffISO } — archives reports with createdDate < cutoff
|
getExperimentMetrics |
{ experimentId?, includeArchived?, agency? } |
{ submittedCount, scrapedCount, ... } |
External / research queries (Admin SDK example):
const experimentId = '2026-main';
const submitted = await db.collection('reports')
.where('archived', '==', false)
.where('experimentId', '==', experimentId)
.count().get();
const scraped = await db.collection('reports')
.where('archived', '==', false)
.where('experimentId', '==', experimentId)
.where('origin', '==', 'scrape')
.count().get();Or invoke getExperimentMetrics with a signed-in admin user for the same counts.
Client helpers:
-
utils/reports-queries.js—fetchExperimentConfig,buildActiveReportsQuery,fetchAdminReportsList,newReportExperimentFields -
utils/experiment-config.js— defaultactiveExperimentId, cohort cutoffs for backfill (keep in sync withfunctions/experiment-config.js)
Deploy composite indexes from firestore.indexes.json before production use.
Each report has specific tags applied. Topic Tags, Source Tags and Labels.
| Files | |
|---|---|
components/admin/Settings.jsx |
tagging system entry point |
components/analytics/TagSystem.jsx |
import of tagging modals |
components/modals/NewTagModal.jsx |
modal for adding new tags |
components/modals/RenameTagModal.jsx |
modal for renaming existing tags |
components/modals/common/ConfirmModal.jsx |
modal for confirming tag changes |
Pie chart or line graph for the trending topics.
Determines graph of trending topics in the format of the selected graph view (either overview graph or comparison graph).
| Files | |
|---|---|
components/common/Toggle.jsx |
Switch between overview and comparison graph |
components/dashboard/TagGraph.jsx |
Fetches report counts and renders overview or comparison UI |
Pie chart that shows the number of reports for the top three trending topics for yesterday, the past three days, and the past week.
| Files | |
|---|---|
components/dashboard/OverviewGraph.jsx |
Pie charts for top trending topics (1 / 3 / 7 days) |
Line chart that plots the number of reports for the selected topic reports within the requested date range.
| Files | |
|---|---|
components/analytics/ComparisonGraphSetup.jsx |
Topic and date-range selection for comparison chart |
components/analytics/ComparisonGraphPlotted.jsx |
Line chart for selected topics and range |
components/analytics/ComparisonGraphMenu.jsx |
Controls to change comparison parameters |
Redirects to default email client with link to the report
- Simple button that uses JS mailto function to share report through email
- Only shown on the details page of existing reports. Not related to other functions or pages in the system.
| Files |
|---|
pages/dashboard/reports/[reportId].jsx |
Allows users to create new reports through popup modal, not a separate page.
- Requires at least one: description, link, or photo
- Connects to firebase and generates a new report in the database
- Same functionality as the app, just for desktop
| Files |
|---|
components/modals/reports/AgencyReportModal.jsx |
Switches between graph views
- Graph views use react charts library.
Bar graph that displays the number of reports from the previous day for the top 3 trending topics
- Can choose a specific date range as well.
Displays list of most recent reports in firebase.
| Files | |
|---|---|
ConfirmModal.jsx |
Used to display a dialog box with an optional message and two buttons, OK and Cancel. It prevents the user from accessing other parts of the page until the box is closed. |
HelpModal.jsx |
Used to display a dialog box with user documentation. |
AgencyReportModal.jsx |
|
NewTagModal.jsx |
|
RenameTagModal.jsx |
|
ReportModal.jsx |
|
UpdatePwModal.jsx |
A collection of general tips and rules of thumb when coding and building a project.
For example:
- will the change increase the weight of our page?
- will the change increase our load time?
Clever can be fun, but always at the risk of complicating things and making life more difficult for your future self and others. Opt for unglamorous, simple code to save yourself a headache down the road.
If being clever is going to save you a lot of time or be a big performance boost, be sure to put it in a very simple, well-documented standalone function or module with a simple name that clearly explains what it does, why it should be done this way, and how it works.
When writing a new function, make sure that it accomplishes one, specific thing. This keeps the code:
- more testable,
- easier to debug,
- easier to read / understand,
- easier to maintain
Some rules of thumb. You probably need to break apart your function into several smaller functions if:
- if you have a really long function name
- if your function code is many lines long or has many steps
This advice isn't in order to stop you from asking questions, but because some of the best learning happens when you think hard about trying to figure it out on your own. Google it. Read an article or two. Chances are you'll learn something, even if it doesn't lead you to the exact thing you needed to know.
- what you're trying to solve
- why you need to solve it
- what you've already tried
- helps you organize your thoughts
- gives you a chance to think about the problem in a different way
- often leads you to the correct answer
I'd estimate 30% of the time I've written a detailed question, I figure out the answer before I finish writing it or right after I ask it :)
When people have different format on save rules, it makes it really hard to review Pull Requests (PR). For example, if one person uses a two tab vs four spacing autoformat on save, the PR will show everyone of those lines from the file as a change rather than just the work that was completed. So, maybe you made one small change, but now every line in the file is shown as a change. This makes it difficult to identify the real change.
When writing a query or requesting data, it's best to get just what you need (or will likely need)
- Look at the existing code base and see if it makes sense for code to be in one place or another. If it doesn't have an obvious place, create a new file using the existing standards of the code.
Important things to remember:
-
Make sure you are always pulling from
main. -
Thorough testing after big changes. Deploy in a more piecemeal manner
-
Only one person to push to the
prodbranch.
After changes have been pushed to the Dev Site send a link to Kat for review.
-
When you take on a task:
-
Go to the applicable Github repo and choose the issue to work on
-
Assign this issue to yourself
-
Create your Git Branch
a. If this is a critical hotfix that needs to get released immediately:
$ git checkout -b hotfix-[hotfix-name] stable // creates a local branch $ git push origin hotfix-[hotfix-name] // makes the branch remotely availableb. If this is a new feature/improvement:
$ git checkout -b feature-[feature-name] master // creates a local branch $ git push origin feature-[feature-name] // makes the branch remotely availablec. If this is a non-critical bugfix:
$ git checkout -b bug-[bug-name] master // creates a local branch $ git push origin bug-[bug-name] // makes the branch remotely available -
As work gets to stable stopping points or completion, push it to github:
$ git push origin your-branch-name // pushes branch to github -
When your code is ready to be reviewed:
-
Go to your branch on github.com and create a new pull request to be merged into
main. -
Drop any implementation notes into the github.com issue and link the pull request to the github.com issue in the issue right sidebar.
-
-
After your code is reviewed:
- It will either be merged or comments will be left so you can finish up the issue. Go ahead and repeat from #1 while you wait for the review.
Quick Legend
| Instance | Branch | Description, Instructions, Notes |
| Development | dev | Accepts merges from Working, Features/Issues and Hotfixes. |
| Working | main | Accepts merges from Features/Issues and Hotfixes |
| Production | prod | Accepts merges from Working and Hotfixes |
The main repository will always hold two evergreen branches:
mainprod
The main branch should be considered origin/main and will be the main branch where the source code of HEADalways reflects a state with the latest delivered development changes for the next release. As a developer, you will be branching and merging from main.
Consider origin/prod to always represent the latest code deployed to production. During day to day development, the prod branch will not be interacted with.
When the source code in the main branch is stable and has been deployed, all of the changes will be merged into prod.
Supporting branches are used to aid parallel development between team members, ease tracking of features, and to assist in quickly fixing live production problems. Unlike the main branches, these branches always have a limited life time, since they will be removed eventually.
The different types of branches we may use are:
- Feature branches
- Bug branches
- Hotfix branches
Each of these branches have a specific purpose and are bound to strict rules as to which branches may be their originating branch and which branches must be their merge targets. Each branch and its usage is explained below.
Feature branches are used when developing a new feature or enhancement which has the potential of a development lifespan longer than a single deployment. When starting development, the deployment in which this feature will be released may not be known. No matter when the feature branch will be finished, it will always be merged back into the main branch.
During the lifespan of the feature development, the lead should watch the main branch (network tool or branch tool in GitHub) to see if there have been commits since the feature was branched. Any and all changes to main should be merged into the feature before merging back to main; this can be done at various times during the project or at the end, but time to handle merge conflicts should be accounted for.
- Must branch from:
main - Must merge back into:
main - Branch naming convention:
feature-[id]
If the branch does not exist yet (check with the Lead), create the branch locally and then push to GitHub. A feature branch should always be 'publicly' available. That is, development should never exist in just one developer's local branch.
$ git checkout -b feature-id master // creates a local branch for the new feature
$ git push origin feature-id // makes the new feature remotely available
Periodically, changes made to main (if any) should be merged back into your feature branch.
$ git merge main // merges changes from master into feature branch
When development on the feature is complete, the lead (or engineer in charge) should merge changes into main and then make sure the remote branch is deleted.
$ git checkout main // change to the main branch
$ git merge --no-ff feature-id // makes sure to create a commit object during merge
$ git push origin main // push merge changes
$ git push origin :feature-id // deletes the remote branch
Bug branches differ from feature branches only semantically. Bug branches will be created when there is a bug on the live site that should be fixed and merged into the next deployment. For that reason, a bug branch typically will not last longer than one deployment cycle. Additionally, bug branches are used to explicitly track the difference between bug development and feature development. No matter when the bug branch will be finished, it will always be merged back into main.
Although likelihood will be less, during the lifespan of the bug development, the lead should watch the main branch (network tool or branch tool in GitHub) to see if there have been commits since the bug was branched. Any and all changes to main should be merged into the bug before merging back to main; this can be done at various times during the project or at the end, but time to handle merge conflicts should be accounted for.
- Must branch from:
main - Must merge back into:
main - Branch naming convention:
bug-[id]
If the branch does not exist yet (check with the Lead), create the branch locally and then push to GitHub. A bug branch should always be 'publicly' available. That is, development should never exist in just one developer's local branch.
$ git checkout -b bug-id main // creates a local branch for the new bug
$ git push origin bug-id // makes the new bug remotely available
Periodically, changes made to main (if any) should be merged back into your bug branch.
$ git merge main // merges changes from main into bug branch
When development on the bug is complete, [the Lead] should merge changes into main and then make sure the remote branch is deleted.
$ git checkout main // change to the main branch
$ git merge --no-ff bug-id // makes sure to create a commit object during merge
$ git push origin main // push merge changes
$ git push origin :bug-id // deletes the remote branch
A hotfix branch comes from the need to act immediately upon an undesired state of a live production version. Additionally, because of the urgency, a hotfix is not required to be be pushed during a scheduled deployment. Due to these requirements, a hotfix branch is always branched from a tagged main branch. This is done for two reasons:
-
Development on the
mainbranch can continue while the hotfix is being addressed. -
A tagged
prodbranch still represents what is in production. At the point in time where a hotfix is needed, there could have been multiple commits tomainwhich would then no longer represent production. -
Must branch from: tagged
prod -
Must merge back into:
mainandprod -
Branch naming convention:
hotfix-[id]
If the branch does not exist yet (check with the Lead), create the branch locally and then push to GitHub. A hotfix branch should always be 'publicly' available. That is, development should never exist in just one developer's local branch.
$ git checkout -b hotfix-id main // creates a local branch for the new hotfix
$ git push origin hotfix-id // makes the new hotfix remotely available
When development on the hotfix is complete, [the Lead] should merge changes into prod and then update the tag.
$ git checkout main // change to the main branch
$ git merge --no-ff hotfix-id // forces creation of commit object during merge
$ git tag -a <tag> // tags the fix
$ git push origin main --tags // push tag changes
Merge changes into main so not to lose the hotfix and then delete the remote hotfix branch.
$ git checkout main // change to the main branch
$ git merge --no-ff hotfix-id // forces creation of commit object during merge
$ git push origin main // push merge changes
$ git push origin :hotfix-id // deletes the remote branch
See where your local files are at
git status
Move to main branch
git checkout main
Pull from main
git pull origin main
Merge feature branch with main branch
git merge feature-slider-mobile-fix
Merge feature branch with dev branch
```
git checkout dev
git merge feature-slider-mobile-fix
```
Check your remote setup
git remote -v
Pull changes from main
git pull origin main
Add all files to commit
git add .
Set remote repository URL
git remote add origin https://github.com/engagingnewsproject/misinfo-dashboard.git