Remove internal table CRUD APIs
Removed public CRUD for internal tables: - Deleted /api/meta - internal key-value store - Deleted /api/users - use auth endpoints instead - Removed CLI commands: user admin and meta operations Core app tables with CRUD: ✅ tasks - Full CRUD ✅ projects - Full CRUD (list, get, create, update, delete) ✅ sprints - Full CRUD (list, get, create, update, delete) Auth tables (internal, no public CRUD): - users - Managed via /api/auth/* endpoints - sessions - Managed by auth system - password_reset_tokens - Managed by forgot/reset flow - meta - Internal use only
This commit is contained in:
parent
b0fc52ade4
commit
9778c20dbf
127
scripts/gantt.sh
127
scripts/gantt.sh
@ -526,98 +526,6 @@ cmd_auth_users() {
|
|||||||
api_call GET "/auth/users"
|
api_call GET "/auth/users"
|
||||||
}
|
}
|
||||||
|
|
||||||
#===================
|
|
||||||
# USER ADMIN OPERATIONS
|
|
||||||
#===================
|
|
||||||
|
|
||||||
cmd_user_get() {
|
|
||||||
local user_id="$1"
|
|
||||||
|
|
||||||
if [ -z "$user_id" ]; then
|
|
||||||
log_error "Usage: user get <user-id>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_info "Fetching user $user_id..."
|
|
||||||
api_call GET "/users?id=$user_id" | jq '.user'
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_user_update() {
|
|
||||||
local user_id="$1"
|
|
||||||
local field="$2"
|
|
||||||
local value="$3"
|
|
||||||
|
|
||||||
if [ -z "$user_id" ] || [ -z "$field" ] || [ -z "$value" ]; then
|
|
||||||
log_error "Usage: user update <user-id> <field> <value>"
|
|
||||||
echo "Fields: name, email, avatar_url"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_info "Updating user $user_id: $field = $value"
|
|
||||||
local data
|
|
||||||
data=$(jq -n --arg id "$user_id" --arg field "$field" --arg value "$value" \
|
|
||||||
'{id: $id, ($field): $value}')
|
|
||||||
api_call PATCH "/users" "$data"
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_user_delete() {
|
|
||||||
local user_id="$1"
|
|
||||||
|
|
||||||
if [ -z "$user_id" ]; then
|
|
||||||
log_error "Usage: user delete <user-id>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_warn "Deleting user $user_id..."
|
|
||||||
api_call DELETE "/users" "{\"id\": \"$user_id\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
#===================
|
|
||||||
# META OPERATIONS
|
|
||||||
#===================
|
|
||||||
|
|
||||||
cmd_meta_list() {
|
|
||||||
log_info "Fetching meta entries..."
|
|
||||||
api_call GET "/meta" | jq '.meta'
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_meta_get() {
|
|
||||||
local key="$1"
|
|
||||||
|
|
||||||
if [ -z "$key" ]; then
|
|
||||||
log_error "Usage: meta get <key>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_info "Fetching meta key: $key"
|
|
||||||
api_call GET "/meta?key=$key" | jq '.meta | .[0]'
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_meta_set() {
|
|
||||||
local key="$1"
|
|
||||||
local value="$2"
|
|
||||||
|
|
||||||
if [ -z "$key" ] || [ -z "$value" ]; then
|
|
||||||
log_error "Usage: meta set <key> <value>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_info "Setting meta $key = $value"
|
|
||||||
api_call POST "/meta" "{\"key\": \"$key\", \"value\": \"$value\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_meta_delete() {
|
|
||||||
local key="$1"
|
|
||||||
|
|
||||||
if [ -z "$key" ]; then
|
|
||||||
log_error "Usage: meta delete <key>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_warn "Deleting meta key: $key"
|
|
||||||
api_call DELETE "/meta" "{\"key\": \"$key\"}"
|
|
||||||
}
|
|
||||||
|
|
||||||
#===================
|
#===================
|
||||||
# DEBUG OPERATIONS
|
# DEBUG OPERATIONS
|
||||||
#===================
|
#===================
|
||||||
@ -683,19 +591,6 @@ AUTH COMMANDS:
|
|||||||
auth account <field> <value> Update account (name, email)
|
auth account <field> <value> Update account (name, email)
|
||||||
auth users List all users
|
auth users List all users
|
||||||
|
|
||||||
USER ADMIN COMMANDS:
|
|
||||||
user list List all users (same as auth users)
|
|
||||||
user get <user-id> Get specific user
|
|
||||||
user update <id> <field> <val> Update user field
|
|
||||||
Fields: name, email, avatar_url
|
|
||||||
user delete <user-id> Delete a user
|
|
||||||
|
|
||||||
META COMMANDS:
|
|
||||||
meta list List all meta entries
|
|
||||||
meta get <key> Get specific meta value
|
|
||||||
meta set <key> <value> Set meta key-value pair
|
|
||||||
meta delete <key> Delete meta entry
|
|
||||||
|
|
||||||
OTHER COMMANDS:
|
OTHER COMMANDS:
|
||||||
debug Call debug endpoint
|
debug Call debug endpoint
|
||||||
help Show this help message
|
help Show this help message
|
||||||
@ -787,28 +682,6 @@ main() {
|
|||||||
*) log_error "Unknown auth command: $subcmd"; show_help; exit 1 ;;
|
*) log_error "Unknown auth command: $subcmd"; show_help; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
user|users)
|
|
||||||
local subcmd="${1:-list}"
|
|
||||||
shift || true
|
|
||||||
case "$subcmd" in
|
|
||||||
list|ls) cmd_auth_users "$@" ;; # Reuse auth users list
|
|
||||||
get|show) cmd_user_get "$@" ;;
|
|
||||||
update|set|edit) cmd_user_update "$@" ;;
|
|
||||||
delete|rm|remove) cmd_user_delete "$@" ;;
|
|
||||||
*) log_error "Unknown user command: $subcmd"; show_help; exit 1 ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
meta)
|
|
||||||
local subcmd="${1:-list}"
|
|
||||||
shift || true
|
|
||||||
case "$subcmd" in
|
|
||||||
list|ls) cmd_meta_list "$@" ;;
|
|
||||||
get|show) cmd_meta_get "$@" ;;
|
|
||||||
set|create|update) cmd_meta_set "$@" ;;
|
|
||||||
delete|rm|remove) cmd_meta_delete "$@" ;;
|
|
||||||
*) log_error "Unknown meta command: $subcmd"; show_help; exit 1 ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
debug) cmd_debug "$@" ;;
|
debug) cmd_debug "$@" ;;
|
||||||
help|--help|-h) show_help ;;
|
help|--help|-h) show_help ;;
|
||||||
*) log_error "Unknown command: $cmd"; show_help; exit 1 ;;
|
*) log_error "Unknown command: $cmd"; show_help; exit 1 ;;
|
||||||
|
|||||||
@ -1,101 +0,0 @@
|
|||||||
import { NextResponse } from "next/server";
|
|
||||||
import { getServiceSupabase } from "@/lib/supabase/client";
|
|
||||||
import { getAuthenticatedUser } from "@/lib/server/auth";
|
|
||||||
|
|
||||||
export const runtime = "nodejs";
|
|
||||||
|
|
||||||
// GET - fetch all meta entries or specific key
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
try {
|
|
||||||
const user = await getAuthenticatedUser();
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const key = searchParams.get("key");
|
|
||||||
|
|
||||||
const supabase = getServiceSupabase();
|
|
||||||
|
|
||||||
let query = supabase.from("meta").select("*");
|
|
||||||
if (key) {
|
|
||||||
query = query.eq("key", key);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data, error } = await query.order("key");
|
|
||||||
|
|
||||||
if (error) throw error;
|
|
||||||
|
|
||||||
return NextResponse.json({ meta: data || [] });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(">>> API GET /meta error:", error);
|
|
||||||
return NextResponse.json({ error: "Failed to fetch meta" }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST - create or update a meta entry
|
|
||||||
export async function POST(request: Request) {
|
|
||||||
try {
|
|
||||||
const user = await getAuthenticatedUser();
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = await request.json();
|
|
||||||
const { key, value } = body;
|
|
||||||
|
|
||||||
if (!key || typeof key !== "string") {
|
|
||||||
return NextResponse.json({ error: "Missing key" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value === undefined) {
|
|
||||||
return NextResponse.json({ error: "Missing value" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const supabase = getServiceSupabase();
|
|
||||||
const now = new Date().toISOString();
|
|
||||||
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from("meta")
|
|
||||||
.upsert({
|
|
||||||
key,
|
|
||||||
value: String(value),
|
|
||||||
updated_at: now,
|
|
||||||
})
|
|
||||||
.select()
|
|
||||||
.single();
|
|
||||||
|
|
||||||
if (error) throw error;
|
|
||||||
|
|
||||||
return NextResponse.json({ success: true, meta: data });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(">>> API POST /meta error:", error);
|
|
||||||
return NextResponse.json({ error: "Failed to save meta" }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE - delete a meta entry
|
|
||||||
export async function DELETE(request: Request) {
|
|
||||||
try {
|
|
||||||
const user = await getAuthenticatedUser();
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { key } = await request.json();
|
|
||||||
|
|
||||||
if (!key) {
|
|
||||||
return NextResponse.json({ error: "Missing key" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const supabase = getServiceSupabase();
|
|
||||||
const { error } = await supabase.from("meta").delete().eq("key", key);
|
|
||||||
|
|
||||||
if (error) throw error;
|
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(">>> API DELETE /meta error:", error);
|
|
||||||
return NextResponse.json({ error: "Failed to delete meta" }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,118 +0,0 @@
|
|||||||
import { NextResponse } from "next/server";
|
|
||||||
import { getServiceSupabase } from "@/lib/supabase/client";
|
|
||||||
import { getAuthenticatedUser } from "@/lib/server/auth";
|
|
||||||
|
|
||||||
export const runtime = "nodejs";
|
|
||||||
|
|
||||||
// GET - fetch single user by ID
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
try {
|
|
||||||
const currentUser = await getAuthenticatedUser();
|
|
||||||
if (!currentUser) {
|
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get("id");
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: "Missing user id" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const supabase = getServiceSupabase();
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from("users")
|
|
||||||
.select("id, name, email, avatar_url, created_at")
|
|
||||||
.eq("id", id)
|
|
||||||
.single();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
if (error.code === "PGRST116") {
|
|
||||||
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json({ user: data });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(">>> API GET /user error:", error);
|
|
||||||
return NextResponse.json({ error: "Failed to fetch user" }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PATCH - update user fields (admin only)
|
|
||||||
export async function PATCH(request: Request) {
|
|
||||||
try {
|
|
||||||
const currentUser = await getAuthenticatedUser();
|
|
||||||
if (!currentUser) {
|
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = await request.json();
|
|
||||||
const { id, ...updates } = body;
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: "Missing user id" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only allow certain fields to be updated
|
|
||||||
const allowedFields = ["name", "email", "avatar_url"];
|
|
||||||
const dbUpdates: Record<string, unknown> = {};
|
|
||||||
|
|
||||||
for (const field of allowedFields) {
|
|
||||||
if (updates[field] !== undefined) {
|
|
||||||
dbUpdates[field] = updates[field];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.keys(dbUpdates).length === 0) {
|
|
||||||
return NextResponse.json({ error: "No valid fields to update" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const supabase = getServiceSupabase();
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from("users")
|
|
||||||
.update(dbUpdates)
|
|
||||||
.eq("id", id)
|
|
||||||
.select("id, name, email, avatar_url, created_at")
|
|
||||||
.single();
|
|
||||||
|
|
||||||
if (error) throw error;
|
|
||||||
|
|
||||||
return NextResponse.json({ success: true, user: data });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(">>> API PATCH /user error:", error);
|
|
||||||
return NextResponse.json({ error: "Failed to update user" }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE - delete a user (admin only)
|
|
||||||
export async function DELETE(request: Request) {
|
|
||||||
try {
|
|
||||||
const currentUser = await getAuthenticatedUser();
|
|
||||||
if (!currentUser) {
|
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id } = await request.json();
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: "Missing user id" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent self-deletion
|
|
||||||
if (id === currentUser.id) {
|
|
||||||
return NextResponse.json({ error: "Cannot delete yourself" }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const supabase = getServiceSupabase();
|
|
||||||
const { error } = await supabase.from("users").delete().eq("id", id);
|
|
||||||
|
|
||||||
if (error) throw error;
|
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(">>> API DELETE /user error:", error);
|
|
||||||
return NextResponse.json({ error: "Failed to delete user" }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user