Solar_Axis1: SolarAxis: The Marketplace That Only Charges When the Expert Shows Up
A PERN stack solar platform uses manual Stripe capture, private Daily.co rooms, and service-layer orchestration to turn a consultation into a trust contract.
- SolarAxis turns trust into product logic by authorizing payment up front and capturing it only when the expert actually starts the consultation.
- The repo’s real strength is orchestration, not feature count, because Stripe, Daily.co, Prisma, and middleware each own a narrow part of the workflow.
- The backend is organized around a service layer that keeps controllers thin and makes the payment and video lifecycle easier to reason about.
- The data model is stricter than a generic lead form, which keeps the platform honest about what kind of solar request each user actually made.
The clever part is not solar. It is the billing rule.
Most marketplaces charge when the booking is made. SolarAxis does the opposite: it authorizes the card first, then waits for the expert to actually join before it captures the payment. That one choice changes the whole product from a scheduling app into a trust system.
That matters because the platform is selling a promise, not just a call. The customer does not have to wonder whether they paid for a no-show, and the expert does not have to fight for manual invoicing after the fact. The code makes the fairness rule explicit.
How the trust loop works end to end
requestConsultation() -> create PaymentIntent (capture_method: 'manual')
-> create consultation record (pending)
-> create private Daily room
admin joins room
-> startConsultation()
-> stripe.paymentIntents.capture(id)
-> consultation becomes active
no-show / timeout
-> cancelConsultation()
-> stripe.paymentIntents.cancel(id)
-> hold is released
The sequence is simple, but the timing is doing the heavy lifting. Stripe is not used as a checkout endpoint. It is used as a conditional guarantee that only resolves when the consultation becomes real.
The system is split by responsibility, not by framework fashion.
The backend looks mature because it refuses to let one layer do everything. Controllers handle HTTP concerns. Services own the Stripe and Daily orchestration. Prisma handles typed persistence. Middleware protects the sensitive paths.
That separation is not cosmetic. It keeps the cancellation path, the capture path, and the room creation path from collapsing into one large route handler. For a workflow with money and live presence in the loop, that discipline matters.
| Pattern | What happens | Why it matters |
|---|---|---|
| Fat controller | HTTP, payment, video, and database logic live in one route handler. | Hard to test, harder to recover when one step fails. |
| Service layer separation | Controller delegates to focused services for Stripe, Daily.co, and Prisma. | Each business step is isolated, readable, and easier to retry or cancel. |
| Middleware guards | Admin-only actions are blocked before the service layer runs. | Sensitive operations stay constrained to the right role. |
This is the kind of structure that makes a prototype feel like a system. It gives the repo a backbone, not just a working demo.
Daily rooms turn a consultation into a private event
The video layer is not just embedded. SolarAxis creates a private room per consultation and mints different tokens depending on whether the participant is an admin or a customer. That makes identity part of the call itself, not something bolted on around it.
The frontend then manages the room lifecycle, including cleanup when the session ends. That sounds small until you realize it prevents orphaned calls, stale rooms, and ambiguous session states. Video becomes a managed event with a beginning and an end.
The data model is stricter than a generic lead form.
A lot of service apps treat intake as one blob of form data. SolarAxis does not. It separates request types into dedicated models such as installation, maintenance, consultation, and upgradation, then connects them through a central Request record.
That design keeps the system typed around real business categories. It also avoids the usual mess where a single table slowly turns into an unstructured bucket of optional fields that nobody trusts six months later.
| Generic intake form | SolarAxis model |
|---|---|
| One flexible form with many optional fields | Dedicated models for each request type |
| Hard to validate by request kind | Validation can follow the service being requested |
| Loose downstream reporting | Cleaner analytics and clearer operational handling |
| Easy to start, hard to scale | Stricter up front, easier to evolve |
Why this stack feels mature even as an MVP
The version numbers are not the point, even if they signal modern tooling. Express 5, React 19, Tailwind 4, Prisma migrations, and asyncHandler together say something more useful: this repo is organized like an operational product, not a page bundle.
It has the signs of a builder who thinks in lifecycle, failure modes, and boundaries. The interesting part is not that the app can book a solar consultation. It is that the app knows what must happen before money changes hands.





