Nitrokit Nitrokit - Ship faster with AI - No more heavy lifting, build Angular apps at NITROSPEED!

Getting Started

Install influencer locally

Need to get started quickly with Nitrokit? We'll get you set up in minutes.

Ready to start building your next idea without losing time? Great! That's the spirit. It's better to ship something imperfect now then to ship something solid in a year. The market is changing rapidly and by shipping, we learn and adapt.

Let's install influencer locally on your computer so you can start building immediately

Intro

In this guide, we will install the influencer app locally on your machine. This is a great way to:

  • Explore the application's architecture
  • Remove what you don't need and start experimenting
  • Play around with the code
  • Get insights into app structure
  • Cherry-pick features for your own projects

If you want to create an app from scratch, check out this tutorial.

By the end of this guide, you will have:

  • A fully functional influencer app running on your local machine
  • A new Supabase project to experiment with
  • Integrated authentication and calendar features

This guide is not a Supabase course but a step-by-step guide to setting up influencer locally.

Create a new supabase project

For this tutorial we are going to assume that you use the cloud version of supabase (which has 2 projects for free) How great is that?! I'm going to assume this because the setup to installing supabase locally involves docker and is more complex. So let's go to https://supabase.com/dashboard/sign-up if you don't have an account yet, and if you do go to https://supabase.com/dashboard/sign-in

No let's click on the green New project button to create a new project. Choose your default organization and chose a project name. Let's use influencer

Generating the Tables

First, you need to create a new Supabase project.

Once you’ve done that, let’s create the necessary tables. In your Supabase dashboard, navigate to the SQL Editor and run the following SQL:

CREATE TYPE social_media_platform AS ENUM ('linkedin', 'x', 'youtube', 'instagram', 'facebook', 'tiktok', 'other');
CREATE TABLE public.products (
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    profile_id uuid NOT NULL,
    name text NOT NULL,
    description text NOT NULL,
    display_name text NOT NULL DEFAULT 'test',
    github_access_token text,
    id uuid DEFAULT gen_random_uuid() NOT NULL
);

ALTER TABLE public.products OWNER TO postgres;

CREATE TABLE public.channels (
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    profile_id uuid NOT NULL,
    name text NOT NULL,
    platform social_media_platform NOT NULL DEFAULT 'other',
    color text NOT NULL,
    id uuid DEFAULT gen_random_uuid() NOT NULL
);

ALTER TABLE public.channels OWNER TO postgres;

CREATE TABLE public.ideas (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    profile_id uuid NOT NULL,
    name text NOT NULL,
    content text,
    media_path text,
    topic_id uuid NOT NULL,
    recurring_task_id uuid NOT NULL,
    publish_date timestamp with time zone,
    released boolean DEFAULT false NOT NULL,
    verified boolean DEFAULT false NOT NULL
);

ALTER TABLE public.ideas OWNER TO postgres;

CREATE TABLE public.profiles (
    id uuid NOT NULL,
    updated_at timestamp with time zone,
    username text,
    full_name text,
    avatar_url text,
    default_data_generated boolean DEFAULT false NOT NULL,
    email text NOT NULL,
    CONSTRAINT username_length CHECK ((char_length(username) >= 3))
);

ALTER TABLE public.profiles OWNER TO postgres;

CREATE TABLE public.recurring_tasks (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    name text NOT NULL,
    description text NOT NULL,
    profile_id uuid NOT NULL,
    repetition_type character varying NOT NULL,
    repeat_every_amount numeric,
    repeat_every_week_values numeric[],
    execute_on timestamp with time zone NOT NULL,
    channel_id uuid NOT NULL,
    product_id uuid NOT NULL,
    CONSTRAINT recurring_tasks_duration_type_check CHECK (((repetition_type)::text = ANY ((ARRAY['none'::character varying, 'day'::character varying, 'week'::character varying])::text[])))
);

ALTER TABLE public.recurring_tasks OWNER TO postgres;

COMMENT ON COLUMN public.recurring_tasks.repetition_type IS 'The type of the duration';

CREATE TABLE public.todos (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    profile_id uuid NOT NULL,
    label text NOT NULL,
    description text
);

ALTER TABLE public.todos OWNER TO postgres;

CREATE TABLE public.topics (
    id uuid DEFAULT gen_random_uuid() NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    label text NOT NULL,
    goal text NOT NULL,
    content text,
    github_content_url text,
    product_id uuid NOT NULL,
    profile_id uuid NOT NULL
);

ALTER TABLE public.topics OWNER TO postgres;

-- Set primary and foreign key constraints
ALTER TABLE ONLY public.products ADD CONSTRAINT products_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.channels ADD CONSTRAINT channels_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.ideas ADD CONSTRAINT ideas_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.recurring_tasks ADD CONSTRAINT recurring_tasks_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.todos ADD CONSTRAINT todos_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.topics ADD CONSTRAINT topics_pkey PRIMARY KEY (id);

