开发者
Decoding JWT: It's Not Encryption, It's a Signature
Every API request needs to answer: who is this, and are they allowed? Session auth answers it by having the server remember every login. JWT answers it by making the client carry its own proof — no server memory needed. What's inside a token Header . Payload . Signature. Header and payload are just base64-encoded — readable by anyone, not encrypted. The signature is what matters: a hash of the header + payload, made with a secret key only the server knows. Change one character of the payload, the signature breaks, the server rejects it. Trust comes from the math, not from hiding the data. Client logs in with credentials Server verifies them, signs a token, sends it back Client attaches the token to every future request Server checks the signature — no database lookup Valid + not expired → request proceeds No session table anywhere. The auth state lives inside the token itself. The trade-off Can't instantly revoke a token — it's valid until it expires. Fix: short-lived access tokens + a revocable refresh token. Payload is readable, so never put sensitive data in it. Security comes from HTTPS + safe client-side storage, not secrecy. One-liner to remember it by Session auth: remember who logged in, check memory each time. JWT: remember nothing, verify the proof each time.
AI 资讯
Building an E-commerce Backend: Auth, Cart, and Transactional Orders with Prisma
This is the second stage of my CodeAlpha Full Stack internship — two projects, built in a deliberate order so the patterns from the first carry forward. First was a project management tool (auth + real-time updates with Socket.io). This one is a store: products, cart, orders. Same stack — Express, Prisma, PostgreSQL, JWT — but the interesting part isn't the CRUD, it's the order-placement flow, which is the first genuinely transactional piece of logic in the whole internship. I'll walk through the schema decisions, the auth changes from project one, and then spend most of the time on the part that actually matters: making sure an order can never be created without correctly and atomically updating stock and clearing the cart. The schema model User { id String @id @default(cuid()) name String email String @unique password String role String @default("USER") createdAt DateTime @default(now()) orders Order[] cartItems CartItem[] } model Product { id String @id @default(cuid()) name String description String price Float image String? stock Int @default(0) category String createdAt DateTime @default(now()) cartItems CartItem[] orderItems OrderItem[] } model CartItem { id String @id @default(cuid()) quantity Int @default(1) user User @relation(fields: [userId], references: [id]) userId String product Product @relation(fields: [productId], references: [id]) productId String @@unique([userId, productId]) } model Order { id String @id @default(cuid()) status String @default("PENDING") total Float createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) userId String items OrderItem[] } model OrderItem { id String @id @default(cuid()) quantity Int price Float order Order @relation(fields: [orderId], references: [id]) orderId String product Product @relation(fields: [productId], references: [id]) productId String } Two decisions worth explaining, because they're easy to get wrong if you're building this for the first time. OrderItem.price is a
AI 资讯
The Internet's First Message Was 'LO'
The first message ever sent across the network that became the internet was not a grand declaration. It was two letters: "LO" . Not a word anyone chose, not a slogan, just the first half of a login command that never finished because the system crashed. More than fifty years later, that accidental fragment is one of the best origin stories in computing, and it still has something to teach anyone building connected devices today. The night of 29 October 1969 At around 10:30 in the evening on 29 October 1969, a student programmer named Charley Kline sat at a computer in Leonard Kleinrock's lab at UCLA. His job was to log in to a second machine roughly 350 miles away at the Stanford Research Institute (SRI) in Menlo Park, California. The two computers were among the first nodes of ARPANET, the U.S. Defense Department research network that would eventually grow into the internet. Kline started typing the command LOGIN . To make sure the letters were arriving, he had a colleague at SRI on the phone confirming each keystroke. He typed L , and Stanford confirmed the L. He typed O , and Stanford confirmed the O. Then he typed G , and the SRI machine crashed. So the very first message transmitted over ARPANET was the truncated, unintentional "LO" . Kleinrock has enjoyed pointing out for decades that they could not have scripted anything better: the first word on the internet was "lo," as in "lo and behold." A little over an hour later, after the bug was fixed, Kline completed a full login, but the accidental version is the one history remembers. Why a crash matters more than a clean success It is tempting to treat "LO" as a cute footnote, but the crash is the useful part. ARPANET was not built to be reliable on day one. It was built to discover how to be reliable. Everything we now take for granted about networking, error handling, retransmission, acknowledgements, graceful recovery, exists because early links failed constantly and engineers had to design around failure rath
AI 资讯
I built a free tool to scan your package.json for API deprecations
While researching API changes I noticed something — Google Maps removed DirectionsService on May 1 2026 with no soft fallback. Calls just throw runtime errors after the deadline. Most developers won't know until something breaks. So I built DepRadar — paste your package.json, it checks your exact stack against known deprecations and shows only the ones affecting you, with severity, sunset dates, and migration links. Currently tracks 13 real deprecations across: Google Maps (DirectionsService, DistanceMatrixService removed) OpenAI (Realtime API Beta sunset) AWS SDK v2 (maintenance mode) Microsoft Actionable Messages (retired) moment.js, request package And more Free → depradar.netlify.app Open source → github.com/Ahmed889-code/depradar What deprecations am I missing from your stack?
AI 资讯
The Evolving Agent: How Jean2 Learns Across Sessions
I've been coding with AI agents for about two years. Every major one. Cursor, Copilot, Codex, OpenCode. They're good at generating code. They all share one problem. They forget everything. You finish a session, close the window, and the agent resets. Next time you open it, you're starting from zero. "We use pnpm, not npm." "The database is SQLite, not Postgres." "Don't touch the migrations folder." You repeat yourself. Every. Single. Time. Some tools added memory features. Usually as an afterthought. A pinned file. A custom instruction. A context window that grows until it hits a wall and everything old gets silently dropped. I didn't want a bigger context window. I wanted an agent that accumulates knowledge the way a colleague does. Not by being retrained. By taking notes, writing down what it learned, and reading those notes next time. That's what Jean2 can do. Not through fine-tuning. Not through vector embeddings. Through files on disk that the agent reads and writes itself. But here's the thing: none of this is on by default. By default, Jean2 is as bare as Codex or OpenCode. A blank prompt. No memory. No skills. No session search. You opt in to each layer in workspace settings . That's the point. You build the agent you want, layer by layer. The Four Layers If you turn them on, Jean2's agent has four knowledge layers that persist across sessions. They're not features bolted on top. They're part of the system prompt that gets composed every time a session starts. 1. Workspace Memory Turn on workspace memory in workspace settings , and the workspace gets two files: MEMORY.md for shared knowledge and USER.md for your personal preferences within that workspace. Both live at <workspace>/.jean2/ . The concept is simple. Shared knowledge that's useful for any agent working in that workspace. "We use pnpm." "The database is SQLite." "Don't touch the migrations folder." Whatever agent you bring in, coding specialist, reviewer, docs writer, they all get the same context
AI 资讯
The FTC Settlement With John Deere Is a Huge Win for the Right-to-Repair Movement
After more than a decade of pushback, farmers and repair advocates have won access to equipment and services John Deere had long kept under its control.
AI 资讯
Git tells you what changed. Causari tells you why.
AI coding agents are becoming good enough to touch real codebases. They can refactor files, write tests, change architecture, move logic around, and sometimes modify more code in ten minutes than a human would in an afternoon. That is powerful. But it creates a new debugging problem. Git can tell you what changed . When an AI agent was involved, you often need to know something deeper: Why did this change happen? Which prompt caused this line? Which model produced it? What files did the agent read before writing it? What later changes depended on this agent action? That is the problem I wanted to solve with Causari . Causari is a local CLI for intent-addressable code . It records AI agent actions as causal events: prompts, models, reads, writes, diffs, reasoning, cost, and relationships between actions. The goal is simple: Git tracks bytes. Causari tracks intent and causality. Repository: https://github.com/croviatrust/causari Website: https://causari.dev The problem When a human developer changes code, there is usually some context. A commit message. A pull request. A ticket. A discussion. A design decision. With AI coding agents, the workflow is different. You ask something like this: Refactor the auth flow and add JWT refresh logic. The agent reads files, makes assumptions, writes code, maybe fixes tests, maybe changes something unrelated, then moves on. At the end, you have a diff. But the diff does not tell the full story. A suspicious line appears in auth.ts . Git can show when the line appeared. But Git cannot answer: which prompt produced this exact line? what completion did it come from? did the agent read the right files first? was this part of the original request or an accidental side effect? if I revert this, what downstream work am I also undoing? That gap becomes bigger as agents become more autonomous. The more work agents do, the more we need provenance. Not only code provenance. Intent provenance. The idea: intent-addressable code Causari treats an
AI 资讯
I built on-device workout rep counting in Flutter — here's what actually worked
I'm building TrainWiz , a Flutter app that turns real exercise into a pet-raising game: you do squats or push-ups, your phone counts the reps, and a little creature levels up and evolves. The core technical problem sounds trivial and absolutely is not: count reps from the camera, on-device, without uploading a single frame. Here's what broke along the way, and what finally worked. Why on-device Two reasons: privacy and latency. A fitness camera that streams your body to a server is a non-starter for most people, and rep feedback has to feel instant or the whole "game" loop dies. So everything runs locally with tflite_flutter + an on-device pose model — no footage ever leaves the phone. Naive attempt #1: joint-angle thresholds The obvious approach: track the knee angle, count a rep when it dips below X° and comes back up. // looks fine in a demo, dies in the real world final kneeAngle = angleBetween ( hip , knee , ankle ); if ( ! _down && kneeAngle < 100 ) _down = true ; if ( _down && kneeAngle > 160 ) { reps ++ ; _down = false ; } It demos beautifully. Then real users prop the phone on the floor, stand at an angle, and it falls apart. The trap: a phone camera gives you 2D pose. A "120° knee angle" flattens completely depending on where the camera sits — the same squat reads as 90° or 150° purely from perspective. Lifting to 3D via the model's z doesn't save you either; monocular z is noisy enough that the angle jitters across your threshold and double-counts. Naive attempt #2: a "body-line" gate Next idea: figure out which exercise you're doing so I can pick the right signal. Standing (squat) vs. horizontal (push-up) should be easy — just check if shoulder, hip and heel form a straight line, right? Wrong, again for the 2D reason. In a real push-up shot from the front-corner, shoulder–hip–heel are not collinear on the image plane — perspective bends them. I gated push-up counting on "body is a straight line" and it would just... stop counting mid-set. Nothing is more
AI 资讯
How I Structure Large Next.js Projects — Folder Architecture Guide
Bad nextjs folder structure does not show up on day one. It shows up at month six when three developers search for the checkout form hook and find four copies. I reorganised a client dashboard after exactly that — this guide is the tree I use now on large App Router projects, why each folder exists, mistakes from my first Next.js apps, and the 10-second findability rule . Real folder tree — production-shaped layout my-app/ ├── app/ # routes only — thin pages │ ├── (marketing)/ # route group — shared layout, no URL segment │ │ ├── layout.tsx │ │ ├── page.tsx │ │ └── pricing/page.tsx │ ├── (dashboard)/ │ │ ├── layout.tsx │ │ └── orders/page.tsx │ ├── api/ # route handlers │ │ └── webhooks/stripe/route.ts │ ├── layout.tsx # root layout │ └── globals.css ├── components/ # shared UI — buttons, cards, shell │ ├── ui/ │ └── layout/ ├── features/ # business domains — colocated logic │ ├── auth/ │ │ ├── components/ │ │ ├── hooks/ │ │ └── actions.ts │ └── orders/ │ ├── components/ │ ├── api.ts │ └── types.ts ├── lib/ # server + shared utilities │ ├── db.ts │ └── env.ts ├── hooks/ # truly global client hooks ├── types/ # global TS types ├── data/ # static data, blog posts list └── public/ Routes live in app/ . Business logic lives in features/ . Generic design system pieces live in components/ui . That separation is the whole game. Why each folder exists Folder Purpose Do not put here app/ URLs, layouts, loading.tsx Fat business logic features/ Domain modules (orders, auth) Generic Button components/ui Reusable primitives Order-specific tables lib/ DB clients, env validation React components app/api Webhooks, REST edge cases Every form POST (prefer actions) Thin pages — route files under 40 lines // app/(dashboard)/orders/page.tsx — orchestration only import { OrderTable } from "@/features/orders/components/OrderTable"; import { getOrders } from "@/features/orders/api"; export default async function OrdersPage() { const orders = await getOrders(); return ( <section> <h1>Orders
AI 资讯
A Verdict Is Not Evidence. Test Is Where I Learned the Difference.
The call-order change came back pass-with-risk. I read the recommendation, saw it had a name and a reason, and felt the task close. Then I looked at the row under it. How was this verified: not run. Nobody had run the queue. I had a label. I did not have proof. This is Part 6 of The Contract Think produced a brief. Plan produced a gate. Build executed inside it. Review scored every requirement against a verdict instead of an impression. Review reads the diff and the plan and decides whether one satisfies the other. It does not run the queue. It cannot. Its whole job is judgment about what the code should do. Test is where someone finally checks what the code actually does. I had been treating those two as the same step. They are not. Test asks one question, and a verdict is not the answer For every active requirement, Test asks how it was verified. Command run, manual QA, or a comparison against known-good output. One of those three, or a written reason none of them ran. Not a recommendation. Not a risk level. Evidence. I built the matrix against the plan's requirements and filled in each row. Most had a command behind them. The call-order requirement had nothing. The cell read not run, and it sat directly below a pass-with-risk that already carried a name and a reason. That name had almost been enough for me. A named risk feels handled. It is not. It is a risk with a label on it, waiting for someone to actually look. So I ran the queue Three notifications, all with a real reason to fire within the same tick. The scheduler picked them up and ordered them by priority instead of arrival. Two landed in the sequence the requirement wanted. The third jumped ahead of a lower-priority notification that was still mid-processing. The change worked almost every time. Under one timing condition, it did not. That is the gap a verdict cannot see. Review had marked the requirement partial because the wording left the mechanism open. Running it found a real failure inside the mech
AI 资讯
The Placebo Bug: Why Smart Developers Leave Mistakes in Their Code on Purpose
A few days ago, I was talking to a junior developer who was literally sweating bullets. He had just pushed a feature for a staging website that barely gets 500 users a month. But looking at his senior developer’s reaction? You’d think the guy was managing the infrastructure for Amazon’s Prime Day Sale. “Scale check kiya? What if 10,000 users hit this exact API at 3 AM? Refactor this logic.” The code was perfectly fine for their current requirement. But the senior dev had to find a flaw to justify his hierarchy. This is where the tragedy of modern software engineering begins, and a brilliant, toxic survival hack takes over: The Placebo Bug. What is a Placebo Bug? (The Strategic Distraction) When experienced developers realize that their managers or seniors have a habit of “kami nikalna” (finding faults just for the sake of it), they stop giving them perfect code. Instead, they intentionally leave a very small, harmless, and obvious mistake in the front-end or the script. Maybe an unaligned button. Maybe a funny typo in an error message (like writing “Succesfully” instead of “Successfully”). Maybe a massive padding that makes the UI look slightly weird. When the senior reviews the code, their eyes immediately light up. “Arey! Look at this alignment. Everything else is fine, but fix this button first.” The junior says, “Sorry, my bad. Fixing it right away.” Two minutes later, a new commit is pushed. The senior feels proud that they added value, the junior’s core complex architecture passes without unnecessary refactoring, and everyone goes home happy. It’s not good engineering; it’s human management. This is actually a very old trick in the tech world, famously known as “The Corporate Duck” story. Years ago, a game designer noticed that his manager always forced changes on every project just to prove he was the boss. So, the designer tried a hack: he put a totally random, funny Duck on the main character’s head. The manager reviewed it and said, “Everything looks perfe
AI 资讯
Applying SAST to Infrastructure as Code (Without TFSec)
Static analysis isn't just for application source code. Terraform, Pulumi, OpenTofu, and CloudFormation files are code too — and they get misconfigured just as often as a backend service. A public S3 bucket, a security group open to 0.0.0.0/0 , or an unencrypted RDS instance are all bugs you can catch before apply ever runs. TFSec is the tool most people reach for first, but it's not the only option on the OWASP Source Code Analysis Tools list . In this article I'll use Checkov , a free, open-source policy-as-code scanner built by Bridgecrew (now part of Palo Alto Networks), to scan a Terraform project end to end — from a local scan to a GitHub Actions gate that blocks merges on critical misconfigurations. The same approach works with OpenTofu and Pulumi projects too, since Checkov understands HCL directly and also has native support for Pulumi's rendered plan output and CloudFormation/ARM/Kubernetes manifests. Why Checkov? 100% open source (Apache 2.0), actively maintained, thousands of built-in policies. Understands Terraform, OpenTofu, CloudFormation, Kubernetes, Helm, Dockerfile, ARM, Serverless Framework, and Pulumi (via cdktf /synthesized plans) — one tool across most of your IaC surface. No account or API key required to run locally or in CI. Supports custom policies written in Python or YAML if the built-in rule set doesn't cover something specific to your org. ## 1. The sample infrastructure A small AWS setup with a few intentionally introduced misconfigurations — the kind that get merged during a rushed sprint: # main.tf provider "aws" { region = "us-east-1" } resource "aws_s3_bucket" "data" { bucket = "company-app-data-bucket" } # Vulnerable: bucket has no encryption, no versioning, and is publicly readable resource "aws_s3_bucket_acl" "data_acl" { bucket = aws_s3_bucket . data . id acl = "public-read" } resource "aws_security_group" "web" { name = "web-sg" description = "Allow web traffic" # Vulnerable: SSH open to the entire internet ingress { from_port
AI 资讯
10 Useless NPM Packages You Didn't Know You Needed
We have all been there. You are staring at your screen late at night, trying to optimize a bundle size, or debugging an enterprise pipeline that has been failing for three hours straight. The mainstream development community constantly tells us to only install packages that are high performance, audited for security, and strictly necessary for production. But where is the fun in a perfectly clean node_modules folder? Sometimes, the ultimate way to level up your engineering workflow is to inject some absolute chaos into your dependencies. Why spend hours writing robust logic when you can install a library that brings pure irony to your terminal? Let us dive into ten packages that might look completely useless on the surface but are actually the most important modules you will ever encounter in your developer journey. 1. emoji-poop This NPM package lets you use the poop emoji in your output. The emoji is well required in most of the websites as the real fun begins when the site crashes and you can use this poop emoji to showcase the errors with an emoji. This will help the clients get a bit calm after seeing the emoji and the errors. Think about it from a psychological perspective: traditional red stack traces cause immediate client panic, but a well-placed graphical poop emoji introduces a masterclass in modern error mitigation. javascript // npm i emoji-poop const emoji = require('emoji-poop'); console.log(emoji) // 💩 2. thanos-js Who doesn't love Marvel, and Thanos being the strongest villain in the MCU? This package lets you delete files in Thanos fashion. Once you install and run it, it deletes 50% of your files, reducing your stress and giving you less codebase to work with. Yes, it deletes the files for those who are confused about what this package does. It uses fs.unlinkSync to delete the files. Deleting random files from .git would be absolutely evil, and Thanos would love to do it. Exactly half of the files are deleted. Each file is given a chance at random
AI 资讯
Applying SAST to Any Application (Without Sonar, Snyk, Semgrep, or Veracode)
Most "how to add SAST to your pipeline" articles gravitate toward the same four names: SonarQube, Snyk, Semgrep, Veracode. They're solid tools, but they're not the only options, and sometimes you can't use them — budget constraints, air-gapped environments, licensing restrictions, or simply wanting something lightweight that lives entirely in your repo. The OWASP Source Code Analysis Tools page lists dozens of alternatives across every language. In this article I'll walk through applying Bandit , a free, open-source SAST tool for Python, to a real sample application — from finding vulnerabilities locally to wiring it into a CI/CD pipeline with GitHub Actions. The same workflow (install → configure → scan → fail the build on high-severity findings → track results over time) applies almost identically if you swap Bandit for other OWASP-listed tools like Brakeman (Ruby), FindSecBugs (Java), Gosec (Go), or Horusec (multi-language). Why Bandit? 100% open source (Apache 2.0), maintained under the PyCQA org. No account, no server, no license key — it runs as a CLI or a library. Understands Python's AST, so it catches real logic patterns, not just regex matches. Easy to tune with a config file and inline # nosec suppressions. ## 1. The sample application Let's use a small Flask app with a few intentionally introduced vulnerabilities — the kind of thing that slips into real codebases under deadline pressure. # app.py import subprocess import sqlite3 import pickle import yaml from flask import Flask , request app = Flask ( __name__ ) DB_PATH = " users.db " @app.route ( " /ping " ) def ping (): host = request . args . get ( " host " ) # Vulnerable: command injection via shell=True result = subprocess . run ( f " ping -c 1 { host } " , shell = True , capture_output = True ) return result . stdout @app.route ( " /user " ) def get_user (): user_id = request . args . get ( " id " ) conn = sqlite3 . connect ( DB_PATH ) cursor = conn . cursor () # Vulnerable: SQL injection via strin
开发者
Cockroaches will learn to fear my SwitchBot Bot Rechargeable
A little robotic switch-flipper has become my sidekick in combating cockroaches. Before I got the SwitchBot Bot Rechargeable, I'd tiptoe through the dark every morning, hoping I wouldn't step on one of those terrible bugs scurrying around as I made my way to the light switch across the room. Now I'm ready for battle before […]
开发者
Waymo will soon go fully autonomous in four more cities
Waymo will ditch human supervisors in San Diego, Las Vegas, Tampa and Denver.
AI 资讯
7 Dockerfile Mistakes That Are Quietly Costing You
Most Dockerfiles work. That's the problem — "it builds and runs" hides a lot of quiet costs in security, speed, and size that don't announce themselves until an audit, an incident, or a cloud bill does it for them. Here are seven mistakes I see constantly, and what to do instead. 1. Running as root By default, the process in your container runs as root — and if someone breaks out, they're root on a surface they shouldn't be. Add a non-root user and switch to it: RUN useradd --system --uid 10001 appuser USER appuser Cheap, and it closes off a whole category of "well, at least it wasn't root" incidents. 2. FROM some-image:latest latest is not a version — it's "whatever was newest when this happened to build." Two builds a week apart can produce different images with no diff to explain it, and a surprise base upgrade is a fun way to spend a Friday. Pin a specific tag, ideally by digest: FROM node:20.11.1-slim 3. Baking secrets into layers COPY .env . or ARG API_KEY followed by using it — and now the secret lives in an image layer forever , recoverable by anyone who pulls the image, even if a later layer deletes the file. Layers are immutable and additive; you can't delete your way out of a leak. Use build secrets ( --mount=type=secret ) or inject at runtime, never at build. 4. No .dockerignore Without one, COPY . . sweeps your .git directory, local env files, node_modules , and test data into the build context — bloating the image and, worse, potentially baking credentials and history into a layer. A five-line .dockerignore is one of the highest-leverage files in the repo. 5. Layer order that destroys your cache COPY . . RUN npm ci # ← reinstalls on EVERY code change Docker invalidates every layer after the first change. Copy the lockfile and install dependencies before copying the rest of your source, so a one-line code change doesn't trigger a full reinstall. This is a build-speed bug hiding as a style choice. 6. Leaving package manager cruft in the image RUN apt-get
AI 资讯
Requests hang forever: why missing timeouts cause recurring outages in .NET
This post was originally published on MatrixTrak.com — the production reliability toolkit for trading bot operators and .NET engineers. When requests hang forever and recycling releases stuck work: why missing timeouts create backlog, how to add budgets safely, and the rollout plan that prevents new incidents.. Most production incidents do not start as "down." They start as waiting. At 09:12 a dependency slows down. Your ASP.NET instances look healthy. CPU is fine. Memory is fine. But requests stop finishing. In-flight count climbs. Connection pools stop turning over. You scale out and it does not help because the new instances just join the waiting. The cost is not subtle. Backlog grows, SLAs fail, and on-call starts recycling processes because it is the only thing that releases the stuck work. Then the incident repeats next week because nothing changed about the waiting. This post gives you a production playbook for .NET: how to set time budgets, wire cancellation, and roll it out without triggering a new outage. Rescuing an ASP.NET service in production? Start at the .NET Production Rescue hub . If you only do three things Write down a total budget per request/job (then enforce it). Set per-attempt timeouts for each dependency and log elapsedMs , timeoutMs , and the decision (retry/stop/fallback). Propagate cancellation end-to-end so work stops (no zombie work after timeouts). Why requests hang forever: infinite waits capture capacity Missing timeouts are not a performance problem. They are a capacity problem. When a call can wait forever, it will eventually wait longer than your system can afford. While it waits, it holds something your service needs to operate: a worker slot, a thread, a connection, a lock, or a request budget. Once enough requests or jobs are holding those resources, the system stops behaving like a service and starts behaving like a queue you did not design. From the outside it looks like "everything is slow." Underneath, you are accumulating
AI 资讯
I Built a Platform Where Developers Can Document Their Products Before They Even Launch
I Built a Platform Where builders Can Document Their Products Before They Even Launch One thing I've learned after building side projects is that writing code isn't the hardest part. Getting people to notice what you've built is. Every time I finished a project, I'd launch it on a few platforms, share it on X, and hope someone would find it. Sometimes I'd get a few users, but after a day or two, the momentum was gone. It made me realize something. Most platforms are designed for the launch, not the journey. But as developers, the journey is where the interesting stuff happens. You fix bugs, redesign the UI three times, celebrate your first user, rewrite your backend, and slowly turn an idea into a real product. Those moments are worth sharing too. So I started building LaunchDock.space . The idea is simple. Instead of only launching finished products, developers can also create a page for projects that are still in development and post daily progress updates. Think of it as a place to build in public, document your progress, and grow an audience before your product is even ready. Along with development logs, LaunchDock lets makers: Launch finished products. Discover tools built by other builders. Follow the progress of other makers. Connect with a community that enjoys discovering new projects. I'm building LaunchDock with React, TypeScript, Node.js, Express, MongoDB, and Cloudflare R2, keeping the stack simple and focused on performance. The project is still evolving, and I'm shipping new features regularly. Building it has taught me a lot about product design, user feedback, and the importance of consistent shipping. I'd love to hear your thoughts. If you were using a platform like this, what feature would make you come back every day?
AI 资讯
These AI startups are growing revenue at faster and faster rates
There are a lot of fast-growing AI startups, but some are growing even faster, they say.