ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기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
저장소 README에서 가져옴
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: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-).