ALTER TABLE public.profiles ADD PRIMARY KEY (id);
ALTER TABLE ONLY public.profiles ADD CONSTRAINT profiles_id_fkey FOREIGN KEY (id) REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.products ADD CONSTRAINT products_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES public.profiles(id);
ALTER TABLE ONLY public.channels ADD CONSTRAINT channels_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES public.profiles(id);
ALTER TABLE ONLY public.ideas ADD CONSTRAINT ideas_topic_id_fkey FOREIGN KEY (topic_id) REFERENCES public.topics(id);
ALTER TABLE ONLY public.ideas ADD CONSTRAINT ideas_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES public.profiles(id);
ALTER TABLE ONLY public.ideas ADD CONSTRAINT ideas_recurring_task_id_fkey FOREIGN KEY (recurring_task_id) REFERENCES public.recurring_tasks(id);
ALTER TABLE ONLY public.recurring_tasks ADD CONSTRAINT recurring_tasks_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id);
ALTER TABLE ONLY public.recurring_tasks ADD CONSTRAINT recurring_tasks_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);
ALTER TABLE ONLY public.todos ADD CONSTRAINT todos_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES public.profiles(id);
ALTER TABLE ONLY public.topics ADD CONSTRAINT topics_profile_id_fkey FOREIGN KEY (profile_id) REFERENCES public.profiles(id);
ALTER TABLE ONLY public.topics ADD CONSTRAINT topics_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id);

Click Run to execute the SQL, and if successful, you will see the message Success. No rows returned.

Enable RLS for Your App

Next, enable Row-Level Security (RLS) for all the tables. Go to Authentication > Policies and click Enable RLS.

Go back to the SQL Editor, copy and run this SQL:

CREATE POLICY "Enable all for users based on profile_id" ON public.recurring_tasks TO authenticated USING ((auth.uid() = profile_id)) WITH CHECK ((auth.uid() = profile_id));
CREATE POLICY "Enable all for users based on profile_id" ON public.todos USING ((auth.uid() = profile_id)) WITH CHECK ((auth.uid() = profile_id));
CREATE POLICY "Enable all for users based on profile_id" ON public.ideas USING ((auth.uid() = profile_id)) WITH CHECK ((auth.uid() = profile_id));
CREATE POLICY "Enable all for users based on profile_id" ON public.topics USING ((auth.uid() = profile_id)) WITH CHECK ((auth.uid() = profile_id));
CREATE POLICY "Enable crud for users based on profile_id" ON public.products TO authenticated USING ((auth.uid() = profile_id)) WITH CHECK ((auth.uid() = profile_id));
CREATE POLICY "Enable crud for users based on profile_id" ON public.channels TO authenticated USING ((auth.uid() = profile_id)) WITH CHECK ((auth.uid() = profile_id));
CREATE POLICY "Public profiles are viewable by the user." ON public.profiles FOR SELECT USING ((auth.uid() = id));
CREATE POLICY "Users can insert their own profile." ON public.profiles FOR INSERT WITH CHECK ((auth.uid() = id));
CREATE POLICY "Users can update their own profile." ON public.profiles FOR UPDATE USING ((auth.uid() = id));

Turn on Realtime

To enable real-time updates for your app, run this SQL in the SQL Editor:

ALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.products;
ALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.channels;
ALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.recurring_tasks;
ALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.todos;
ALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.ideas;
ALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.topics;

Add Functions

Next, add some necessary functions, including one to handle new users, avatars, and profile deletions. Run this in the SQL Editor:

CREATE FUNCTION public.handle_new_user() RETURNS trigger
    LANGUAGE plpgsql SECURITY DEFINER
    AS $$
begin
  insert into public.profiles (id, full_name, avatar_url, email, username)
  values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url', new.email, new.email);
  return new;
end;
$$;

ALTER FUNCTION public.handle_new_user() OWNER TO postgres;
CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();

insert into storage.buckets (id, name) values ('avatars', 'avatars');

-- Set up access controls for storage.
create policy "Avatar images are publicly accessible." on storage.objects for select using (bucket_id = 'avatars');
create policy "Anyone can upload an avatar." on storage.objects for insert with check (bucket_id = 'avatars');
create policy "Anyone can update their own avatar." on storage.objects for update using ((select auth.uid()) = owner) with check (bucket_id = 'avatars');

Configuring Redirect URLs

Go to Authentication > URL Configuration and

add http://localhost:4200 as the redirect URL.

Connecting in Your Angular Code

In your Supabase project’s home, you will see the Project URL and API Key.

Open apps/influencer/src/environments/environment.ts and replace supabaseUrl and supabaseKey with the values you found in your Supabase dashboard.

Serve the Project

You can now serve the project using this command:

npx nx run influencer:serve

Logging In

To test the login flow, make sure your redirect URL is set to http://localhost:4200 in the Supabase dashboard under Authentication > URL Configuration.

Log in using your email. You’ll receive a Check your email prompt. Confirm the email and you’ll be automatically logged in.

Update Typings

In the Supabase dashboard, go to Settings > General and copy the Reference ID from the URL.

Next, update the script in your package.json:

"generate-supabase-types:influencer": "npx supabase gen types typescript --project-id=\"<your-reference-id>\" --schema public > libs/shared/type-supabase/src/lib/types/supabase.type.ts"

Before running the script, you have to log in.

npx supabase login

When you make database changes, regenerate your typings by running:

npm run generate-supabase-types:influencer

Congratz

You have set up influencer locally in no-time!

Have questions?

Still have questions? Talk to support.

Previous
Influencer