ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
Fair workload planning for student group assignments
Translation pending
EducationTypeScript · CSSGitHub @MoinIhtejazOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Next.js and Supabase app for university group assignments, teams vote on task effort before anything is assigned, then work is allocated around availability and tracked with a workload fairness score
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Equitask is a full-stack web app for university group assignments that prioritizes fair workload distribution, task effort voting, availability-aware assignment, accountability, and team analytics.
The app now uses Supabase authentication for normal access. Earlier demo-login entry points have
been removed, so users sign up or sign in with a real Supabase-backed account.
Equitask solves group-project imbalance by making effort estimation and assignment transparent:Read the full README ↗Equitask is a full-stack web app for university group assignments that prioritizes fair workload distribution, task effort voting, availability-aware assignment, accountability, and team analytics.
The app now uses Supabase authentication for normal access. Earlier demo-login entry points have been removed, so users sign up or sign in with a real Supabase-backed account.
Equitask solves group-project imbalance by making effort estimation and assignment transparent:
/api/...) for backend logicnpm install
npm run dev
http://localhost:3000
The public demo login flow has been removed. To use the workspace, configure Supabase and sign in through the normal email/password flow.
The codebase still contains seeded data and a provider abstraction for development history and safe fallback testing, but the website no longer exposes a demo login button, settings switch, sidebar switch, or any demo workspace controls in the UI.
Do not hardcode credentials. Add these yourself in local/Vercel:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYNo filled .env file is generated by this project.
Create a project in Supabase and wait for it to initialize.
In Supabase Dashboard:
Authentication -> ProvidersEmailEmail + Password sign-inAdd these to your local environment and Vercel project settings:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSupabase Dashboard -> SQL Editornpm run dev/sign-up and create an account/sign-in/dashboard/teams (Team Hub)teamId) so users return to their team workspace directly.Paste this entire SQL block into Supabase SQL Editor:
-- Extensions
create extension if not exists pgcrypto;
-- Helper function for updated_at
create or replace function public.set_tasks_updated_at()
returns trigger
language plpgsql
as $$
begin
new.updated_at = now();
return new;
end;
$$;
-- Profiles
create table if not exists public.profiles (
id text primary key,
name text not null,
role text not null default 'Student collaborator',
bio text not null default '',
preferred_working_style text not null default '',
availability jsonb not null default '[]'::jsonb,
reliability_score int not null default 80,
avatar_color text not null default '#2f6b4f',
created_at timestamptz not null default now()
);
-- Teams
create table if not exists public.teams (
id text primary key default ('team-' || gen_random_uuid()::text),
name text not null,
project_name text not null,
created_by text not null references public.profiles(id) on delete restrict,
created_at timestamptz not null default now()
);
-- Team membership
create table if not exists public.team_members (
team_id text not null references public.teams(id) on delete cascade,
profile_id text not null references public.profiles(id) on delete cascade,
member_role text not null default 'member',
joined_at timestamptz not null default now(),
primary key (team_id, profile_id)
);
-- Membership helper for RLS
create or replace function public.is_member_of_team(target_team_id text)
returns boolean
language sql
stable
security definer
set search_path = public
as $$
select exists (
select 1
from public.team_members tm
where tm.team_id = target_team_id
and tm.profile_id = auth.uid()::text
);
$$;
revoke all on function public.is_member_of_team(text) from public;
grant execute on function public.is_member_of_team(text) to authenticated;
-- Tasks
create table if not exists public.tasks (
id text primary key default ('task-' || gen_random_uuid()::text),
team_id text not null references public.teams(id) on delete cascade,
title text not null,
description text not null default '',
status text not null check (status in ('backlog', 'todo', 'in_progress', 'review', 'done')),
priority text not null check (priority in ('low', 'medium', 'high', 'critical')),
tags text[] not null default '{}',
due_date date not null,
assignee_id text references public.profiles(id) on delete set null,
voting_required boolean not null default true,
voting_closed boolean not null default false,
official_story_points numeric(6,2),
created_by text not null references public.profiles(id) on delete restrict,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Votes
create table if not exists public.task_votes (
id text primary key default ('vote-' || gen_random_uuid()::text),
task_id text not null references public.tasks(id) on delete cascade,
member_id text not null references public.profiles(id) on delete cascade,
vote_value int not null check (vote_value in (1, 2, 3, 5, 8, 13)),
created_at timestamptz not null default now(),
unique (task_id, member_id)
);
-- Comments
create table if not exists public.comments (
id text primary key default ('comment-' || gen_random_uuid()::text),
task_id text not null references public.tasks(id) on delete cascade,
member_id text not null references public.profiles(id) on delete cascade,
body text not null,
created_at timestamptz not null default now()
);
-- Notifications
create table if not exists public.notifications (
id text primary key default ('notif-' || gen_random_uuid()::text),
team_id text not null references public.teams(id) on delete cascade,
type text not null check (type in ('vote_needed', 'task_overdue', 'task_assigned', 'member_overloaded', 'vote_disagreement', 'deadline_approaching')),
message text not null,
task_id text references public.tasks(id) on delete set null,
member_id text references public.profiles(id) on delete set null,
is_read boolean not null default false,
severity text not null check (severity in ('info', 'warning', 'critical')),
created_at timestamptz not null default now()
);
-- Indexes
create index if not exists idx_team_members_profile on public.team_members(profile_id);
create index if not exists idx_tasks_team_status on public.tasks(team_id, status);
create index if not exists idx_tasks_assignee on public.tasks(assignee_id);
create index if not exists idx_tasks_due_date on public.tasks(due_date);
create index if not exists idx_votes_task on public.task_votes(task_id);
create index if not exists idx_comments_task on public.comments(task_id);
create index if not exists idx_notifications_team_created on public.notifications(team_id, created_at desc);
-- Trigger
drop trigger if exists trg_tasks_updated_at on public.tasks;
create trigger trg_tasks_updated_at
before update on public.tasks
for each row
execute function public.set_tasks_updated_at();
-- RLS
alter table public.profiles enable row level security;
alter table public.teams enable row level security;
alter table public.team_members enable row level security;
alter table public.tasks enable row level security;
alter table public.task_votes enable row level security;
alter table public.comments enable row level security;
alter table public.notifications enable row level security;
-- Profiles policies (intentionally permissive for team-seeding workflow)
drop policy if exists profiles_select_authenticated on public.profiles;
create policy profiles_select_authenticated
on public.profiles
for select
using (auth.role() = 'authenticated');
drop policy if exists profiles_insert_authenticated on public.profiles;
create policy profiles_insert_authenticated
on public.profiles
for insert
with check (auth.role() = 'authenticated');
drop policy if exists profiles_update_authenticated on public.profiles;
create policy profiles_update_authenticated
on public.profiles
for update
using (auth.role() = 'authenticated')
with check (auth.role() = 'authenticated');
-- Teams policies
drop policy if exists teams_select_member on public.teams;
create policy teams_select_member
on public.teams
for select
using (public.is_member_of_team(id) or created_by = auth.uid()::text);
drop policy if exists teams_insert_owner on public.teams;
create policy teams_insert_owner
on public.teams
for insert
with check (created_by = auth.uid()::text);
drop policy if exists teams_update_member on public.teams;
create policy teams_update_member
on public.teams
for update
using (public.is_member_of_team(id))
with check (public.is_member_of_team(id));
-- Team member policies
drop policy if exists team_members_select_member on public.team_members;
create policy team_members_select_member
on public.team_members
for select
using (
profile_id = auth.uid()::text
or exists (
select 1
from public.teams t
where t.id = team_id
and t.created_by = auth.uid()::text
)
);
drop policy if exists team_members_insert_member on public.team_members;
create policy team_members_insert_member
on public.team_members
for insert
with check (
profile_id = auth.uid()::text
or exists (
select 1
from public.teams t
where t.id = team_id
and t.created_by = auth.uid()::text
)
);
drop policy if exists team_members_update_member on public.team_members;
create policy team_members_update_member
on public.team_members
for update
using (
exists (
select 1
from public.teams t
where t.id = team_id
and t.created_by = auth.uid()::text
)
)
with check (
exists (
select 1
from public.teams t
where t.id = team_id
and t.created_by = auth.uid()::text
)
);
-- Tasks policies
drop policy if exists tasks_select_member on public.tasks;
create policy tasks_select_member
on public.tasks
for select
using (public.is_member_of_team(team_id));
drop policy if exists tasks_insert_member on public.tasks;
create policy tasks_insert_member
on public.tasks
for insert
with check (public.is_member_of_team(team_id));
drop policy if exists tasks_update_member on public.tasks;
create policy tasks_update_member
on public.tasks
for update
using (public.is_member_of_team(team_id))
with check (public.is_member_of_team(team_id));
drop policy if exists tasks_delete_member on public.tasks;
create policy tasks_delete_member
on public.tasks
for delete
using (public.is_member_of_team(team_id));
-- Votes policies
drop policy if exists votes_select_member on public.task_votes;
create policy votes_select_member
on public.task_votes
for select
using (
exists (
select 1
from public.tasks t
where t.id = task_id
and public.is_member_of_team(t.team_id)
)
);
drop policy if exists votes_insert_member on public.task_votes;
create policy votes_insert_member
on public.task_votes
for insert
with check (
exists (
select 1
from public.tasks t
where t.id = task_id
and public.is_member_of_team(t.team_id)
)
);
drop policy if exists votes_update_member on public.task_votes;
create policy votes_update_member
on public.task_votes
for update
using (
exists (
select 1
from public.tasks t
where t.id = task_id
and public.is_member_of_team(t.team_id)
)
)
with check (
exists (
select 1
from public.tasks t
where t.id = task_id
and public.is_member_of_team(t.team_id)
)
);
-- Comments policies
drop policy if exists comments_select_member on public.comments;
create policy comments_select_member
on public.comments
for select
using (
exists (
select 1
from public.tasks t
where t.id = task_id
and public.is_member_of_team(t.team_id)
)
);
drop policy if exists comments_insert_member on public.comments;
create policy comments_insert_member
on public.comments
for insert
with check (
exists (
select 1
from public.tasks t
where t.id = task_id
and public.is_member_of_team(t.team_id)
)
);
-- Notifications policies
drop policy if exists notifications_select_member on public.notifications;
create policy notifications_select_member
on public.notifications
for select
using (public.is_member_of_team(team_id));
drop policy if exists notifications_insert_member on public.notifications;
create policy notifications_insert_member
on public.notifications
for insert
with check (public.is_member_of_team(team_id));
drop policy if exists notifications_update_member on public.notifications;
create policy notifications_update_member
on public.notifications
for update
using (public.is_member_of_team(team_id))
with check (public.is_member_of_team(team_id));
No storage bucket is required for the current app features.
/sign-up and create a user.team-... id shared by teammate)./sign-in and authenticate./dashboard/teams./board, create a new task with title/description/due date./voting or task detail, then assign after voting closes.src/
app/
(auth)/
(workspace)/
teams/
api/
teams/
components/
teams/
data/
providers/
seed/
lib/
services/
types/
demoProvider for development history and provider
abstraction.supabaseteamId, team/project metadata)supabaseProvider)The app uses:
demoProvidersupabaseProviderauthServicetaskServicevoteServicememberServiceanalyticsServicefairnessServicenotificationServiceteamServiceworkspaceServiceThis avoids business-logic duplication. The live website now uses Supabase-backed data for normal user access.
Fairness score (0-100) is calculated from:
The score and breakdown are visible in dashboard and analytics.
1, 2, 3, 5, 8, 13max - min) is surfacedNEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYNo custom Node server is required; app uses standard Next.js conventions.
/sign-in or /sign-up to create a Supabase session./teams)./board and submit votes so charts have dataset to render./sign-in.team_members.teams.id value (format starts with team-).