
Tecnologías Web Modernas para Empresas en California: Stack Tecnológico 2025
California lidera la innovación tecnológica mundial, y las empresas que operan aquí necesitan adoptar las tecnologías web más avanzadas para mantenerse competitivas. Con Silicon Valley marcando las tendencias globales, elegir el stack tecnológico correcto puede determinar el éxito o fracaso de tu proyecto digital.
El Ecosistema Tecnológico de California
Estadísticas del Mercado Tech
- $1.8 billones en valor de empresas tech en California
- 3.8 millones de trabajadores en tecnología
- 40% de startups globales tienen sede en California
- $180 mil salario promedio de desarrolladores senior
Tendencias Tecnológicas Dominantes
Frameworks en Crecimiento:
- React: 68% de adopción en startups californianas
- Next.js: 45% crecimiento año tras año
- Vue.js: Preferido por 32% de empresas medianas
- Svelte: Adoptado por 28% de nuevos proyectos
Frontend: Frameworks y Librerías
1. React - El Estándar de la Industria
¿Por qué React domina en California?
- Respaldado por Meta (Facebook)
- Ecosistema maduro y extenso
- Comunidad activa en Silicon Valley
- Facilidad para encontrar desarrolladores
Ejemplo de Componente React:
import React, { useState, useEffect } from "react";
import styled from "styled-components";
const BusinessCard = styled.div`
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
padding: 2rem;
transition: transform 0.3s ease;
&:hover {
transform: translateY(-5px);
}
`;
const CaliforniaBusinessComponent = () => {
const [businesses, setBusinesses] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchCaliforniaBusinesses();
}, []);
const fetchCaliforniaBusinesses = async () => {
try {
const response = await fetch("/api/businesses/california");
const data = await response.json();
setBusinesses(data);
} catch (error) {
console.error("Error fetching businesses:", error);
} finally {
setLoading(false);
}
};
if (loading) return <div>Cargando negocios en California...</div>;
return (
<div className="business-grid">
{businesses.map((business) => (
<BusinessCard key={business.id}>
<h3>{business.name}</h3>
<p>{business.location}</p>
<span>{business.category}</span>
</BusinessCard>
))}
</div>
);
};
export default CaliforniaBusinessComponent;
Ventajas para Empresas Californianas:
- Desarrollo rápido de MVPs
- Escalabilidad probada (Netflix, Airbnb, Uber)
- Integración fácil con APIs
- SEO mejorado con Next.js
2. Next.js - Full-Stack React Framework
Características Clave:
// pages/api/california-businesses.js
export default async function handler(req, res) {
if (req.method === 'GET') {
try {
const businesses = await getCaliforniaBusinesses();
res.status(200).json(businesses);
} catch (error) {
res.status(500).json({ error: 'Error fetching businesses' });
}
}
}
// pages/businesses/[city].js
import { useRouter } from 'next/router';
import { GetStaticProps, GetStaticPaths } from 'next';
export default function CityBusinesses({ businesses, city }) {
const router = useRouter();
return (
<div>
<h1>Negocios en {city}, California</h1>
{businesses.map(business => (
<BusinessCard key={business.id} business={business} />
))}
</div>
);
}
export const getStaticPaths = async () => {
const cities = ['san-diego', 'los-angeles', 'san-francisco'];
const paths = cities.map(city => ({ params: { city } }));
return { paths, fallback: false };
};
export const getStaticProps = async ({ params }) => {
const businesses = await getBusinessesByCity(params.city);
return {
props: { businesses, city: params.city },
revalidate: 3600 // Regenerar cada hora
};
};
3. Vue.js - Progresivo y Flexible
Composición API en Vue 3:
<template>
<div class="california-dashboard">
<h2>Dashboard de Negocios - California</h2>
<div class="filters">
<select v-model="selectedCity" @change="filterBusinesses">
<option value="">Todas las ciudades</option>
<option v-for="city in cities" :key="city" :value="city">
{{ city }}
</option>
</select>
</div>
<div class="business-grid">
<BusinessCard
v-for="business in filteredBusinesses"
:key="business.id"
:business="business"
@click="selectBusiness"
/>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from "vue";
import { useBusinessStore } from "@/stores/business";
const businessStore = useBusinessStore();
const selectedCity = ref("");
const cities = ref(["San Diego", "Los Angeles", "San Francisco"]);
const filteredBusinesses = computed(() => {
if (!selectedCity.value) return businessStore.businesses;
return businessStore.businesses.filter(
(business) => business.city === selectedCity.value
);
});
const filterBusinesses = () => {
businessStore.filterByCity(selectedCity.value);
};
const selectBusiness = (business) => {
businessStore.setSelectedBusiness(business);
};
onMounted(() => {
businessStore.fetchCaliforniaBusinesses();
});
</script>
4. Svelte/SvelteKit - Performance Extremo
Componente Svelte Optimizado:
<script>
import { onMount } from 'svelte';
import { fade, fly } from 'svelte/transition';
let businesses = [];
let loading = true;
let selectedCategory = '';
$: filteredBusinesses = selectedCategory
? businesses.filter(b => b.category === selectedCategory)
: businesses;
onMount(async () => {
const response = await fetch('/api/california-businesses');
businesses = await response.json();
loading = false;
});
function handleCategoryChange(event) {
selectedCategory = event.target.value;
}
</script>
<div class="california-business-finder">
<h1>Encuentra Negocios en California</h1>
{#if loading}
<div class="loading" transition:fade>
Cargando negocios...
</div>
{:else}
<select bind:value={selectedCategory} on:change={handleCategoryChange}>
<option value="">Todas las categorías</option>
<option value="tech">Tecnología</option>
<option value="retail">Retail</option>
<option value="food">Restaurantes</option>
</select>
<div class="business-grid">
{#each filteredBusinesses as business (business.id)}
<div
class="business-card"
transition:fly="{{ y: 20, duration: 300 }}"
>
<h3>{business.name}</h3>
<p>{business.description}</p>
<span class="location">{business.city}, CA</span>
</div>
{/each}
</div>
{/if}
</div>
<style>
.california-business-finder {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.business-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.business-card {
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
transition: transform 0.2s ease;
}
.business-card:hover {
transform: translateY(-2px);
}
</style>
Backend: Tecnologías del Servidor
1. Node.js - JavaScript Everywhere
API REST con Express:
const express = require("express");
const cors = require("cors");
const helmet = require("helmet");
const rateLimit = require("express-rate-limit");
const app = express();
// Middleware de seguridad
app.use(helmet());
app.use(
cors({
origin: process.env.FRONTEND_URL,
credentials: true,
})
);
// Rate limiting para APIs
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 100, // máximo 100 requests por IP
});
app.use("/api/", limiter);
// Middleware
app.use(express.json({ limit: "10mb" }));
app.use(express.urlencoded({ extended: true }));
// Rutas para negocios en California
app.get("/api/businesses/california", async (req, res) => {
try {
const { city, category, limit = 20 } = req.query;
const businesses = await Business.find({
state: "California",
...(city && { city }),
...(category && { category }),
})
.limit(parseInt(limit))
.sort({ createdAt: -1 });
res.json({
success: true,
data: businesses,
total: businesses.length,
});
} catch (error) {
res.status(500).json({
success: false,
error: "Error fetching California businesses",
});
}
});
// Crear nuevo negocio
app.post("/api/businesses", async (req, res) => {
try {
const businessData = req.body;
// Validación específica para California
if (businessData.state !== "California") {
return res.status(400).json({
success: false,
error: "Solo aceptamos negocios de California",
});
}
const business = new Business(businessData);
await business.save();
res.status(201).json({
success: true,
data: business,
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
});
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Servidor corriendo en puerto ${PORT}`);
});
2. Python con FastAPI
API Moderna con Python:
from fastapi import FastAPI, HTTPException, Depends, Query
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from typing import List, Optional
import asyncio
from datetime import datetime
app = FastAPI(
title="California Business API",
description="API para gestión de negocios en California",
version="1.0.0"
)
# CORS para frontend
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Modelos Pydantic
class BusinessBase(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
description: str = Field(..., max_length=500)
city: str = Field(..., regex="^(San Diego|Los Angeles|San Francisco|Sacramento)$")
category: str
website: Optional[str] = None
phone: Optional[str] = None
class BusinessCreate(BusinessBase):
pass
class Business(BusinessBase):
id: int
created_at: datetime
updated_at: datetime
class Config:
orm_mode = True
# Endpoints
@app.get("/api/businesses/california", response_model=List[Business])
async def get_california_businesses(
city: Optional[str] = Query(None, description="Filtrar por ciudad"),
category: Optional[str] = Query(None, description="Filtrar por categoría"),
limit: int = Query(20, ge=1, le=100, description="Límite de resultados")
):
"""
Obtener negocios en California con filtros opcionales
"""
try:
# Simulación de consulta a base de datos
businesses = await get_businesses_from_db(
city=city,
category=category,
limit=limit
)
return businesses
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/businesses", response_model=Business)
async def create_business(business: BusinessCreate):
"""
Crear un nuevo negocio en California
"""
try:
# Validación adicional
if business.city not in ["San Diego", "Los Angeles", "San Francisco", "Sacramento"]:
raise HTTPException(
status_code=400,
detail="Solo aceptamos negocios en ciudades principales de California"
)
new_business = await create_business_in_db(business)
return new_business
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@app.get("/api/businesses/{business_id}", response_model=Business)
async def get_business(business_id: int):
"""
Obtener un negocio específico por ID
"""
business = await get_business_by_id(business_id)
if not business:
raise HTTPException(status_code=404, detail="Negocio no encontrado")
return business
# Funciones auxiliares (simuladas)
async def get_businesses_from_db(city=None, category=None, limit=20):
# Simulación de consulta asíncrona a base de datos
await asyncio.sleep(0.1)
return []
async def create_business_in_db(business_data):
# Simulación de creación en base de datos
await asyncio.sleep(0.1)
return business_data
async def get_business_by_id(business_id):
# Simulación de consulta por ID
await asyncio.sleep(0.1)
return None
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
3. Go - Performance y Concurrencia
API en Go con Gin:
package main
import (
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
)
type Business struct {
ID int `json:"id"`
Name string `json:"name" binding:"required"`
Description string `json:"description"`
City string `json:"city" binding:"required"`
Category string `json:"category"`
Website string `json:"website"`
Phone string `json:"phone"`
CreatedAt time.Time `json:"created_at"`
}
type BusinessService struct {
businesses []Business
}
func NewBusinessService() *BusinessService {
return &BusinessService{
businesses: make([]Business, 0),
}
}
func (bs *BusinessService) GetCaliforniaBusinesses(city, category string, limit int) []Business {
var filtered []Business
for _, business := range bs.businesses {
if city != "" && business.City != city {
continue
}
if category != "" && business.Category != category {
continue
}
filtered = append(filtered, business)
if len(filtered) >= limit {
break
}
}
return filtered
}
func (bs *BusinessService) CreateBusiness(business Business) Business {
business.ID = len(bs.businesses) + 1
business.CreatedAt = time.Now()
bs.businesses = append(bs.businesses, business)
return business
}
func main() {
r := gin.Default()
// CORS middleware
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
businessService := NewBusinessService()
// Rutas API
api := r.Group("/api")
{
api.GET("/businesses/california", func(c *gin.Context) {
city := c.Query("city")
category := c.Query("category")
limitStr := c.DefaultQuery("limit", "20")
limit, err := strconv.Atoi(limitStr)
if err != nil {
limit = 20
}
businesses := businessService.GetCaliforniaBusinesses(city, category, limit)
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": businesses,
"total": len(businesses),
})
})
api.POST("/businesses", func(c *gin.Context) {
var business Business
if err := c.ShouldBindJSON(&business); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"error": err.Error(),
})
return
}
// Validación para California
validCities := map[string]bool{
"San Diego": true,
"Los Angeles": true,
"San Francisco": true,
"Sacramento": true,
}
if !validCities[business.City] {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"error": "Solo aceptamos negocios en ciudades principales de California",
})
return
}
newBusiness := businessService.CreateBusiness(business)
c.JSON(http.StatusCreated, gin.H{
"success": true,
"data": newBusiness,
})
})
}
r.Run(":8080")
}
Bases de Datos Modernas
1. PostgreSQL - Robustez Empresarial
Schema para Negocios Californianos:
-- Extensiones útiles
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "postgis";
-- Tabla de negocios
CREATE TABLE california_businesses (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(100) NOT NULL,
description TEXT,
city VARCHAR(50) NOT NULL,
state VARCHAR(2) DEFAULT 'CA',
zip_code VARCHAR(10),
category VARCHAR(50),
website VARCHAR(255),
phone VARCHAR(20),
email VARCHAR(100),
location POINT, -- Para coordenadas geográficas
rating DECIMAL(3,2) DEFAULT 0.00,
review_count INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Índices para optimización
CREATE INDEX idx_california_businesses_city ON california_businesses(city);
CREATE INDEX idx_california_businesses_category ON california_businesses(category);
CREATE INDEX idx_california_businesses_rating ON california_businesses(rating DESC);
CREATE INDEX idx_california_businesses_location ON california_businesses USING GIST(location);
-- Trigger para updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_california_businesses_updated_at
BEFORE UPDATE ON california_businesses
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Función para buscar negocios por proximidad
CREATE OR REPLACE FUNCTION find_nearby_businesses(
lat DECIMAL,
lng DECIMAL,
radius_km INTEGER DEFAULT 10,
business_category VARCHAR DEFAULT NULL
)
RETURNS TABLE (
id UUID,
name VARCHAR,
city VARCHAR,
category VARCHAR,
distance_km DECIMAL
) AS $$
BEGIN
RETURN QUERY
SELECT
b.id,
b.name,
b.city,
b.category,
ROUND(
(ST_Distance(
ST_GeogFromText('POINT(' || lng || ' ' || lat || ')'),
ST_GeogFromText('POINT(' || ST_X(b.location) || ' ' || ST_Y(b.location) || ')')
) / 1000)::DECIMAL, 2
) as distance_km
FROM california_businesses b
WHERE
b.is_active = true
AND (business_category IS NULL OR b.category = business_category)
AND ST_DWithin(
ST_GeogFromText('POINT(' || lng || ' ' || lat || ')'),
ST_GeogFromText('POINT(' || ST_X(b.location) || ' ' || ST_Y(b.location) || ')'),
radius_km * 1000
)
ORDER BY distance_km;
END;
$$ LANGUAGE plpgsql;
2. MongoDB - Flexibilidad NoSQL
Schema y Consultas MongoDB:
// Modelo de negocio con Mongoose
const mongoose = require("mongoose");
const businessSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
trim: true,
maxlength: 100,
},
description: {
type: String,
maxlength: 1000,
},
location: {
type: {
type: String,
enum: ["Point"],
default: "Point",
},
coordinates: {
type: [Number], // [longitude, latitude]
required: true,
},
address: {
street: String,
city: {
type: String,
required: true,
enum: ["San Diego", "Los Angeles", "San Francisco", "Sacramento"],
},
state: {
type: String,
default: "CA",
},
zipCode: String,
},
},
category: {
type: String,
required: true,
enum: [
"technology",
"retail",
"food",
"healthcare",
"professional-services",
],
},
contact: {
website: String,
phone: String,
email: String,
socialMedia: {
facebook: String,
instagram: String,
linkedin: String,
},
},
businessHours: [
{
day: {
type: String,
enum: [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday",
],
},
open: String,
close: String,
isClosed: {
type: Boolean,
default: false,
},
},
],
rating: {
average: {
type: Number,
default: 0,
min: 0,
max: 5,
},
count: {
type: Number,
default: 0,
},
},
features: [String], // ['parking', 'wifi', 'wheelchair-accessible']
isActive: {
type: Boolean,
default: true,
},
verificationStatus: {
type: String,
enum: ["pending", "verified", "rejected"],
default: "pending",
},
},
{
timestamps: true,
}
);
// Índice geoespacial para búsquedas por proximidad
businessSchema.index({ location: "2dsphere" });
businessSchema.index({ category: 1, "location.address.city": 1 });
businessSchema.index({ "rating.average": -1 });
// Método para encontrar negocios cercanos
businessSchema.statics.findNearby = function (
longitude,
latitude,
maxDistance = 10000
) {
return this.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [longitude, latitude],
},
$maxDistance: maxDistance, // metros
},
},
isActive: true,
});
};
// Método para buscar por ciudad y categoría
businessSchema.statics.findByCityAndCategory = function (
city,
category,
options = {}
) {
const query = {
"location.address.city": city,
isActive: true,
};
if (category) {
query.category = category;
}
return this.find(query)
.sort(options.sort || { "rating.average": -1 })
.limit(options.limit || 20)
.skip(options.skip || 0);
};
const Business = mongoose.model("Business", businessSchema);
// Ejemplos de uso
async function getCaliforniaBusinesses() {
// Buscar negocios en San Diego
const sanDiegoBusinesses = await Business.findByCityAndCategory("San Diego");
// Buscar restaurantes cerca de una ubicación
const nearbyRestaurants = await Business.findNearby(-117.1611, 32.7157, 5000)
.where("category")
.equals("food");
// Agregación para estadísticas por ciudad
const cityStats = await Business.aggregate([
{ $match: { isActive: true } },
{
$group: {
_id: "$location.address.city",
totalBusinesses: { $sum: 1 },
averageRating: { $avg: "$rating.average" },
categories: { $addToSet: "$category" },
},
},
{ $sort: { totalBusinesses: -1 } },
]);
return { sanDiegoBusinesses, nearbyRestaurants, cityStats };
}
DevOps y Deployment
1. Docker para Containerización
Dockerfile para aplicación Node.js:
# Multi-stage build para optimización
FROM node:18-alpine AS builder
WORKDIR /app
# Copiar package files
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# Copiar código fuente
COPY . .
# Build de la aplicación
RUN npm run build
# Imagen de producción
FROM node:18-alpine AS production
# Crear usuario no-root
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
WORKDIR /app
# Copiar archivos necesarios desde builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# Cambiar ownership
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV NODE_ENV production
CMD ["node", "server.js"]
Docker Compose para desarrollo:
version: "3.8"
services:
# Frontend Next.js
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- ./frontend:/app
- /app/node_modules
environment:
- NODE_ENV=development
- NEXT_PUBLIC_API_URL=http://localhost:8000
depends_on:
- backend
# Backend API
backend:
build:
context: ./backend
dockerfile: Dockerfile.dev
ports:
- "8000:8000"
volumes:
- ./backend:/app
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://user:password@postgres:5432/california_businesses
- REDIS_URL=redis://redis:6379
depends_on:
- postgres
- redis
# Base de datos PostgreSQL
postgres:
image: postgres:15-alpine
ports:
- "5432:5432"
environment:
- POSTGRES_DB=california_businesses
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
# Redis para caché
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
# Nginx como reverse proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- frontend
- backend
volumes:
postgres_data:
redis_data:
2. CI/CD con GitHub Actions
Workflow para deployment:
name: Deploy to California Servers
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: "18"
REGISTRY: ghcr.io
IMAGE_NAME: california-business-app
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run linting
run: npm run lint
- name: Run type checking
run: npm run type-check
- name: Run tests
run: npm run test:ci
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
- name: Run E2E tests
run: npm run test:e2e
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
build-and-push:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
- name: Log in to Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to California servers
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.CALIFORNIA_SERVER_HOST }}
username: ${{ secrets.CALIFORNIA_SERVER_USER }}
key: ${{ secrets.CALIFORNIA_SERVER_SSH_KEY }}
script: |
cd /opt/california-business-app
docker-compose pull
docker-compose up -d
docker system prune -f
- name: Health check
run: |
sleep 30
curl -f ${{ secrets.CALIFORNIA_APP_URL }}/health || exit 1
- name: Notify deployment
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: "#deployments"
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
if: always()
Casos de Éxito con Stack Moderno
Startup de Delivery - San Francisco
Stack Tecnológico:
- Frontend: Next.js + TypeScript + Tailwind CSS
- Backend: Node.js + Express + PostgreSQL
- Mobile: React Native
- Infrastructure: AWS + Docker + Kubernetes
Resultados:
- 0 a 100,000 usuarios en 6 meses
- 99.9% uptime
- < 200ms tiempo de respuesta API
- Escalamiento automático durante picos
E-commerce B2B - Los Angeles
Stack Tecnológico:
- Frontend: Vue.js + Nuxt.js + Vuetify
- Backend: Python + FastAPI + MongoDB
- Search: Elasticsearch
- Infrastructure: Google Cloud + Terraform
Resultados:
- $50M en transacciones anuales
- 500,000 productos en catálogo
- Búsqueda en < 50ms
- 40% reducción en costos de infraestructura
Plataforma SaaS - San Diego
Stack Tecnológico:
- Frontend: React + TypeScript + Material-UI
- Backend: Go + PostgreSQL + Redis
- Real-time: WebSockets + Socket.io
- Infrastructure: Digital Ocean + Docker Swarm
Resultados:
- 10,000+ empresas usuarias
- 99.95% disponibilidad
- Procesamiento de 1M+ eventos/día
- Escalamiento global a 15 países
Herramientas de Desarrollo
1. IDEs y Editores
Visual Studio Code - Configuración Optimizada:
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"typescript.preferences.importModuleSpecifier": "relative",
"emmet.includeLanguages": {
"javascript": "javascriptreact",
"typescript": "typescriptreact"
},
"extensions.recommendations": [
"bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-next",
"formulahendry.auto-rename-tag",
"christian-kohler.path-intellisense"
]
}
2. Herramientas de Testing
Jest + Testing Library:
// __tests__/CaliforniaBusinesses.test.jsx
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { rest } from "msw";
import { setupServer } from "msw/node";
import CaliforniaBusinesses from "../components/CaliforniaBusinesses";
// Mock del servidor API
const server = setupServer(
rest.get("/api/businesses/california", (req, res, ctx) => {
const city = req.url.searchParams.get("city");
const mockBusinesses = [
{
id: 1,
name: "Tech Startup SD",
city: "San Diego",
category: "technology",
},
{
id: 2,
name: "LA Restaurant",
city: "Los Angeles",
category: "food",
},
];
const filtered = city
? mockBusinesses.filter((b) => b.city === city)
: mockBusinesses;
return res(ctx.json(filtered));
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
describe("CaliforniaBusinesses Component", () => {
test("renders business list correctly", async () => {
render(<CaliforniaBusinesses />);
// Verificar que se muestran los negocios
await waitFor(() => {
expect(screen.getByText("Tech Startup SD")).toBeInTheDocument();
expect(screen.getByText("LA Restaurant")).toBeInTheDocument();
});
});
test("filters businesses by city", async () => {
const user = userEvent.setup();
render(<CaliforniaBusinesses />);
// Seleccionar filtro de ciudad
const citySelect = screen.getByLabelText(/ciudad/i);
await user.selectOptions(citySelect, "San Diego");
// Verificar filtrado
await waitFor(() => {
expect(screen.getByText("Tech Startup SD")).toBeInTheDocument();
expect(screen.queryByText("LA Restaurant")).not.toBeInTheDocument();
});
});
test("handles API errors gracefully", async () => {
// Simular error del servidor
server.use(
rest.get("/api/businesses/california", (req, res, ctx) => {
return res(ctx.status(500), ctx.json({ error: "Server error" }));
})
);
render(<CaliforniaBusinesses />);
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
});
});
Próximos Pasos
Las tecnologías web modernas evolucionan constantemente, especialmente en California donde la innovación nunca se detiene. Elegir el stack tecnológico correcto puede determinar el éxito de tu proyecto digital.
¿Necesitas ayuda para elegir las mejores tecnologías para tu proyecto? Solicita una consulta técnica gratuita y descubre cómo podemos ayudarte a construir soluciones web de clase mundial con las tecnologías más avanzadas.
¿Qué tecnologías web estás considerando para tu próximo proyecto? Comparte tu experiencia en los comentarios.