Building with NextJS (When You'd Rather Use Svelte)
Introduction
I’ve always loved Svelte, the syntax is clean, the Runes system is superior, and it doesn’t force you to learn a dozen concepts just to build a webpage. I am definitely not big on web development and especially front end, but it remains in my philosophy the biggest and best way to express what your product is about, If you build a super duper algorithm that unlocks a huge bottleneck for a client but they will need a UI to interact with it, you can go and carve the rocks with tkinter or something similar or -god help you- try to build a gui in C++ (if you are not already an expert in it) so for the most part, using a web platform as the ui is the easiest way, especially with the rise of tauri or its cousin electron and other webview based runtimes.
While Svelte remains my goto choice, I am building this project in NextJS. Maybe then I will understand if it has upsides pushing it to the top other than having Vercel shoving millions of dollars to promote it to everyone in existence only to end up having one of the most dangerous threats to ever exist CVE-2025-55182. You can argue that the issue is in React and that they are simply building on top of it, but you should have been careful Vercel.
The best way to learn a framework is to build something real. I’m creating a task management app, but I am not into lame projects and if there is ever a lame project contender it’s going to be task management. Here’s what makes it different: I manage many projects and use GitHub extensively for issues and feature requests. I’m integrating the GitHub API to sync issues as tasks, add custom priorities, and include a task scheduler.
This series documents the journey of building my “not so lame” project management platform, hopefully I will be able to document my decision making and thought process along with my code.
Choosing the Stack
Obviously I will be choosing NextJS for the frontend (No surprises there), and for the backend I will choose Go. Our DB is the good old reliable sqlite which is more than the sufficient for our single-user use case. When it comes to libraries, I will use the built-in net/http library in Go and shadcn for components because I don’t want to spend 50% of my time tweaking the button layout. The rest will be uncovered throughout the way.
You might ask, why even use Go or any backend language when you can use NextJS’ server side features to serve your db, This is for many reasons:
- I am definitely building a mobile app using either Tauri or Capacitor (Haven’t decided yet) as soon as I am done with this app.
- I am not building this tool to be OK, I am building it to perfectly integrate into my workflow with extensibility in mind, meaning that some totally unrelated features might need to be added and I don’t want any future limitation to be the technology.
DB Arch
Right after developing even a basic understanding of the problem, I like to put it into a draft sql, I do multiple iterations evolving it into the ready sql migration to use in my db. This helps me organize my understanding of the problem and at the same time helps me feel like I already kick started the project.
For example my initial idea of the database would be:
CREATE TABLE projects (
id INTEGER PRIMARY KEY,
name TEXT,
created_at TIMESTAMP,
updated_at TIMESTAMP,
status TEXT
)
CREATE TABLE tasks (
id INTEGER PRIMARY KEY,
project_id INTEGER REFERENCES projects(id),
github_issue_id INTEGER,
title TEXT,
description TEXT,
status TEXT,
priority INT,
created_at TIMESTAMP,
updated_at TIMESTAMP
) And then I would evolve it into something like this:
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); -- Even though it's single-user for now, I'm adding a basic Users table so I don't have to rewrite the auth logic later if I open it up + it's a good practice to have users table when handling sessions
CREATE TABLE sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
token TEXT NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NOT NULL
);
CREATE TABLE projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
project_description TEXT,
project_category TEXT CHECK (project_category IN ('personal', 'work', 'hobby', 'other')) DEFAULT 'personal',
due_date TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status TEXT CHECK (status IN ('active', 'completed', 'archived')) DEFAULT 'active'
);
CREATE TABLE tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_id INTEGER REFERENCES projects(id) ON DELETE CASCADE,
github_issue_id INTEGER,
title TEXT NOT NULL,
description TEXT,
status TEXT CHECK (status IN ('todo', 'in_progress', 'done')) DEFAULT 'todo',
priority INTEGER CHECK (priority BETWEEN 1 AND 5) DEFAULT 3,
estimated_duration_minutes INTEGER,
scheduled_start TIMESTAMP,
scheduled_end TIMESTAMP,
due_date TIMESTAMP,
depends_on_task_id INTEGER REFERENCES tasks(id),
completed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_tasks_project_id ON tasks(project_id);
CREATE INDEX idx_tasks_status ON tasks(status);
CREATE INDEX idx_tasks_priority ON tasks(priority);
CREATE INDEX idx_tasks_due_date ON tasks(due_date); Conclusion
This is just the start of the journey, I will be documenting my progress as I go along building this project. Let me know if you have any suggestions or if you want to see specific parts of the code or architecture in more detail.